me stupid.
[Samba.git] / source / smbd / chgpasswd.c
blob030c69bd4a7a317f06221fe492af36ea04971135
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 int DEBUGLEVEL;
53 extern struct passdb_ops pdb_ops;
55 #if ALLOW_CHANGE_PASSWORD
57 static int findpty(char **slave)
59 int master;
60 static fstring line;
61 DIR *dirp;
62 char *dpname;
64 #if defined(HAVE_GRANTPT)
65 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
66 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
68 grantpt(master);
69 unlockpt(master);
70 *slave = (char *)ptsname(master);
71 if (*slave == NULL)
73 DEBUG(0,
74 ("findpty: Unable to create master/slave pty pair.\n"));
75 /* Stop fd leak on error. */
76 close(master);
77 return -1;
79 else
81 DEBUG(10,
82 ("findpty: Allocated slave pty %s\n", *slave));
83 return (master);
86 #endif /* HAVE_GRANTPT */
88 fstrcpy(line, "/dev/ptyXX");
90 dirp = opendir("/dev");
91 if (!dirp)
92 return (-1);
93 while ((dpname = readdirname(dirp)) != NULL)
95 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
97 DEBUG(3,
98 ("pty: try to open %s, line was %s\n", dpname,
99 line));
100 line[8] = dpname[3];
101 line[9] = dpname[4];
102 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
104 DEBUG(3, ("pty: opened %s\n", line));
105 line[5] = 't';
106 *slave = line;
107 closedir(dirp);
108 return (master);
112 closedir(dirp);
113 return (-1);
116 static int dochild(int master, char *slavedev, char *name,
117 char *passwordprogram, BOOL as_root)
119 int slave;
120 struct termios stermios;
121 struct passwd *pass = Get_Pwnam(name, True);
122 gid_t gid;
123 uid_t uid;
125 if (pass == NULL)
127 DEBUG(0,
128 ("dochild: user name %s doesn't exist in the UNIX password database.\n",
129 name));
130 return False;
133 gid = pass->pw_gid;
134 uid = pass->pw_uid;
136 gain_root_privilege();
138 /* Start new session - gets rid of controlling terminal. */
139 if (setsid() < 0)
141 DEBUG(3,
142 ("Weirdness, couldn't let go of controlling terminal\n"));
143 return (False);
146 /* Open slave pty and acquire as new controlling terminal. */
147 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
149 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
150 return (False);
152 #ifdef I_PUSH
153 ioctl(slave, I_PUSH, "ptem");
154 ioctl(slave, I_PUSH, "ldterm");
155 #elif defined(TIOCSCTTY)
156 if (ioctl(slave, TIOCSCTTY, 0) < 0)
158 DEBUG(3, ("Error in ioctl call for slave pty\n"));
159 /* return(False); */
161 #endif
163 /* Close master. */
164 close(master);
166 /* Make slave stdin/out/err of child. */
168 if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
170 DEBUG(3, ("Could not re-direct stdin\n"));
171 return (False);
173 if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
175 DEBUG(3, ("Could not re-direct stdout\n"));
176 return (False);
178 if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
180 DEBUG(3, ("Could not re-direct stderr\n"));
181 return (False);
183 if (slave > 2)
184 close(slave);
186 /* Set proper terminal attributes - no echo, canonical input processing,
187 no map NL to CR/NL on output. */
189 if (tcgetattr(0, &stermios) < 0)
191 DEBUG(3,
192 ("could not read default terminal attributes on pty\n"));
193 return (False);
195 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
196 stermios.c_lflag |= ICANON;
197 stermios.c_oflag &= ~(ONLCR);
198 if (tcsetattr(0, TCSANOW, &stermios) < 0)
200 DEBUG(3, ("could not set attributes of pty\n"));
201 return (False);
204 /* make us completely into the right uid */
205 if (!as_root)
207 become_user_permanently(uid, gid);
210 DEBUG(10,
211 ("Invoking '%s' as password change program.\n",
212 passwordprogram));
214 /* execl() password-change application */
215 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
217 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
218 return (False);
220 return (True);
223 static int expect(int master, char *issue, char *expected)
225 pstring buffer;
226 int attempts, timeout, nread, len;
227 BOOL match = False;
229 for (attempts = 0; attempts < 2; attempts++)
231 if (!strequal(issue, "."))
233 if (lp_passwd_chat_debug())
234 DEBUG(100, ("expect: sending [%s]\n", issue));
236 write(master, issue, strlen(issue));
239 if (strequal(expected, "."))
240 return True;
242 timeout = 2000;
243 nread = 0;
244 buffer[nread] = 0;
246 while ((len = read_with_timeout(master, buffer + nread, 1,
247 sizeof(buffer) - nread - 1,
248 timeout)) > 0)
250 nread += len;
251 buffer[nread] = 0;
253 if ((match = (wild_match(expected, buffer) == 0)))
254 timeout = 200;
257 if (lp_passwd_chat_debug())
258 DEBUG(100, ("expect: expected [%s] received [%s]\n",
259 expected, buffer));
261 if (match)
262 break;
264 if (len < 0)
266 DEBUG(2, ("expect: %s\n", strerror(errno)));
267 return False;
271 return match;
274 static void pwd_sub(char *buf)
276 all_string_sub(buf, "\\n", "\n", 0);
277 all_string_sub(buf, "\\r", "\r", 0);
278 all_string_sub(buf, "\\s", " ", 0);
279 all_string_sub(buf, "\\t", "\t", 0);
282 static int talktochild(int master, char *seq)
284 int count = 0;
285 fstring issue, expected;
287 fstrcpy(issue, ".");
289 while (next_token(&seq, expected, NULL, sizeof(expected)))
291 pwd_sub(expected);
292 count++;
294 if (!expect(master, issue, expected))
296 DEBUG(3, ("Response %d incorrect\n", count));
297 return False;
300 if (!next_token(&seq, issue, NULL, sizeof(issue)))
301 fstrcpy(issue, ".");
303 pwd_sub(issue);
306 return (count > 0);
309 static BOOL chat_with_program(char *passwordprogram, char *name,
310 char *chatsequence, BOOL as_root)
312 char *slavedev;
313 int master;
314 pid_t pid, wpid;
315 int wstat;
316 BOOL chstat = False;
318 /* allocate a pseudo-terminal device */
319 if ((master = findpty(&slavedev)) < 0)
321 DEBUG(3,
322 ("Cannot Allocate pty for password change: %s\n",
323 name));
324 return (False);
328 * We need to temporarily stop CatchChild from eating
329 * SIGCLD signals as it also eats the exit status code. JRA.
332 CatchChildLeaveStatus();
334 if ((pid = sys_fork()) < 0)
336 DEBUG(3,
337 ("Cannot fork() child for password change: %s\n",
338 name));
339 close(master);
340 CatchChild();
341 return (False);
344 /* we now have a pty */
345 if (pid > 0)
346 { /* This is the parent process */
347 if ((chstat = talktochild(master, chatsequence)) == False)
349 DEBUG(3,
350 ("Child failed to change password: %s\n",
351 name));
352 kill(pid, SIGKILL); /* be sure to end this process */
355 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
357 if (errno == EINTR)
359 errno = 0;
360 continue;
362 break;
365 if (wpid < 0)
367 DEBUG(3, ("The process is no longer waiting!\n\n"));
368 close(master);
369 CatchChild();
370 return (False);
374 * Go back to ignoring children.
376 CatchChild();
378 close(master);
380 if (pid != wpid)
382 DEBUG(3,
383 ("We were waiting for the wrong process ID\n"));
384 return (False);
386 if (WIFEXITED(wstat) == 0)
388 DEBUG(3,
389 ("The process exited while we were waiting\n"));
390 return (False);
392 if (WEXITSTATUS(wstat) != 0)
394 DEBUG(3,
395 ("The status of the process exiting was %d\n",
396 wstat));
397 return (False);
401 else
403 /* CHILD */
406 * Lose any oplock capabilities.
408 oplock_set_capability(False, False);
410 /* make sure it doesn't freeze */
411 alarm(20);
413 if (as_root)
414 become_root();
416 DEBUG(3,
417 ("Dochild for user %s (uid=%d,gid=%d)\n", name,
418 (int)getuid(), (int)getgid()));
419 chstat =
420 dochild(master, slavedev, name, passwordprogram,
421 as_root);
423 if (as_root)
424 unbecome_root();
427 * The child should never return from dochild() ....
430 DEBUG(0,
431 ("chat_with_program: Error: dochild() returned %d\n",
432 chstat));
433 exit(1);
436 if (chstat)
437 DEBUG(3,
438 ("Password change %ssuccessful for user %s\n",
439 (chstat ? "" : "un"), name));
440 return (chstat);
444 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
446 pstring passwordprogram;
447 pstring chatsequence;
448 size_t i;
449 size_t len;
451 strlower(name);
452 DEBUG(3, ("Password change for user: %s\n", name));
454 #if DEBUG_PASSWORD
455 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
456 #endif
458 /* Take the passed information and test it for minimum criteria */
459 /* Minimum password length */
460 if (strlen(newpass) < lp_min_passwd_length()) {
461 /* too short, must be at least MINPASSWDLENGTH */
462 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
463 name, lp_min_passwd_length()));
464 return (False); /* inform the user */
467 /* Password is same as old password */
468 if (strcmp(oldpass, newpass) == 0) {
469 /* don't allow same password */
470 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
471 return (False); /* inform the user */
475 * Check the old and new passwords don't contain any control
476 * characters.
479 len = strlen(oldpass);
480 for (i = 0; i < len; i++) {
481 if (iscntrl((int)oldpass[i])) {
482 DEBUG(0,
483 ("chat_with_program: oldpass contains control characters (disallowed).\n"));
484 return False;
488 len = strlen(newpass);
489 for (i = 0; i < len; i++) {
490 if (iscntrl((int)newpass[i])) {
491 DEBUG(0,
492 ("chat_with_program: newpass contains control characters (disallowed).\n"));
493 return False;
497 #ifdef WITH_PAM
498 if (lp_pam_password_change()) {
499 BOOL ret;
501 if (as_root)
502 become_root();
504 ret = smb_pam_passchange(name, oldpass, newpass);
506 if (as_root)
507 unbecome_root();
509 return ret;
511 #endif
513 pstrcpy(passwordprogram, lp_passwd_program());
514 pstrcpy(chatsequence, lp_passwd_chat());
516 if (!*chatsequence) {
517 DEBUG(2, ("Null chat sequence - no password changing\n"));
518 return (False);
521 if (!*passwordprogram) {
522 DEBUG(2, ("Null password program - no password changing\n"));
523 return (False);
526 pstring_sub(passwordprogram, "%u", name);
527 /* note that we do NOT substitute the %o and %n in the password program
528 as this would open up a security hole where the user could use
529 a new password containing shell escape characters */
531 pstring_sub(chatsequence, "%u", name);
532 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
533 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
534 return (chat_with_program
535 (passwordprogram, name, chatsequence, as_root));
538 #else /* ALLOW_CHANGE_PASSWORD */
540 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
542 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
543 return (False);
545 #endif /* ALLOW_CHANGE_PASSWORD */
547 /***********************************************************
548 Code to check the lanman hashed password.
549 ************************************************************/
551 BOOL check_lanman_password(char *user, uchar * pass1,
552 uchar * pass2, SAM_ACCOUNT **hnd)
554 static uchar null_pw[16];
555 uchar unenc_new_pw[16];
556 uchar unenc_old_pw[16];
557 SAM_ACCOUNT *sampass = NULL;
558 uint16 acct_ctrl;
559 uint8 *lanman_pw;
560 BOOL ret;
562 become_root();
563 ret = pdb_getsampwnam(sampass, user);
564 unbecome_root();
566 if (ret == False) {
567 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
568 pdb_free_sam(sampass);
569 return False;
572 acct_ctrl = pdb_get_acct_ctrl (sampass);
573 lanman_pw = pdb_get_lanman_passwd (sampass);
575 if (acct_ctrl & ACB_DISABLED) {
576 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
577 pdb_free_sam(sampass);
578 return False;
581 if ((lanman_pw == NULL) && (acct_ctrl & ACB_PWNOTREQ)) {
582 uchar no_pw[14];
583 memset(no_pw, '\0', 14);
584 E_P16(no_pw, null_pw);
585 pdb_set_lanman_passwd (sampass, null_pw);
587 else if (lanman_pw == NULL) {
588 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
589 pdb_free_sam(sampass);
590 return False;
593 /* Get the new lanman hash. */
594 D_P16(lanman_pw, pass2, unenc_new_pw);
596 /* Use this to get the old lanman hash. */
597 D_P16(unenc_new_pw, pass1, unenc_old_pw);
599 /* Check that the two old passwords match. */
600 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
601 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
602 pdb_free_sam(sampass);
603 return False;
606 /* this saves the pointer for the caller */
607 *hnd = sampass;
609 return True;
612 /***********************************************************
613 Code to change the lanman hashed password.
614 It nulls out the NT hashed password as it will
615 no longer be valid.
616 ************************************************************/
618 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
619 uchar * pass2)
621 static uchar null_pw[16];
622 uchar unenc_new_pw[16];
623 BOOL ret;
624 uint16 acct_ctrl;
625 uint8 *pwd;
627 if (sampass == NULL) {
628 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
629 return False;
632 acct_ctrl = pdb_get_acct_ctrl(sampass);
633 pwd = pdb_get_lanman_passwd(sampass);
635 if (acct_ctrl & ACB_DISABLED) {
636 DEBUG(0,("change_lanman_password: account %s disabled.\n",
637 pdb_get_username(sampass)));
638 return False;
641 if ((pwd == NULL) && (acct_ctrl & ACB_PWNOTREQ)) {
642 uchar no_pw[14];
643 memset(no_pw, '\0', 14);
644 E_P16(no_pw, null_pw);
645 pdb_set_lanman_passwd(sampass, null_pw);
647 else if (pwd == NULL) {
648 DEBUG(0,("change_lanman_password: no lanman password !\n"));
649 return False;
652 /* Get the new lanman hash. */
653 D_P16(pwd, pass2, unenc_new_pw);
655 pdb_set_lanman_passwd(sampass, unenc_new_pw);
656 pdb_set_nt_passwd (sampass, NULL); /* We lose the NT hash. Sorry. */
658 /* Now flush the sam_passwd struct to persistent storage */
659 become_root();
660 ret = pdb_update_sam_account (sampass, False);
661 unbecome_root();
663 return ret;
666 /***********************************************************
667 Code to check and change the OEM hashed password.
668 ************************************************************/
669 BOOL pass_oem_change(char *user,
670 uchar * lmdata, uchar * lmhash,
671 uchar * ntdata, uchar * nthash)
673 fstring new_passwd;
674 SAM_ACCOUNT *sampass = NULL;
675 BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
676 &sampass, new_passwd, sizeof(new_passwd));
679 * At this point we have the new case-sensitive plaintext
680 * password in the fstring new_passwd. If we wanted to synchronise
681 * with UNIX passwords we would call a UNIX password changing
682 * function here. However it would have to be done as root
683 * as the plaintext of the old users password is not
684 * available. JRA.
687 if (ret && lp_unix_password_sync())
688 ret = chgpasswd(user, "", new_passwd, True);
690 if (ret)
691 ret = change_oem_password(sampass, new_passwd, False);
693 memset(new_passwd, 0, sizeof(new_passwd));
695 pdb_free_sam(sampass);
697 return ret;
700 /***********************************************************
701 Code to check the OEM hashed password.
703 this function ignores the 516 byte nt OEM hashed password
704 but does use the lm OEM password to check the nt hashed-hash.
706 ************************************************************/
707 BOOL check_oem_password(char *user,
708 uchar * lmdata, uchar * lmhash,
709 uchar * ntdata, uchar * nthash,
710 SAM_ACCOUNT **hnd, char *new_passwd,
711 int new_passwd_size)
713 static uchar null_pw[16];
714 static uchar null_ntpw[16];
715 SAM_ACCOUNT *sampass = NULL;
716 uint8 *lanman_pw, *nt_pw;
717 uint16 acct_ctrl;
718 int new_pw_len;
719 uchar new_ntp16[16];
720 uchar unenc_old_ntpw[16];
721 uchar new_p16[16];
722 uchar unenc_old_pw[16];
723 char no_pw[2];
724 BOOL ret;
726 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
728 pdb_init_sam(&sampass);
730 become_root();
731 ret = pdb_getsampwnam(sampass, user);
732 unbecome_root();
734 if (ret == False) {
735 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
736 return False;
739 *hnd = sampass;
741 acct_ctrl = pdb_get_acct_ctrl(sampass);
743 if (acct_ctrl & ACB_DISABLED) {
744 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
745 return False;
748 /* construct a null password (in case one is needed */
749 no_pw[0] = 0;
750 no_pw[1] = 0;
751 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
753 /* save pointers to passwords so we don't have to keep looking them up */
754 lanman_pw = pdb_get_lanman_passwd(sampass);
755 nt_pw = pdb_get_nt_passwd (sampass);
757 /* check for null passwords */
758 if (lanman_pw == NULL) {
759 if (acct_ctrl & ACB_PWNOTREQ)
760 pdb_set_lanman_passwd(sampass, null_pw);
761 else {
762 DEBUG(0,("check_oem_password: no lanman password !\n"));
763 return False;
767 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
768 if (acct_ctrl & ACB_PWNOTREQ)
769 pdb_set_nt_passwd(sampass, null_pw);
770 else {
771 DEBUG(0,("check_oem_password: no ntlm password !\n"));
772 return False;
777 * Call the hash function to get the new password.
779 SamOEMhash((uchar *) lmdata, (uchar *)lanman_pw, 516);
782 * The length of the new password is in the last 4 bytes of
783 * the data buffer.
786 new_pw_len = IVAL(lmdata, 512);
787 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
788 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
789 return False;
792 if (nt_pass_set) {
794 * nt passwords are in unicode
796 pull_ucs2(NULL, new_passwd,
797 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
798 new_passwd_size, new_pw_len, 0);
799 } else {
800 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
801 new_passwd[new_pw_len] = 0;
805 * To ensure we got the correct new password, hash it and
806 * use it as a key to test the passed old password.
809 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
811 if (!nt_pass_set)
814 * Now use new_p16 as the key to see if the old
815 * password matches.
817 D_P16(new_p16, lmhash, unenc_old_pw);
819 if (memcmp(lanman_pw, unenc_old_pw, 16))
821 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
822 return False;
825 #ifdef DEBUG_PASSWORD
826 DEBUG(100,
827 ("check_oem_password: password %s ok\n", new_passwd));
828 #endif
829 return True;
833 * Now use new_p16 as the key to see if the old
834 * password matches.
836 D_P16(new_ntp16, lmhash, unenc_old_pw);
837 D_P16(new_ntp16, nthash, unenc_old_ntpw);
839 if (memcmp(lanman_pw, unenc_old_pw, 16))
841 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
842 return False;
845 if (memcmp(nt_pw, unenc_old_ntpw, 16))
847 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
848 return False;
850 #ifdef DEBUG_PASSWORD
851 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
852 #endif
853 return True;
856 /***********************************************************
857 Code to change the oem password. Changes both the lanman
858 and NT hashes.
859 override = False, normal
860 override = True, override XXXXXXXXXX'd password
861 ************************************************************/
863 BOOL change_oem_password(SAM_ACCOUNT *hnd, char *new_passwd,
864 BOOL override)
866 int ret;
867 uchar new_nt_p16[16];
868 uchar new_p16[16];
870 nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
872 pdb_set_lanman_passwd (hnd, new_p16);
873 pdb_set_nt_passwd (hnd, new_nt_p16);
875 /* Now write it into the file. */
876 become_root();
877 ret = pdb_update_sam_account (hnd, override);
878 unbecome_root();
880 memset(new_passwd, '\0', strlen(new_passwd));
882 return ret;
885 /***********************************************************
886 Code to check a plaintext password against smbpasswd entries.
887 ***********************************************************/
889 BOOL check_plaintext_password(char *user, char *old_passwd,
890 int old_passwd_size, SAM_ACCOUNT **hnd)
892 SAM_ACCOUNT *sampass = NULL;
893 uchar old_pw[16], old_ntpw[16];
894 BOOL ret;
896 pdb_init_sam(&sampass);
898 become_root();
899 ret = pdb_getsampwnam(sampass, user);
900 unbecome_root();
902 *hnd = sampass;
904 if (ret == False)
906 DEBUG(0,("check_plaintext_password: getsmbpwnam returned NULL\n"));
907 return False;
910 if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED)
912 DEBUG(0,("check_plaintext_password: account %s disabled.\n", user));
913 return (False);
916 nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
918 #ifdef DEBUG_PASSWORD
919 DEBUG(100, ("check_plaintext_password: nt_passwd \n"));
920 dump_data(100, pdb_get_nt_passwd(sampass), 16);
921 DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
922 dump_data(100, old_ntpw, 16);
923 DEBUG(100, ("check_plaintext_password: lanman_passwd \n"));
924 dump_data(100, pdb_get_lanman_passwd(sampass), 16);
925 DEBUG(100, ("check_plaintext_password: old_pw\n"));
926 dump_data(100, old_pw, 16);
927 #endif
929 if (memcmp(pdb_get_nt_passwd(sampass), old_ntpw, 16)
930 && memcmp(pdb_get_lanman_passwd(sampass), old_pw, 16))
931 return (False);
932 else
933 return (True);