fix for bad check spotted by Ray Simard <ray@sylvan-glade.com>
[Samba.git] / source3 / smbd / chgpasswd.c
blobc2a82d1eb6cf8cb5966c57a218cfbcba6f2ecec5
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* fork a child process to exec passwd and write to its
22 * tty to change a users password. This is running as the
23 * user who is attempting to change the password.
26 /*
27 * This code was copied/borrowed and stolen from various sources.
28 * The primary source was the poppasswd.c from the authors of POPMail. This software
29 * was included as a client to change passwords using the 'passwd' program
30 * on the remote machine.
32 * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE
33 * is defined in the compiler directives located in the Makefile.
35 * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
36 * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
37 * and rights to modify, distribute or incorporate this change to the CAP suite or
38 * using it for any other reason are granted, so long as this disclaimer is left intact.
42 This code was hacked considerably for inclusion in Samba, primarily
43 by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
44 of the "password chat" option, which allows the easy runtime
45 specification of the expected sequence of events to change a
46 password.
49 #include "includes.h"
51 extern struct passdb_ops pdb_ops;
53 static BOOL check_oem_password(const char *user,
54 uchar * lmdata, const uchar * lmhash,
55 const uchar * ntdata, const uchar * nthash,
56 SAM_ACCOUNT **hnd, char *new_passwd,
57 int new_passwd_size);
59 #if ALLOW_CHANGE_PASSWORD
61 static int findpty(char **slave)
63 int master;
64 static fstring line;
65 DIR *dirp;
66 char *dpname;
68 #if defined(HAVE_GRANTPT)
69 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
70 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
72 grantpt(master);
73 unlockpt(master);
74 *slave = (char *)ptsname(master);
75 if (*slave == NULL)
77 DEBUG(0,
78 ("findpty: Unable to create master/slave pty pair.\n"));
79 /* Stop fd leak on error. */
80 close(master);
81 return -1;
83 else
85 DEBUG(10,
86 ("findpty: Allocated slave pty %s\n", *slave));
87 return (master);
90 #endif /* HAVE_GRANTPT */
92 fstrcpy(line, "/dev/ptyXX");
94 dirp = opendir("/dev");
95 if (!dirp)
96 return (-1);
97 while ((dpname = readdirname(dirp)) != NULL)
99 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
101 DEBUG(3,
102 ("pty: try to open %s, line was %s\n", dpname,
103 line));
104 line[8] = dpname[3];
105 line[9] = dpname[4];
106 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
108 DEBUG(3, ("pty: opened %s\n", line));
109 line[5] = 't';
110 *slave = line;
111 closedir(dirp);
112 return (master);
116 closedir(dirp);
117 return (-1);
120 static int dochild(int master, const char *slavedev, const struct passwd *pass,
121 const char *passwordprogram, BOOL as_root)
123 int slave;
124 struct termios stermios;
125 gid_t gid;
126 uid_t uid;
128 if (pass == NULL)
130 DEBUG(0,
131 ("dochild: user doesn't exist in the UNIX password database.\n"));
132 return False;
135 gid = pass->pw_gid;
136 uid = pass->pw_uid;
138 gain_root_privilege();
140 /* Start new session - gets rid of controlling terminal. */
141 if (setsid() < 0)
143 DEBUG(3,
144 ("Weirdness, couldn't let go of controlling terminal\n"));
145 return (False);
148 /* Open slave pty and acquire as new controlling terminal. */
149 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
151 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
152 return (False);
154 #ifdef I_PUSH
155 ioctl(slave, I_PUSH, "ptem");
156 ioctl(slave, I_PUSH, "ldterm");
157 #elif defined(TIOCSCTTY)
158 if (ioctl(slave, TIOCSCTTY, 0) < 0)
160 DEBUG(3, ("Error in ioctl call for slave pty\n"));
161 /* return(False); */
163 #endif
165 /* Close master. */
166 close(master);
168 /* Make slave stdin/out/err of child. */
170 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
172 DEBUG(3, ("Could not re-direct stdin\n"));
173 return (False);
175 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
177 DEBUG(3, ("Could not re-direct stdout\n"));
178 return (False);
180 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
182 DEBUG(3, ("Could not re-direct stderr\n"));
183 return (False);
185 if (slave > 2)
186 close(slave);
188 /* Set proper terminal attributes - no echo, canonical input processing,
189 no map NL to CR/NL on output. */
191 if (tcgetattr(0, &stermios) < 0)
193 DEBUG(3,
194 ("could not read default terminal attributes on pty\n"));
195 return (False);
197 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
198 stermios.c_lflag |= ICANON;
199 #ifdef ONLCR
200 stermios.c_oflag &= ~(ONLCR);
201 #endif
202 if (tcsetattr(0, TCSANOW, &stermios) < 0)
204 DEBUG(3, ("could not set attributes of pty\n"));
205 return (False);
208 /* make us completely into the right uid */
209 if (!as_root)
211 become_user_permanently(uid, gid);
214 DEBUG(10,
215 ("Invoking '%s' as password change program.\n",
216 passwordprogram));
218 /* execl() password-change application */
219 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
221 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
222 return (False);
224 return (True);
227 static int expect(int master, char *issue, char *expected)
229 pstring buffer;
230 int attempts, timeout, nread, len;
231 BOOL match = False;
233 for (attempts = 0; attempts < 2; attempts++) {
234 if (!strequal(issue, ".")) {
235 if (lp_passwd_chat_debug())
236 DEBUG(100, ("expect: sending [%s]\n", issue));
238 if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
239 DEBUG(2,("expect: (short) write returned %d\n", len ));
240 return False;
244 if (strequal(expected, "."))
245 return True;
247 timeout = 2000;
248 nread = 0;
249 buffer[nread] = 0;
251 while ((len = read_with_timeout(master, buffer + nread, 1,
252 sizeof(buffer) - nread - 1,
253 timeout)) > 0) {
254 nread += len;
255 buffer[nread] = 0;
258 /* Eat leading/trailing whitespace before match. */
259 pstring str;
260 pstrcpy( str, buffer);
261 trim_string( str, " ", " ");
263 if ((match = (unix_wild_match(expected, str) == 0)))
264 timeout = 200;
268 if (lp_passwd_chat_debug())
269 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
270 expected, buffer, match ? "yes" : "no" ));
272 if (match)
273 break;
275 if (len < 0) {
276 DEBUG(2, ("expect: %s\n", strerror(errno)));
277 return False;
281 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
282 return match;
285 static void pwd_sub(char *buf)
287 all_string_sub(buf, "\\n", "\n", 0);
288 all_string_sub(buf, "\\r", "\r", 0);
289 all_string_sub(buf, "\\s", " ", 0);
290 all_string_sub(buf, "\\t", "\t", 0);
293 static int talktochild(int master, const char *seq)
295 int count = 0;
296 fstring issue, expected;
298 fstrcpy(issue, ".");
300 while (next_token(&seq, expected, NULL, sizeof(expected)))
302 pwd_sub(expected);
303 count++;
305 if (!expect(master, issue, expected))
307 DEBUG(3, ("Response %d incorrect\n", count));
308 return False;
311 if (!next_token(&seq, issue, NULL, sizeof(issue)))
312 fstrcpy(issue, ".");
314 pwd_sub(issue);
316 if (!strequal(issue, ".")) {
317 /* we have one final issue to send */
318 fstrcpy(expected, ".");
319 if (!expect(master, issue, expected))
320 return False;
323 return (count > 0);
326 static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
327 char *chatsequence, BOOL as_root)
329 char *slavedev;
330 int master;
331 pid_t pid, wpid;
332 int wstat;
333 BOOL chstat = False;
335 if (pass == NULL)
337 DEBUG(0,
338 ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
339 return False;
342 /* allocate a pseudo-terminal device */
343 if ((master = findpty(&slavedev)) < 0)
345 DEBUG(3,
346 ("Cannot Allocate pty for password change: %s\n",
347 pass->pw_name));
348 return (False);
352 * We need to temporarily stop CatchChild from eating
353 * SIGCLD signals as it also eats the exit status code. JRA.
356 CatchChildLeaveStatus();
358 if ((pid = sys_fork()) < 0)
360 DEBUG(3,
361 ("Cannot fork() child for password change: %s\n",
362 pass->pw_name));
363 close(master);
364 CatchChild();
365 return (False);
368 /* we now have a pty */
369 if (pid > 0)
370 { /* This is the parent process */
371 if ((chstat = talktochild(master, chatsequence)) == False)
373 DEBUG(3,
374 ("Child failed to change password: %s\n",
375 pass->pw_name));
376 kill(pid, SIGKILL); /* be sure to end this process */
379 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
381 if (errno == EINTR)
383 errno = 0;
384 continue;
386 break;
389 if (wpid < 0)
391 DEBUG(3, ("The process is no longer waiting!\n\n"));
392 close(master);
393 CatchChild();
394 return (False);
398 * Go back to ignoring children.
400 CatchChild();
402 close(master);
404 if (pid != wpid)
406 DEBUG(3,
407 ("We were waiting for the wrong process ID\n"));
408 return (False);
410 if (WIFEXITED(wstat) == 0)
412 DEBUG(3,
413 ("The process exited while we were waiting\n"));
414 return (False);
416 if (WEXITSTATUS(wstat) != 0)
418 DEBUG(3,
419 ("The status of the process exiting was %d\n",
420 wstat));
421 return (False);
425 else
427 /* CHILD */
430 * Lose any oplock capabilities.
432 oplock_set_capability(False, False);
434 /* make sure it doesn't freeze */
435 alarm(20);
437 if (as_root)
438 become_root();
440 DEBUG(3,
441 ("Dochild for user %s (uid=%d,gid=%d)\n", pass->pw_name,
442 (int)getuid(), (int)getgid()));
443 chstat =
444 dochild(master, slavedev, pass, passwordprogram,
445 as_root);
447 if (as_root)
448 unbecome_root();
451 * The child should never return from dochild() ....
454 DEBUG(0,
455 ("chat_with_program: Error: dochild() returned %d\n",
456 chstat));
457 exit(1);
460 if (chstat)
461 DEBUG(3,
462 ("Password change %ssuccessful for user %s\n",
463 (chstat ? "" : "un"), pass->pw_name));
464 return (chstat);
468 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
470 pstring passwordprogram;
471 pstring chatsequence;
472 size_t i;
473 size_t len;
475 struct passwd *pass;
477 if (!name) {
478 DEBUG(1, ("NULL username specfied to chgpasswd()!\n"));
481 DEBUG(3, ("Password change for user: %s\n", name));
483 #if DEBUG_PASSWORD
484 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
485 #endif
487 /* Take the passed information and test it for minimum criteria */
488 /* Minimum password length */
489 if (strlen(newpass) < lp_min_passwd_length()) {
490 /* too short, must be at least MINPASSWDLENGTH */
491 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
492 name, lp_min_passwd_length()));
493 return (False); /* inform the user */
496 /* Password is same as old password */
497 if (strcmp(oldpass, newpass) == 0) {
498 /* don't allow same password */
499 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
500 return (False); /* inform the user */
504 * Check the old and new passwords don't contain any control
505 * characters.
508 len = strlen(oldpass);
509 for (i = 0; i < len; i++) {
510 if (iscntrl((int)oldpass[i])) {
511 DEBUG(0,
512 ("chat_with_program: oldpass contains control characters (disallowed).\n"));
513 return False;
517 len = strlen(newpass);
518 for (i = 0; i < len; i++) {
519 if (iscntrl((int)newpass[i])) {
520 DEBUG(0,
521 ("chat_with_program: newpass contains control characters (disallowed).\n"));
522 return False;
526 pass = Get_Pwnam(name);
528 #ifdef WITH_PAM
529 if (lp_pam_password_change()) {
530 BOOL ret;
532 if (as_root)
533 become_root();
535 if (pass) {
536 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
537 } else {
538 ret = smb_pam_passchange(name, oldpass, newpass);
541 if (as_root)
542 unbecome_root();
544 return ret;
546 #endif
548 /* A non-PAM password change just doen't make sense without a valid local user */
550 if (pass == NULL)
552 DEBUG(0,
553 ("chgpasswd: user %s doesn't exist in the UNIX password database.\n",
554 name));
555 return False;
558 pstrcpy(passwordprogram, lp_passwd_program());
559 pstrcpy(chatsequence, lp_passwd_chat());
561 if (!*chatsequence) {
562 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
563 return (False);
566 if (!*passwordprogram) {
567 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
568 return (False);
571 if (as_root) {
572 /* The password program *must* contain the user name to work. Fail if not. */
573 if (strstr(passwordprogram, "%u") == NULL) {
574 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
575 the string %%u, and the given string %s does not.\n", passwordprogram ));
576 return False;
580 pstring_sub(passwordprogram, "%u", name);
581 /* note that we do NOT substitute the %o and %n in the password program
582 as this would open up a security hole where the user could use
583 a new password containing shell escape characters */
585 pstring_sub(chatsequence, "%u", name);
586 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
587 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
588 return (chat_with_program
589 (passwordprogram, pass, chatsequence, as_root));
592 #else /* ALLOW_CHANGE_PASSWORD */
594 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
596 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
597 return (False);
599 #endif /* ALLOW_CHANGE_PASSWORD */
601 /***********************************************************
602 Code to check the lanman hashed password.
603 ************************************************************/
605 BOOL check_lanman_password(char *user, uchar * pass1,
606 uchar * pass2, SAM_ACCOUNT **hnd)
608 uchar unenc_new_pw[16];
609 uchar unenc_old_pw[16];
610 SAM_ACCOUNT *sampass = NULL;
611 uint16 acct_ctrl;
612 const uint8 *lanman_pw;
613 BOOL ret;
615 become_root();
616 ret = pdb_getsampwnam(sampass, user);
617 unbecome_root();
619 if (ret == False) {
620 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
621 pdb_free_sam(&sampass);
622 return False;
625 acct_ctrl = pdb_get_acct_ctrl (sampass);
626 lanman_pw = pdb_get_lanman_passwd (sampass);
628 if (acct_ctrl & ACB_DISABLED) {
629 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
630 pdb_free_sam(&sampass);
631 return False;
634 if (lanman_pw == NULL) {
635 if (acct_ctrl & ACB_PWNOTREQ) {
636 /* this saves the pointer for the caller */
637 *hnd = sampass;
638 return True;
639 } else {
640 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
641 pdb_free_sam(&sampass);
642 return False;
646 /* Get the new lanman hash. */
647 D_P16(lanman_pw, pass2, unenc_new_pw);
649 /* Use this to get the old lanman hash. */
650 D_P16(unenc_new_pw, pass1, unenc_old_pw);
652 /* Check that the two old passwords match. */
653 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
654 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
655 pdb_free_sam(&sampass);
656 return False;
659 /* this saves the pointer for the caller */
660 *hnd = sampass;
661 return True;
664 /***********************************************************
665 Code to change the lanman hashed password.
666 It nulls out the NT hashed password as it will
667 no longer be valid.
668 ************************************************************/
670 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
671 uchar * pass2)
673 static uchar null_pw[16];
674 uchar unenc_new_pw[16];
675 BOOL ret;
676 uint16 acct_ctrl;
677 const uint8 *pwd;
679 if (sampass == NULL) {
680 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
681 return False;
684 acct_ctrl = pdb_get_acct_ctrl(sampass);
685 pwd = pdb_get_lanman_passwd(sampass);
687 if (acct_ctrl & ACB_DISABLED) {
688 DEBUG(0,("change_lanman_password: account %s disabled.\n",
689 pdb_get_username(sampass)));
690 return False;
693 if (pwd == NULL) {
694 if (acct_ctrl & ACB_PWNOTREQ) {
695 uchar no_pw[14];
696 memset(no_pw, '\0', 14);
697 E_P16(no_pw, null_pw);
699 /* Get the new lanman hash. */
700 D_P16(null_pw, pass2, unenc_new_pw);
701 } else {
702 DEBUG(0,("change_lanman_password: no lanman password !\n"));
703 return False;
705 } else {
706 /* Get the new lanman hash. */
707 D_P16(pwd, pass2, unenc_new_pw);
710 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
711 return False;
714 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
715 return False; /* We lose the NT hash. Sorry. */
718 if (!pdb_set_pass_changed_now (sampass)) {
719 pdb_free_sam(&sampass);
720 /* Not quite sure what this one qualifies as, but this will do */
721 return False;
724 /* Now flush the sam_passwd struct to persistent storage */
725 become_root();
726 ret = pdb_update_sam_account (sampass);
727 unbecome_root();
729 return ret;
732 /***********************************************************
733 Code to check and change the OEM hashed password.
734 ************************************************************/
735 BOOL pass_oem_change(char *user,
736 uchar * lmdata, uchar * lmhash,
737 uchar * ntdata, uchar * nthash)
739 fstring new_passwd;
740 const char *unix_user;
741 SAM_ACCOUNT *sampass = NULL;
742 BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
743 &sampass, new_passwd, sizeof(new_passwd));
746 * At this point we have the new case-sensitive plaintext
747 * password in the fstring new_passwd. If we wanted to synchronise
748 * with UNIX passwords we would call a UNIX password changing
749 * function here. However it would have to be done as root
750 * as the plaintext of the old users password is not
751 * available. JRA.
754 unix_user = pdb_get_username(sampass);
756 if ((ret) && (unix_user) && (*unix_user) && lp_unix_password_sync())
757 ret = chgpasswd(unix_user, "", new_passwd, True);
759 if (ret)
760 ret = change_oem_password(sampass, new_passwd);
762 memset(new_passwd, 0, sizeof(new_passwd));
764 pdb_free_sam(&sampass);
766 return ret;
769 /***********************************************************
770 Code to check the OEM hashed password.
772 this function ignores the 516 byte nt OEM hashed password
773 but does use the lm OEM password to check the nt hashed-hash.
775 ************************************************************/
776 static BOOL 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 pdb_init_sam(&sampass);
799 become_root();
800 ret = pdb_getsampwnam(sampass, user);
801 unbecome_root();
803 if (ret == False) {
804 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
805 return False;
808 *hnd = sampass;
810 acct_ctrl = pdb_get_acct_ctrl(sampass);
812 if (acct_ctrl & ACB_DISABLED) {
813 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
814 return False;
817 /* construct a null password (in case one is needed */
818 no_pw[0] = 0;
819 no_pw[1] = 0;
820 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
822 /* save pointers to passwords so we don't have to keep looking them up */
823 lanman_pw = pdb_get_lanman_passwd(sampass);
824 nt_pw = pdb_get_nt_passwd (sampass);
826 /* check for null passwords */
827 if (lanman_pw == NULL) {
828 if (!(acct_ctrl & ACB_PWNOTREQ)) {
829 DEBUG(0,("check_oem_password: no lanman password !\n"));
830 return False;
834 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
835 if (!(acct_ctrl & ACB_PWNOTREQ)) {
836 DEBUG(0,("check_oem_password: no ntlm password !\n"));
837 return False;
842 * Call the hash function to get the new password.
844 SamOEMhash( lmdata, lanman_pw, 516);
847 * The length of the new password is in the last 4 bytes of
848 * the data buffer.
851 new_pw_len = IVAL(lmdata, 512);
852 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
853 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
854 return False;
857 if (nt_pass_set) {
859 * nt passwords are in unicode
861 pull_ucs2(NULL, new_passwd,
862 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
863 new_passwd_size, new_pw_len, 0);
864 } else {
865 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
866 new_passwd[new_pw_len] = 0;
870 * To ensure we got the correct new password, hash it and
871 * use it as a key to test the passed old password.
874 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
876 if (!nt_pass_set)
879 * Now use new_p16 as the key to see if the old
880 * password matches.
882 D_P16(new_p16, lmhash, unenc_old_pw);
884 if (memcmp(lanman_pw, unenc_old_pw, 16))
886 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
887 return False;
890 #ifdef DEBUG_PASSWORD
891 DEBUG(100,
892 ("check_oem_password: password %s ok\n", new_passwd));
893 #endif
894 return True;
898 * Now use new_p16 as the key to see if the old
899 * password matches.
901 D_P16(new_ntp16, lmhash, unenc_old_pw);
902 D_P16(new_ntp16, nthash, unenc_old_ntpw);
904 if (memcmp(lanman_pw, unenc_old_pw, 16))
906 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
907 return False;
910 if (memcmp(nt_pw, unenc_old_ntpw, 16))
912 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
913 return False;
915 #ifdef DEBUG_PASSWORD
916 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
917 #endif
918 return True;
921 /***********************************************************
922 Code to change the oem password. Changes both the lanman
923 and NT hashes.
924 ************************************************************/
926 BOOL change_oem_password(SAM_ACCOUNT *hnd, char *new_passwd)
928 BOOL ret;
930 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
931 return False;
934 /* Now write it into the file. */
935 become_root();
936 ret = pdb_update_sam_account (hnd);
937 unbecome_root();
939 return ret;