get rid of unused call
[Samba/gbeck.git] / source3 / smbd / chgpasswd.c
blob3ed94ef740ebb32d72ed0ec0b8b3fa3ef918395b
1 /*
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.
27 /*
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
47 password.
50 #include "includes.h"
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,
58 int new_passwd_size);
60 #if ALLOW_CHANGE_PASSWORD
62 static int findpty(char **slave)
64 int master;
65 static fstring line;
66 DIR *dirp;
67 const char *dpname;
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)
73 grantpt(master);
74 unlockpt(master);
75 *slave = (char *)ptsname(master);
76 if (*slave == NULL)
78 DEBUG(0,
79 ("findpty: Unable to create master/slave pty pair.\n"));
80 /* Stop fd leak on error. */
81 close(master);
82 return -1;
84 else
86 DEBUG(10,
87 ("findpty: Allocated slave pty %s\n", *slave));
88 return (master);
91 #endif /* HAVE_GRANTPT */
93 fstrcpy(line, "/dev/ptyXX");
95 dirp = opendir("/dev");
96 if (!dirp)
97 return (-1);
98 while ((dpname = readdirname(dirp)) != NULL)
100 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
102 DEBUG(3,
103 ("pty: try to open %s, line was %s\n", dpname,
104 line));
105 line[8] = dpname[3];
106 line[9] = dpname[4];
107 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
109 DEBUG(3, ("pty: opened %s\n", line));
110 line[5] = 't';
111 *slave = line;
112 closedir(dirp);
113 return (master);
117 closedir(dirp);
118 return (-1);
121 static int dochild(int master, const char *slavedev, const struct passwd *pass,
122 const char *passwordprogram, BOOL as_root)
124 int slave;
125 struct termios stermios;
126 gid_t gid;
127 uid_t uid;
129 if (pass == NULL)
131 DEBUG(0,
132 ("dochild: user doesn't exist in the UNIX password database.\n"));
133 return False;
136 gid = pass->pw_gid;
137 uid = pass->pw_uid;
139 gain_root_privilege();
141 /* Start new session - gets rid of controlling terminal. */
142 if (setsid() < 0)
144 DEBUG(3,
145 ("Weirdness, couldn't let go of controlling terminal\n"));
146 return (False);
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));
153 return (False);
155 #ifdef I_PUSH
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"));
162 /* return(False); */
164 #endif
166 /* Close master. */
167 close(master);
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"));
174 return (False);
176 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
178 DEBUG(3, ("Could not re-direct stdout\n"));
179 return (False);
181 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
183 DEBUG(3, ("Could not re-direct stderr\n"));
184 return (False);
186 if (slave > 2)
187 close(slave);
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)
194 DEBUG(3,
195 ("could not read default terminal attributes on pty\n"));
196 return (False);
198 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
199 stermios.c_lflag |= ICANON;
200 #ifdef ONLCR
201 stermios.c_oflag &= ~(ONLCR);
202 #endif
203 if (tcsetattr(0, TCSANOW, &stermios) < 0)
205 DEBUG(3, ("could not set attributes of pty\n"));
206 return (False);
209 /* make us completely into the right uid */
210 if (!as_root)
212 become_user_permanently(uid, gid);
215 DEBUG(10,
216 ("Invoking '%s' as password change program.\n",
217 passwordprogram));
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));
223 return (False);
225 return (True);
228 static int expect(int master, char *issue, char *expected)
230 pstring buffer;
231 int attempts, timeout, nread, len;
232 BOOL match = False;
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 ));
241 return False;
245 if (strequal(expected, "."))
246 return True;
248 timeout = 2000;
249 nread = 0;
250 buffer[nread] = 0;
252 while ((len = read_socket_with_timeout(master, buffer + nread, 1,
253 sizeof(buffer) - nread - 1,
254 timeout)) > 0) {
255 nread += len;
256 buffer[nread] = 0;
259 /* Eat leading/trailing whitespace before match. */
260 pstring str;
261 pstrcpy( str, buffer);
262 trim_string( str, " ", " ");
264 if ((match = (unix_wild_match(expected, str) == 0)))
265 timeout = 200;
269 if (lp_passwd_chat_debug())
270 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
271 expected, buffer, match ? "yes" : "no" ));
273 if (match)
274 break;
276 if (len < 0) {
277 DEBUG(2, ("expect: %s\n", strerror(errno)));
278 return False;
282 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
283 return match;
286 static void pwd_sub(char *buf)
288 all_string_sub(buf, "\\n", "\n", 0);
289 all_string_sub(buf, "\\r", "\r", 0);
290 all_string_sub(buf, "\\s", " ", 0);
291 all_string_sub(buf, "\\t", "\t", 0);
294 static int talktochild(int master, const char *seq)
296 int count = 0;
297 fstring issue, expected;
299 fstrcpy(issue, ".");
301 while (next_token(&seq, expected, NULL, sizeof(expected)))
303 pwd_sub(expected);
304 count++;
306 if (!expect(master, issue, expected))
308 DEBUG(3, ("Response %d incorrect\n", count));
309 return False;
312 if (!next_token(&seq, issue, NULL, sizeof(issue)))
313 fstrcpy(issue, ".");
315 pwd_sub(issue);
317 if (!strequal(issue, ".")) {
318 /* we have one final issue to send */
319 fstrcpy(expected, ".");
320 if (!expect(master, issue, expected))
321 return False;
324 return (count > 0);
327 static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
328 char *chatsequence, BOOL as_root)
330 char *slavedev;
331 int master;
332 pid_t pid, wpid;
333 int wstat;
334 BOOL chstat = False;
336 if (pass == NULL)
338 DEBUG(0,
339 ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
340 return False;
343 /* allocate a pseudo-terminal device */
344 if ((master = findpty(&slavedev)) < 0)
346 DEBUG(3,
347 ("Cannot Allocate pty for password change: %s\n",
348 pass->pw_name));
349 return (False);
353 * We need to temporarily stop CatchChild from eating
354 * SIGCLD signals as it also eats the exit status code. JRA.
357 CatchChildLeaveStatus();
359 if ((pid = sys_fork()) < 0)
361 DEBUG(3,
362 ("Cannot fork() child for password change: %s\n",
363 pass->pw_name));
364 close(master);
365 CatchChild();
366 return (False);
369 /* we now have a pty */
370 if (pid > 0)
371 { /* This is the parent process */
372 if ((chstat = talktochild(master, chatsequence)) == False)
374 DEBUG(3,
375 ("Child failed to change password: %s\n",
376 pass->pw_name));
377 kill(pid, SIGKILL); /* be sure to end this process */
380 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
382 if (errno == EINTR)
384 errno = 0;
385 continue;
387 break;
390 if (wpid < 0)
392 DEBUG(3, ("The process is no longer waiting!\n\n"));
393 close(master);
394 CatchChild();
395 return (False);
399 * Go back to ignoring children.
401 CatchChild();
403 close(master);
405 if (pid != wpid)
407 DEBUG(3,
408 ("We were waiting for the wrong process ID\n"));
409 return (False);
411 if (WIFEXITED(wstat) == 0)
413 DEBUG(3,
414 ("The process exited while we were waiting\n"));
415 return (False);
417 if (WEXITSTATUS(wstat) != 0)
419 DEBUG(3,
420 ("The status of the process exiting was %d\n",
421 wstat));
422 return (False);
426 else
428 /* CHILD */
431 * Lose any oplock capabilities.
433 oplock_set_capability(False, False);
435 /* make sure it doesn't freeze */
436 alarm(20);
438 if (as_root)
439 become_root();
441 DEBUG(3,
442 ("Dochild for user %s (uid=%d,gid=%d)\n", pass->pw_name,
443 (int)getuid(), (int)getgid()));
444 chstat =
445 dochild(master, slavedev, pass, passwordprogram,
446 as_root);
448 if (as_root)
449 unbecome_root();
452 * The child should never return from dochild() ....
455 DEBUG(0,
456 ("chat_with_program: Error: dochild() returned %d\n",
457 chstat));
458 exit(1);
461 if (chstat)
462 DEBUG(3,
463 ("Password change %ssuccessful for user %s\n",
464 (chstat ? "" : "un"), pass->pw_name));
465 return (chstat);
469 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
471 pstring passwordprogram;
472 pstring chatsequence;
473 size_t i;
474 size_t len;
476 struct passwd *pass;
478 if (!name) {
479 DEBUG(1, ("NULL username specfied to chgpasswd()!\n"));
482 pass = Get_Pwnam(name);
483 if (!pass) {
484 DEBUG(1, ("Username does not exist in system passwd!\n"));
485 return False;
488 if (!oldpass) {
489 oldpass = "";
492 DEBUG(3, ("Password change for user: %s\n", name));
494 #if DEBUG_PASSWORD
495 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
496 #endif
498 /* Take the passed information and test it for minimum criteria */
499 /* Minimum password length */
500 if (strlen(newpass) < lp_min_passwd_length()) {
501 /* too short, must be at least MINPASSWDLENGTH */
502 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
503 name, lp_min_passwd_length()));
504 return (False); /* inform the user */
507 /* Password is same as old password */
508 if (strcmp(oldpass, newpass) == 0) {
509 /* don't allow same password */
510 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
511 return (False); /* inform the user */
515 * Check the old and new passwords don't contain any control
516 * characters.
519 len = strlen(oldpass);
520 for (i = 0; i < len; i++) {
521 if (iscntrl((int)oldpass[i])) {
522 DEBUG(0,
523 ("chat_with_program: oldpass contains control characters (disallowed).\n"));
524 return False;
528 len = strlen(newpass);
529 for (i = 0; i < len; i++) {
530 if (iscntrl((int)newpass[i])) {
531 DEBUG(0,
532 ("chat_with_program: newpass contains control characters (disallowed).\n"));
533 return False;
537 #ifdef WITH_PAM
538 if (lp_pam_password_change()) {
539 BOOL ret;
541 if (as_root)
542 become_root();
544 if (pass) {
545 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
546 } else {
547 ret = smb_pam_passchange(name, oldpass, newpass);
550 if (as_root)
551 unbecome_root();
553 return ret;
555 #endif
557 /* A non-PAM password change just doen't make sense without a valid local user */
559 if (pass == NULL)
561 DEBUG(0,
562 ("chgpasswd: user %s doesn't exist in the UNIX password database.\n",
563 name));
564 return False;
567 pstrcpy(passwordprogram, lp_passwd_program());
568 pstrcpy(chatsequence, lp_passwd_chat());
570 if (!*chatsequence) {
571 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
572 return (False);
575 if (!*passwordprogram) {
576 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
577 return (False);
580 if (as_root) {
581 /* The password program *must* contain the user name to work. Fail if not. */
582 if (strstr(passwordprogram, "%u") == NULL) {
583 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
584 the string %%u, and the given string %s does not.\n", passwordprogram ));
585 return False;
589 pstring_sub(passwordprogram, "%u", name);
590 /* note that we do NOT substitute the %o and %n in the password program
591 as this would open up a security hole where the user could use
592 a new password containing shell escape characters */
594 pstring_sub(chatsequence, "%u", name);
595 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
596 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
597 return (chat_with_program
598 (passwordprogram, pass, chatsequence, as_root));
601 #else /* ALLOW_CHANGE_PASSWORD */
603 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
605 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
606 return (False);
608 #endif /* ALLOW_CHANGE_PASSWORD */
610 /***********************************************************
611 Code to check the lanman hashed password.
612 ************************************************************/
614 BOOL check_lanman_password(char *user, uchar * pass1,
615 uchar * pass2, SAM_ACCOUNT **hnd)
617 uchar unenc_new_pw[16];
618 uchar unenc_old_pw[16];
619 SAM_ACCOUNT *sampass = NULL;
620 uint16 acct_ctrl;
621 const uint8 *lanman_pw;
622 BOOL ret;
624 become_root();
625 ret = pdb_getsampwnam(sampass, user);
626 unbecome_root();
628 if (ret == False) {
629 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
630 pdb_free_sam(&sampass);
631 return False;
634 acct_ctrl = pdb_get_acct_ctrl (sampass);
635 lanman_pw = pdb_get_lanman_passwd (sampass);
637 if (acct_ctrl & ACB_DISABLED) {
638 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
639 pdb_free_sam(&sampass);
640 return False;
643 if (lanman_pw == NULL) {
644 if (acct_ctrl & ACB_PWNOTREQ) {
645 /* this saves the pointer for the caller */
646 *hnd = sampass;
647 return True;
648 } else {
649 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
650 pdb_free_sam(&sampass);
651 return False;
655 /* Get the new lanman hash. */
656 D_P16(lanman_pw, pass2, unenc_new_pw);
658 /* Use this to get the old lanman hash. */
659 D_P16(unenc_new_pw, pass1, unenc_old_pw);
661 /* Check that the two old passwords match. */
662 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
663 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
664 pdb_free_sam(&sampass);
665 return False;
668 /* this saves the pointer for the caller */
669 *hnd = sampass;
670 return True;
673 /***********************************************************
674 Code to change the lanman hashed password.
675 It nulls out the NT hashed password as it will
676 no longer be valid.
677 NOTE this function is designed to be called as root. Check the old password
678 is correct before calling. JRA.
679 ************************************************************/
681 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar *pass2)
683 static uchar null_pw[16];
684 uchar unenc_new_pw[16];
685 BOOL ret;
686 uint16 acct_ctrl;
687 const uint8 *pwd;
689 if (sampass == NULL) {
690 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
691 return False;
694 acct_ctrl = pdb_get_acct_ctrl(sampass);
695 pwd = pdb_get_lanman_passwd(sampass);
697 if (acct_ctrl & ACB_DISABLED) {
698 DEBUG(0,("change_lanman_password: account %s disabled.\n",
699 pdb_get_username(sampass)));
700 return False;
703 if (pwd == NULL) {
704 if (acct_ctrl & ACB_PWNOTREQ) {
705 uchar no_pw[14];
706 memset(no_pw, '\0', 14);
707 E_P16(no_pw, null_pw);
709 /* Get the new lanman hash. */
710 D_P16(null_pw, pass2, unenc_new_pw);
711 } else {
712 DEBUG(0,("change_lanman_password: no lanman password !\n"));
713 return False;
715 } else {
716 /* Get the new lanman hash. */
717 D_P16(pwd, pass2, unenc_new_pw);
720 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
721 return False;
724 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
725 return False; /* We lose the NT hash. Sorry. */
728 if (!pdb_set_pass_changed_now (sampass)) {
729 pdb_free_sam(&sampass);
730 /* Not quite sure what this one qualifies as, but this will do */
731 return False;
734 /* Now flush the sam_passwd struct to persistent storage */
735 ret = pdb_update_sam_account (sampass);
737 return ret;
740 /***********************************************************
741 Code to check and change the OEM hashed password.
742 ************************************************************/
744 NTSTATUS pass_oem_change(char *user,
745 uchar * lmdata, uchar * lmhash,
746 uchar * ntdata, uchar * nthash)
748 fstring new_passwd;
749 SAM_ACCOUNT *sampass = NULL;
750 NTSTATUS nt_status = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
751 &sampass, new_passwd, sizeof(new_passwd));
753 if (!NT_STATUS_IS_OK(nt_status))
754 return nt_status;
756 /* We've already checked the old password here.... */
757 become_root();
758 nt_status = change_oem_password(sampass, NULL, new_passwd);
759 unbecome_root();
761 memset(new_passwd, 0, sizeof(new_passwd));
763 pdb_free_sam(&sampass);
765 return nt_status;
768 /***********************************************************
769 Code to check the OEM hashed password.
771 this function ignores the 516 byte nt OEM hashed password
772 but does use the lm OEM password to check the nt hashed-hash.
774 ************************************************************/
776 static NTSTATUS check_oem_password(const char *user,
777 uchar * lmdata, const uchar * lmhash,
778 const uchar * ntdata, const uchar * nthash,
779 SAM_ACCOUNT **hnd, char *new_passwd,
780 int new_passwd_size)
782 static uchar null_pw[16];
783 static uchar null_ntpw[16];
784 SAM_ACCOUNT *sampass = NULL;
785 const uint8 *lanman_pw, *nt_pw;
786 uint16 acct_ctrl;
787 int new_pw_len;
788 uchar new_ntp16[16];
789 uchar unenc_old_ntpw[16];
790 uchar new_p16[16];
791 uchar unenc_old_pw[16];
792 char no_pw[2];
793 BOOL ret;
795 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
797 *hnd = NULL;
799 pdb_init_sam(&sampass);
801 become_root();
802 ret = pdb_getsampwnam(sampass, user);
803 unbecome_root();
805 if (ret == False) {
806 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
807 pdb_free_sam(&sampass);
808 return NT_STATUS_WRONG_PASSWORD;
810 TODO: check what Win2k returns for this:
811 return NT_STATUS_NO_SUCH_USER;
815 acct_ctrl = pdb_get_acct_ctrl(sampass);
817 if (acct_ctrl & ACB_DISABLED) {
818 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
819 pdb_free_sam(&sampass);
820 return NT_STATUS_ACCOUNT_DISABLED;
823 /* construct a null password (in case one is needed */
824 no_pw[0] = 0;
825 no_pw[1] = 0;
826 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
828 /* save pointers to passwords so we don't have to keep looking them up */
829 lanman_pw = pdb_get_lanman_passwd(sampass);
830 nt_pw = pdb_get_nt_passwd(sampass);
832 /* check for null passwords */
833 if (lanman_pw == NULL) {
834 if (!(acct_ctrl & ACB_PWNOTREQ)) {
835 DEBUG(0,("check_oem_password: no lanman password !\n"));
836 pdb_free_sam(&sampass);
837 return NT_STATUS_WRONG_PASSWORD;
841 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
842 if (!(acct_ctrl & ACB_PWNOTREQ)) {
843 DEBUG(0,("check_oem_password: no ntlm password !\n"));
844 pdb_free_sam(&sampass);
845 return NT_STATUS_WRONG_PASSWORD;
850 * Call the hash function to get the new password.
852 SamOEMhash( lmdata, lanman_pw, 516);
855 * The length of the new password is in the last 4 bytes of
856 * the data buffer.
859 new_pw_len = IVAL(lmdata, 512);
861 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
862 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
863 pdb_free_sam(&sampass);
864 return NT_STATUS_WRONG_PASSWORD;
867 if (nt_pass_set) {
869 * nt passwords are in unicode
871 pull_ucs2(NULL, new_passwd,
872 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
873 new_passwd_size, new_pw_len, 0);
874 } else {
875 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
876 new_passwd[new_pw_len] = 0;
880 * To ensure we got the correct new password, hash it and
881 * use it as a key to test the passed old password.
884 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
886 if (!nt_pass_set) {
888 * Now use new_p16 as the key to see if the old
889 * password matches.
891 D_P16(new_p16, lmhash, unenc_old_pw);
893 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
894 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
895 pdb_free_sam(&sampass);
896 return NT_STATUS_WRONG_PASSWORD;
899 #ifdef DEBUG_PASSWORD
900 DEBUG(100,
901 ("check_oem_password: password %s ok\n", new_passwd));
902 #endif
903 *hnd = sampass;
904 return NT_STATUS_OK;
908 * Now use new_p16 as the key to see if the old
909 * password matches.
911 D_P16(new_ntp16, lmhash, unenc_old_pw);
912 D_P16(new_ntp16, nthash, unenc_old_ntpw);
914 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
915 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
916 pdb_free_sam(&sampass);
917 return NT_STATUS_WRONG_PASSWORD;
920 if (memcmp(nt_pw, unenc_old_ntpw, 16)) {
921 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
922 pdb_free_sam(&sampass);
923 return NT_STATUS_WRONG_PASSWORD;
925 #ifdef DEBUG_PASSWORD
926 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
927 #endif
929 *hnd = sampass;
930 return NT_STATUS_OK;
933 /***********************************************************
934 Code to change the oem password. Changes both the lanman
935 and NT hashes. Old_passwd is almost always NULL.
936 NOTE this function is designed to be called as root. Check the old password
937 is correct before calling. JRA.
938 ************************************************************/
940 NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd)
942 BOOL ret;
943 uint32 min_len;
945 if (time(NULL) < pdb_get_pass_can_change_time(hnd)) {
946 DEBUG(1, ("user %s cannot change password now, must wait until %s\n",
947 pdb_get_username(hnd), http_timestring(pdb_get_pass_can_change_time(hnd))));
948 return NT_STATUS_PASSWORD_RESTRICTION;
951 if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (strlen(new_passwd) < min_len)) {
952 DEBUG(1, ("user %s cannot change password - password too short\n",
953 pdb_get_username(hnd)));
954 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
955 return NT_STATUS_PASSWORD_RESTRICTION;
956 /* return NT_STATUS_PWD_TOO_SHORT; */
959 /* Take the passed information and test it for minimum criteria */
960 /* Minimum password length */
961 if (strlen(new_passwd) < lp_min_passwd_length()) {
962 /* too short, must be at least MINPASSWDLENGTH */
963 DEBUG(1, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
964 pdb_get_username(hnd), lp_min_passwd_length()));
965 return NT_STATUS_PASSWORD_RESTRICTION;
966 /* return NT_STATUS_PWD_TOO_SHORT; */
969 /* TODO: Add cracklib support here */
972 * If unix password sync was requested, attempt to change
973 * the /etc/passwd database first. Return failure if this cannot
974 * be done.
976 * This occurs before the oem change, because we don't want to
977 * update it if chgpasswd failed.
979 * Conditional on lp_unix_password_sync() because we don't want
980 * to touch the unix db unless we have admin permission.
983 if(lp_unix_password_sync() &&
984 !chgpasswd(pdb_get_username(hnd), old_passwd, new_passwd, False)) {
985 return NT_STATUS_ACCESS_DENIED;
988 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
989 return NT_STATUS_ACCESS_DENIED;
992 /* Now write it into the file. */
993 ret = pdb_update_sam_account (hnd);
995 if (!ret) {
996 return NT_STATUS_ACCESS_DENIED;
999 return NT_STATUS_OK;