Merge from 2.2
[Samba/gbeck.git] / source3 / smbd / chgpasswd.c
blob741f5ef0aa178814aaae40e6c3036fcc3ce8d474
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Samba utility functions
5 Copyright (C) Andrew Tridgell 1992-1998
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 BOOL 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 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 (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
173 DEBUG(3, ("Could not re-direct stdin\n"));
174 return (False);
176 if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
178 DEBUG(3, ("Could not re-direct stdout\n"));
179 return (False);
181 if (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 stermios.c_oflag &= ~(ONLCR);
201 if (tcsetattr(0, TCSANOW, &stermios) < 0)
203 DEBUG(3, ("could not set attributes of pty\n"));
204 return (False);
207 /* make us completely into the right uid */
208 if (!as_root)
210 become_user_permanently(uid, gid);
213 DEBUG(10,
214 ("Invoking '%s' as password change program.\n",
215 passwordprogram));
217 /* execl() password-change application */
218 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
220 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
221 return (False);
223 return (True);
226 static int expect(int master, char *issue, char *expected)
228 pstring buffer;
229 int attempts, timeout, nread, len;
230 BOOL match = False;
232 for (attempts = 0; attempts < 2; attempts++) {
233 if (!strequal(issue, ".")) {
234 if (lp_passwd_chat_debug())
235 DEBUG(100, ("expect: sending [%s]\n", issue));
237 if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
238 DEBUG(2,("expect: (short) write returned %d\n", len ));
239 return False;
243 if (strequal(expected, "."))
244 return True;
246 timeout = 2000;
247 nread = 0;
248 buffer[nread] = 0;
250 while ((len = read_with_timeout(master, buffer + nread, 1,
251 sizeof(buffer) - nread - 1,
252 timeout)) > 0) {
253 nread += len;
254 buffer[nread] = 0;
257 /* Eat leading/trailing whitespace before match. */
258 pstring str;
259 pstrcpy( str, buffer);
260 trim_string( str, " ", " ");
262 if ((match = (unix_wild_match(expected, str) == 0)))
263 timeout = 200;
267 if (lp_passwd_chat_debug())
268 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
269 expected, buffer, match ? "yes" : "no" ));
271 if (match)
272 break;
274 if (len < 0) {
275 DEBUG(2, ("expect: %s\n", strerror(errno)));
276 return False;
280 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
281 return match;
284 static void pwd_sub(char *buf)
286 all_string_sub(buf, "\\n", "\n", 0);
287 all_string_sub(buf, "\\r", "\r", 0);
288 all_string_sub(buf, "\\s", " ", 0);
289 all_string_sub(buf, "\\t", "\t", 0);
292 static int talktochild(int master, char *seq)
294 int count = 0;
295 fstring issue, expected;
297 fstrcpy(issue, ".");
299 while (next_token(&seq, expected, NULL, sizeof(expected)))
301 pwd_sub(expected);
302 count++;
304 if (!expect(master, issue, expected))
306 DEBUG(3, ("Response %d incorrect\n", count));
307 return False;
310 if (!next_token(&seq, issue, NULL, sizeof(issue)))
311 fstrcpy(issue, ".");
313 pwd_sub(issue);
315 if (!strequal(issue, ".")) {
316 /* we have one final issue to send */
317 fstrcpy(expected, ".");
318 if (!expect(master, issue, expected))
319 return False;
322 return (count > 0);
325 static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
326 char *chatsequence, BOOL as_root)
328 char *slavedev;
329 int master;
330 pid_t pid, wpid;
331 int wstat;
332 BOOL chstat = False;
334 if (pass == NULL)
336 DEBUG(0,
337 ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
338 return False;
341 /* allocate a pseudo-terminal device */
342 if ((master = findpty(&slavedev)) < 0)
344 DEBUG(3,
345 ("Cannot Allocate pty for password change: %s\n",
346 pass->pw_name));
347 return (False);
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)
359 DEBUG(3,
360 ("Cannot fork() child for password change: %s\n",
361 pass->pw_name));
362 close(master);
363 CatchChild();
364 return (False);
367 /* we now have a pty */
368 if (pid > 0)
369 { /* This is the parent process */
370 if ((chstat = talktochild(master, chatsequence)) == False)
372 DEBUG(3,
373 ("Child failed to change password: %s\n",
374 pass->pw_name));
375 kill(pid, SIGKILL); /* be sure to end this process */
378 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
380 if (errno == EINTR)
382 errno = 0;
383 continue;
385 break;
388 if (wpid < 0)
390 DEBUG(3, ("The process is no longer waiting!\n\n"));
391 close(master);
392 CatchChild();
393 return (False);
397 * Go back to ignoring children.
399 CatchChild();
401 close(master);
403 if (pid != wpid)
405 DEBUG(3,
406 ("We were waiting for the wrong process ID\n"));
407 return (False);
409 if (WIFEXITED(wstat) == 0)
411 DEBUG(3,
412 ("The process exited while we were waiting\n"));
413 return (False);
415 if (WEXITSTATUS(wstat) != 0)
417 DEBUG(3,
418 ("The status of the process exiting was %d\n",
419 wstat));
420 return (False);
424 else
426 /* CHILD */
429 * Lose any oplock capabilities.
431 oplock_set_capability(False, False);
433 /* make sure it doesn't freeze */
434 alarm(20);
436 if (as_root)
437 become_root();
439 DEBUG(3,
440 ("Dochild for user %s (uid=%d,gid=%d)\n", pass->pw_name,
441 (int)getuid(), (int)getgid()));
442 chstat =
443 dochild(master, slavedev, pass, passwordprogram,
444 as_root);
446 if (as_root)
447 unbecome_root();
450 * The child should never return from dochild() ....
453 DEBUG(0,
454 ("chat_with_program: Error: dochild() returned %d\n",
455 chstat));
456 exit(1);
459 if (chstat)
460 DEBUG(3,
461 ("Password change %ssuccessful for user %s\n",
462 (chstat ? "" : "un"), pass->pw_name));
463 return (chstat);
467 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
469 pstring passwordprogram;
470 pstring chatsequence;
471 size_t i;
472 size_t len;
474 struct passwd *pass;
476 DEBUG(3, ("Password change for user: %s\n", name));
478 #if DEBUG_PASSWORD
479 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
480 #endif
482 /* Take the passed information and test it for minimum criteria */
483 /* Minimum password length */
484 if (strlen(newpass) < lp_min_passwd_length()) {
485 /* too short, must be at least MINPASSWDLENGTH */
486 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
487 name, lp_min_passwd_length()));
488 return (False); /* inform the user */
491 /* Password is same as old password */
492 if (strcmp(oldpass, newpass) == 0) {
493 /* don't allow same password */
494 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
495 return (False); /* inform the user */
499 * Check the old and new passwords don't contain any control
500 * characters.
503 len = strlen(oldpass);
504 for (i = 0; i < len; i++) {
505 if (iscntrl((int)oldpass[i])) {
506 DEBUG(0,
507 ("chat_with_program: oldpass contains control characters (disallowed).\n"));
508 return False;
512 len = strlen(newpass);
513 for (i = 0; i < len; i++) {
514 if (iscntrl((int)newpass[i])) {
515 DEBUG(0,
516 ("chat_with_program: newpass contains control characters (disallowed).\n"));
517 return False;
521 pass = Get_Pwnam(name);
523 #ifdef WITH_PAM
524 if (lp_pam_password_change()) {
525 BOOL ret;
527 if (as_root)
528 become_root();
530 if (pass) {
531 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
532 } else {
533 ret = smb_pam_passchange(name, oldpass, newpass);
536 if (as_root)
537 unbecome_root();
539 return ret;
541 #endif
543 /* A non-PAM password change just doen't make sense without a valid local user */
545 if (pass == NULL)
547 DEBUG(0,
548 ("chgpasswd: user %s doesn't exist in the UNIX password database.\n",
549 name));
550 return False;
553 pstrcpy(passwordprogram, lp_passwd_program());
554 pstrcpy(chatsequence, lp_passwd_chat());
556 if (!*chatsequence) {
557 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
558 return (False);
561 if (!*passwordprogram) {
562 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
563 return (False);
566 if (as_root) {
567 /* The password program *must* contain the user name to work. Fail if not. */
568 if (strstr(passwordprogram, "%u") == NULL) {
569 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
570 the string %%u, and the given string %s does not.\n", passwordprogram ));
571 return False;
575 pstring_sub(passwordprogram, "%u", name);
576 /* note that we do NOT substitute the %o and %n in the password program
577 as this would open up a security hole where the user could use
578 a new password containing shell escape characters */
580 pstring_sub(chatsequence, "%u", name);
581 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
582 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
583 return (chat_with_program
584 (passwordprogram, pass, chatsequence, as_root));
587 #else /* ALLOW_CHANGE_PASSWORD */
589 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
591 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
592 return (False);
594 #endif /* ALLOW_CHANGE_PASSWORD */
596 /***********************************************************
597 Code to check the lanman hashed password.
598 ************************************************************/
600 BOOL check_lanman_password(char *user, uchar * pass1,
601 uchar * pass2, SAM_ACCOUNT **hnd)
603 uchar unenc_new_pw[16];
604 uchar unenc_old_pw[16];
605 SAM_ACCOUNT *sampass = NULL;
606 uint16 acct_ctrl;
607 const uint8 *lanman_pw;
608 BOOL ret;
610 become_root();
611 ret = pdb_getsampwnam(sampass, user);
612 unbecome_root();
614 if (ret == False) {
615 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
616 pdb_free_sam(&sampass);
617 return False;
620 acct_ctrl = pdb_get_acct_ctrl (sampass);
621 lanman_pw = pdb_get_lanman_passwd (sampass);
623 if (acct_ctrl & ACB_DISABLED) {
624 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
625 pdb_free_sam(&sampass);
626 return False;
629 if (lanman_pw == NULL) {
630 if (acct_ctrl & ACB_PWNOTREQ) {
631 /* this saves the pointer for the caller */
632 *hnd = sampass;
633 return True;
634 } else {
635 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
636 pdb_free_sam(&sampass);
637 return False;
641 /* Get the new lanman hash. */
642 D_P16(lanman_pw, pass2, unenc_new_pw);
644 /* Use this to get the old lanman hash. */
645 D_P16(unenc_new_pw, pass1, unenc_old_pw);
647 /* Check that the two old passwords match. */
648 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
649 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
650 pdb_free_sam(&sampass);
651 return False;
654 /* this saves the pointer for the caller */
655 *hnd = sampass;
656 return True;
659 /***********************************************************
660 Code to change the lanman hashed password.
661 It nulls out the NT hashed password as it will
662 no longer be valid.
663 ************************************************************/
665 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
666 uchar * pass2)
668 static uchar null_pw[16];
669 uchar unenc_new_pw[16];
670 BOOL ret;
671 uint16 acct_ctrl;
672 const uint8 *pwd;
674 if (sampass == NULL) {
675 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
676 return False;
679 acct_ctrl = pdb_get_acct_ctrl(sampass);
680 pwd = pdb_get_lanman_passwd(sampass);
682 if (acct_ctrl & ACB_DISABLED) {
683 DEBUG(0,("change_lanman_password: account %s disabled.\n",
684 pdb_get_username(sampass)));
685 return False;
688 if (pwd == NULL) {
689 if (acct_ctrl & ACB_PWNOTREQ) {
690 uchar no_pw[14];
691 memset(no_pw, '\0', 14);
692 E_P16(no_pw, null_pw);
694 /* Get the new lanman hash. */
695 D_P16(null_pw, pass2, unenc_new_pw);
696 } else {
697 DEBUG(0,("change_lanman_password: no lanman password !\n"));
698 return False;
700 } else {
701 /* Get the new lanman hash. */
702 D_P16(pwd, pass2, unenc_new_pw);
705 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw)) {
706 return False;
709 if (!pdb_set_nt_passwd (sampass, NULL)) {
710 return False; /* We lose the NT hash. Sorry. */
713 if (!pdb_set_pass_changed_now (sampass)) {
714 pdb_free_sam(&sampass);
715 /* Not quite sure what this one qualifies as, but this will do */
716 return False;
719 /* Now flush the sam_passwd struct to persistent storage */
720 become_root();
721 ret = pdb_update_sam_account (sampass, False);
722 unbecome_root();
724 return ret;
727 /***********************************************************
728 Code to check and change the OEM hashed password.
729 ************************************************************/
730 BOOL pass_oem_change(char *user,
731 uchar * lmdata, uchar * lmhash,
732 uchar * ntdata, uchar * nthash)
734 fstring new_passwd;
735 SAM_ACCOUNT *sampass = NULL;
736 BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
737 &sampass, new_passwd, sizeof(new_passwd));
740 * At this point we have the new case-sensitive plaintext
741 * password in the fstring new_passwd. If we wanted to synchronise
742 * with UNIX passwords we would call a UNIX password changing
743 * function here. However it would have to be done as root
744 * as the plaintext of the old users password is not
745 * available. JRA.
748 if ((ret) && lp_unix_password_sync())
749 ret = chgpasswd(user, "", new_passwd, True);
751 if (ret)
752 ret = change_oem_password(sampass, new_passwd);
754 memset(new_passwd, 0, sizeof(new_passwd));
756 pdb_free_sam(&sampass);
758 return ret;
761 /***********************************************************
762 Code to check the OEM hashed password.
764 this function ignores the 516 byte nt OEM hashed password
765 but does use the lm OEM password to check the nt hashed-hash.
767 ************************************************************/
768 static BOOL check_oem_password(const char *user,
769 uchar * lmdata, const uchar * lmhash,
770 const uchar * ntdata, const uchar * nthash,
771 SAM_ACCOUNT **hnd, char *new_passwd,
772 int new_passwd_size)
774 static uchar null_pw[16];
775 static uchar null_ntpw[16];
776 SAM_ACCOUNT *sampass = NULL;
777 const uint8 *lanman_pw, *nt_pw;
778 uint16 acct_ctrl;
779 int new_pw_len;
780 uchar new_ntp16[16];
781 uchar unenc_old_ntpw[16];
782 uchar new_p16[16];
783 uchar unenc_old_pw[16];
784 char no_pw[2];
785 BOOL ret;
787 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
789 pdb_init_sam(&sampass);
791 become_root();
792 ret = pdb_getsampwnam(sampass, user);
793 unbecome_root();
795 if (ret == False) {
796 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
797 return False;
800 *hnd = sampass;
802 acct_ctrl = pdb_get_acct_ctrl(sampass);
804 if (acct_ctrl & ACB_DISABLED) {
805 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
806 return False;
809 /* construct a null password (in case one is needed */
810 no_pw[0] = 0;
811 no_pw[1] = 0;
812 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
814 /* save pointers to passwords so we don't have to keep looking them up */
815 lanman_pw = pdb_get_lanman_passwd(sampass);
816 nt_pw = pdb_get_nt_passwd (sampass);
818 /* check for null passwords */
819 if (lanman_pw == NULL) {
820 if (!(acct_ctrl & ACB_PWNOTREQ)) {
821 DEBUG(0,("check_oem_password: no lanman password !\n"));
822 return False;
826 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
827 if (!(acct_ctrl & ACB_PWNOTREQ)) {
828 DEBUG(0,("check_oem_password: no ntlm password !\n"));
829 return False;
834 * Call the hash function to get the new password.
836 SamOEMhash( lmdata, lanman_pw, 516);
839 * The length of the new password is in the last 4 bytes of
840 * the data buffer.
843 new_pw_len = IVAL(lmdata, 512);
844 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
845 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
846 return False;
849 if (nt_pass_set) {
851 * nt passwords are in unicode
853 pull_ucs2(NULL, new_passwd,
854 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
855 new_passwd_size, new_pw_len, 0);
856 } else {
857 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
858 new_passwd[new_pw_len] = 0;
862 * To ensure we got the correct new password, hash it and
863 * use it as a key to test the passed old password.
866 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
868 if (!nt_pass_set)
871 * Now use new_p16 as the key to see if the old
872 * password matches.
874 D_P16(new_p16, lmhash, unenc_old_pw);
876 if (memcmp(lanman_pw, unenc_old_pw, 16))
878 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
879 return False;
882 #ifdef DEBUG_PASSWORD
883 DEBUG(100,
884 ("check_oem_password: password %s ok\n", new_passwd));
885 #endif
886 return True;
890 * Now use new_p16 as the key to see if the old
891 * password matches.
893 D_P16(new_ntp16, lmhash, unenc_old_pw);
894 D_P16(new_ntp16, nthash, unenc_old_ntpw);
896 if (memcmp(lanman_pw, unenc_old_pw, 16))
898 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
899 return False;
902 if (memcmp(nt_pw, unenc_old_ntpw, 16))
904 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
905 return False;
907 #ifdef DEBUG_PASSWORD
908 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
909 #endif
910 return True;
913 /***********************************************************
914 Code to change the oem password. Changes both the lanman
915 and NT hashes.
916 ************************************************************/
918 BOOL change_oem_password(SAM_ACCOUNT *hnd, char *new_passwd)
920 BOOL ret;
922 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
923 return False;
926 /* Now write it into the file. */
927 become_root();
928 ret = pdb_update_sam_account (hnd, False);
929 unbecome_root();
931 return ret;
934 /***********************************************************
935 Code to check a plaintext password against smbpasswd entries.
936 ***********************************************************/
938 BOOL check_plaintext_password(char *user, char *old_passwd,
939 int old_passwd_size, SAM_ACCOUNT **hnd)
941 SAM_ACCOUNT *sampass = NULL;
942 uchar old_pw[16], old_ntpw[16];
943 BOOL ret;
945 pdb_init_sam(&sampass);
947 become_root();
948 ret = pdb_getsampwnam(sampass, user);
949 unbecome_root();
951 *hnd = sampass;
953 if (ret == False)
955 DEBUG(0,("check_plaintext_password: getsmbpwnam returned NULL\n"));
956 return False;
959 if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED)
961 DEBUG(0,("check_plaintext_password: account %s disabled.\n", user));
962 return (False);
965 nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
967 #ifdef DEBUG_PASSWORD
968 DEBUG(100, ("check_plaintext_password: nt_passwd \n"));
969 dump_data(100, pdb_get_nt_passwd(sampass), 16);
970 DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
971 dump_data(100, old_ntpw, 16);
972 DEBUG(100, ("check_plaintext_password: lanman_passwd \n"));
973 dump_data(100, pdb_get_lanman_passwd(sampass), 16);
974 DEBUG(100, ("check_plaintext_password: old_pw\n"));
975 dump_data(100, old_pw, 16);
976 #endif
978 if (memcmp(pdb_get_nt_passwd(sampass), old_ntpw, 16)
979 && memcmp(pdb_get_lanman_passwd(sampass), old_pw, 16))
980 return (False);
981 else
982 return (True);