Fix spurious check of unix home directory during session_setup when add user script...
[Samba.git] / source / smbd / chgpasswd.c
blobb4ddeaa5cf820b0fe9649181f25577c13872947f
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 #if ALLOW_CHANGE_PASSWORD
56 static int findpty(char **slave)
58 int master;
59 static fstring line;
60 DIR *dirp;
61 char *dpname;
63 #if defined(HAVE_GRANTPT)
64 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
65 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
67 grantpt(master);
68 unlockpt(master);
69 *slave = (char *)ptsname(master);
70 if (*slave == NULL)
72 DEBUG(0,
73 ("findpty: Unable to create master/slave pty pair.\n"));
74 /* Stop fd leak on error. */
75 close(master);
76 return -1;
78 else
80 DEBUG(10,
81 ("findpty: Allocated slave pty %s\n", *slave));
82 return (master);
85 #endif /* HAVE_GRANTPT */
87 fstrcpy(line, "/dev/ptyXX");
89 dirp = opendir("/dev");
90 if (!dirp)
91 return (-1);
92 while ((dpname = readdirname(dirp)) != NULL)
94 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
96 DEBUG(3,
97 ("pty: try to open %s, line was %s\n", dpname,
98 line));
99 line[8] = dpname[3];
100 line[9] = dpname[4];
101 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
103 DEBUG(3, ("pty: opened %s\n", line));
104 line[5] = 't';
105 *slave = line;
106 closedir(dirp);
107 return (master);
111 closedir(dirp);
112 return (-1);
115 static int dochild(int master, char *slavedev, char *name,
116 char *passwordprogram, BOOL as_root)
118 int slave;
119 struct termios stermios;
120 struct passwd *pass = Get_Pwnam(name, True);
121 gid_t gid;
122 uid_t uid;
124 if (pass == NULL)
126 DEBUG(0,
127 ("dochild: user name %s doesn't exist in the UNIX password database.\n",
128 name));
129 return False;
132 gid = pass->pw_gid;
133 uid = pass->pw_uid;
135 gain_root_privilege();
137 /* Start new session - gets rid of controlling terminal. */
138 if (setsid() < 0)
140 DEBUG(3,
141 ("Weirdness, couldn't let go of controlling terminal\n"));
142 return (False);
145 /* Open slave pty and acquire as new controlling terminal. */
146 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
148 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
149 return (False);
151 #ifdef I_PUSH
152 ioctl(slave, I_PUSH, "ptem");
153 ioctl(slave, I_PUSH, "ldterm");
154 #elif defined(TIOCSCTTY)
155 if (ioctl(slave, TIOCSCTTY, 0) < 0)
157 DEBUG(3, ("Error in ioctl call for slave pty\n"));
158 /* return(False); */
160 #endif
162 /* Close master. */
163 close(master);
165 /* Make slave stdin/out/err of child. */
167 if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
169 DEBUG(3, ("Could not re-direct stdin\n"));
170 return (False);
172 if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
174 DEBUG(3, ("Could not re-direct stdout\n"));
175 return (False);
177 if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
179 DEBUG(3, ("Could not re-direct stderr\n"));
180 return (False);
182 if (slave > 2)
183 close(slave);
185 /* Set proper terminal attributes - no echo, canonical input processing,
186 no map NL to CR/NL on output. */
188 if (tcgetattr(0, &stermios) < 0)
190 DEBUG(3,
191 ("could not read default terminal attributes on pty\n"));
192 return (False);
194 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
195 stermios.c_lflag |= ICANON;
196 #ifdef ONLCR
197 stermios.c_oflag &= ~(ONLCR);
198 #endif
199 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) {
206 become_user_permanently(uid, gid);
209 DEBUG(10,
210 ("Invoking '%s' as password change program.\n",
211 passwordprogram));
213 /* execl() password-change application */
214 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
216 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
217 return (False);
219 return (True);
222 static int expect(int master, char *issue, char *expected)
224 pstring buffer;
225 int attempts, timeout, nread, len;
226 BOOL match = False;
228 for (attempts = 0; attempts < 2; attempts++) {
229 if (!strequal(issue, ".")) {
230 if (lp_passwd_chat_debug())
231 DEBUG(100, ("expect: sending [%s]\n", issue));
233 if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
234 DEBUG(2,("expect: (short) write returned %d\n", len ));
235 return False;
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) {
249 nread += len;
250 buffer[nread] = 0;
253 /* Eat leading/trailing whitespace before match. */
254 pstring str;
255 pstrcpy( str, buffer);
256 trim_string( str, " ", " ");
258 if ((match = (unix_wild_match(expected, str) == 0)))
259 timeout = 200;
263 if (lp_passwd_chat_debug())
264 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
265 expected, buffer, match ? "yes" : "no" ));
267 if (match)
268 break;
270 if (len < 0) {
271 DEBUG(2, ("expect: %s\n", strerror(errno)));
272 return False;
276 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
277 return match;
280 static void pwd_sub(char *buf)
282 all_string_sub(buf, "\\n", "\n", 0);
283 all_string_sub(buf, "\\r", "\r", 0);
284 all_string_sub(buf, "\\s", " ", 0);
285 all_string_sub(buf, "\\t", "\t", 0);
288 static int talktochild(int master, const char *seq)
290 int count = 0;
291 fstring issue, expected;
293 fstrcpy(issue, ".");
295 while (next_token(&seq, expected, NULL, sizeof(expected)))
297 pwd_sub(expected);
298 count++;
300 if (!expect(master, issue, expected))
302 DEBUG(3, ("Response %d incorrect\n", count));
303 return False;
306 if (!next_token(&seq, issue, NULL, sizeof(issue)))
307 fstrcpy(issue, ".");
309 pwd_sub(issue);
311 if (!strequal(issue, ".")) {
312 /* we have one final issue to send */
313 fstrcpy(expected, ".");
314 if (!expect(master, issue, expected))
315 return False;
318 return (count > 0);
321 static BOOL chat_with_program(char *passwordprogram, char *name,
322 char *chatsequence, BOOL as_root)
324 char *slavedev;
325 int master;
326 pid_t pid, wpid;
327 int wstat;
328 BOOL chstat = False;
330 /* allocate a pseudo-terminal device */
331 if ((master = findpty(&slavedev)) < 0)
333 DEBUG(3,
334 ("Cannot Allocate pty for password change: %s\n",
335 name));
336 return (False);
340 * We need to temporarily stop CatchChild from eating
341 * SIGCLD signals as it also eats the exit status code. JRA.
344 CatchChildLeaveStatus();
346 if ((pid = sys_fork()) < 0)
348 DEBUG(3,
349 ("Cannot fork() child for password change: %s\n",
350 name));
351 close(master);
352 CatchChild();
353 return (False);
356 /* we now have a pty */
357 if (pid > 0)
358 { /* This is the parent process */
359 if ((chstat = talktochild(master, chatsequence)) == False)
361 DEBUG(3,
362 ("Child failed to change password: %s\n",
363 name));
364 kill(pid, SIGKILL); /* be sure to end this process */
367 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
369 if (errno == EINTR)
371 errno = 0;
372 continue;
374 break;
377 if (wpid < 0)
379 DEBUG(3, ("The process is no longer waiting!\n\n"));
380 close(master);
381 CatchChild();
382 return (False);
386 * Go back to ignoring children.
388 CatchChild();
390 close(master);
392 if (pid != wpid)
394 DEBUG(3,
395 ("We were waiting for the wrong process ID\n"));
396 return (False);
398 if (WIFEXITED(wstat) == 0)
400 DEBUG(3,
401 ("The process exited while we were waiting\n"));
402 return (False);
404 if (WEXITSTATUS(wstat) != 0)
406 DEBUG(3,
407 ("The status of the process exiting was %d\n",
408 wstat));
409 return (False);
413 else
415 /* CHILD */
418 * Lose any oplock capabilities.
420 oplock_set_capability(False, False);
422 /* make sure it doesn't freeze */
423 alarm(20);
425 if (as_root)
426 become_root();
428 DEBUG(3,
429 ("Dochild for user %s (uid=%d,gid=%d)\n", name,
430 (int)getuid(), (int)getgid()));
431 chstat =
432 dochild(master, slavedev, name, passwordprogram,
433 as_root);
435 if (as_root)
436 unbecome_root();
439 * The child should never return from dochild() ....
442 DEBUG(0,
443 ("chat_with_program: Error: dochild() returned %d\n",
444 chstat));
445 exit(1);
448 if (chstat)
449 DEBUG(3,
450 ("Password change %ssuccessful for user %s\n",
451 (chstat ? "" : "un"), name));
452 return (chstat);
456 BOOL chgpasswd(char *name, const char *oldpass, const char *newpass, BOOL as_root)
458 pstring passwordprogram;
459 pstring chatsequence;
460 size_t i;
461 size_t len;
463 strlower(name);
464 DEBUG(3, ("Password change for user: %s\n", name));
466 #if DEBUG_PASSWORD
467 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
468 #endif
470 /* Take the passed information and test it for minimum criteria */
471 /* Minimum password length */
472 if (strlen(newpass) < lp_min_passwd_length()) {
473 /* too short, must be at least MINPASSWDLENGTH */
474 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
475 name, lp_min_passwd_length()));
476 return (False); /* inform the user */
479 /* Password is same as old password */
480 if (strcmp(oldpass, newpass) == 0) {
481 /* don't allow same password */
482 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
483 return (False); /* inform the user */
487 * Check the old and new passwords don't contain any control
488 * characters.
491 len = strlen(oldpass);
492 for (i = 0; i < len; i++) {
493 if (iscntrl((int)oldpass[i])) {
494 DEBUG(0,
495 ("chat_with_program: oldpass contains control characters (disallowed).\n"));
496 return False;
500 len = strlen(newpass);
501 for (i = 0; i < len; i++) {
502 if (iscntrl((int)newpass[i])) {
503 DEBUG(0,
504 ("chat_with_program: newpass contains control characters (disallowed).\n"));
505 return False;
509 #ifdef WITH_PAM
510 if (lp_pam_password_change()) {
511 BOOL ret;
513 if (as_root)
514 become_root();
516 ret = smb_pam_passchange(name, oldpass, newpass);
518 if (as_root)
519 unbecome_root();
521 return ret;
523 #endif
525 pstrcpy(passwordprogram, lp_passwd_program());
526 pstrcpy(chatsequence, lp_passwd_chat());
528 if (!*chatsequence) {
529 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
530 return (False);
533 if (!*passwordprogram) {
534 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
535 return (False);
538 if (as_root) {
539 /* The password program *must* contain the user name to work. Fail if not. */
540 if (strstr(passwordprogram, "%u") == NULL) {
541 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
542 the string %%u, and the given string %s does not.\n", passwordprogram ));
543 return False;
547 pstring_sub(passwordprogram, "%u", name);
548 /* note that we do NOT substitute the %o and %n in the password program
549 as this would open up a security hole where the user could use
550 a new password containing shell escape characters */
552 pstring_sub(chatsequence, "%u", name);
553 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
554 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
555 return (chat_with_program
556 (passwordprogram, name, chatsequence, as_root));
559 #else /* ALLOW_CHANGE_PASSWORD */
561 BOOL chgpasswd(char *name, const char *oldpass, const char *newpass, BOOL as_root)
563 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
564 return (False);
566 #endif /* ALLOW_CHANGE_PASSWORD */
568 /***********************************************************
569 Code to check the lanman hashed password.
570 ************************************************************/
572 BOOL check_lanman_password(char *user, uchar * pass1,
573 uchar * pass2, SAM_ACCOUNT **hnd)
575 static uchar null_pw[16];
576 uchar unenc_new_pw[16];
577 uchar unenc_old_pw[16];
578 SAM_ACCOUNT *sampass = NULL;
579 uint16 acct_ctrl;
580 uint8 *lanman_pw;
581 BOOL ret;
583 become_root();
584 ret = pdb_getsampwnam(sampass, user);
585 unbecome_root();
587 if (ret == False) {
588 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
589 pdb_free_sam(sampass);
590 return False;
593 acct_ctrl = pdb_get_acct_ctrl (sampass);
594 lanman_pw = pdb_get_lanman_passwd (sampass);
596 if (acct_ctrl & ACB_DISABLED) {
597 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
598 pdb_free_sam(sampass);
599 return False;
602 if ((lanman_pw == NULL) && (acct_ctrl & ACB_PWNOTREQ)) {
603 uchar no_pw[14];
604 memset(no_pw, '\0', 14);
605 E_P16(no_pw, null_pw);
606 if (!pdb_set_lanman_passwd(sampass, null_pw)) {
607 pdb_free_sam(sampass);
608 return False;
611 else if (lanman_pw == NULL) {
612 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
613 pdb_free_sam(sampass);
614 return False;
617 /* Get the new lanman hash. */
618 D_P16(lanman_pw, pass2, unenc_new_pw);
620 /* Use this to get the old lanman hash. */
621 D_P16(unenc_new_pw, pass1, unenc_old_pw);
623 /* Check that the two old passwords match. */
624 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
625 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
626 pdb_free_sam(sampass);
627 return False;
630 /* this saves the pointer for the caller */
631 *hnd = sampass;
633 return True;
636 /***********************************************************
637 Code to change the lanman hashed password.
638 It nulls out the NT hashed password as it will
639 no longer be valid.
640 ************************************************************/
642 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar * pass1,
643 uchar * pass2)
645 static uchar null_pw[16];
646 uchar unenc_new_pw[16];
647 BOOL ret;
648 uint16 acct_ctrl;
649 uint8 *pwd;
651 if (sampass == NULL) {
652 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
653 return False;
656 acct_ctrl = pdb_get_acct_ctrl(sampass);
657 pwd = pdb_get_lanman_passwd(sampass);
659 if (acct_ctrl & ACB_DISABLED) {
660 DEBUG(0,("change_lanman_password: account %s disabled.\n",
661 pdb_get_username(sampass)));
662 return False;
665 if ((pwd == NULL) && (acct_ctrl & ACB_PWNOTREQ)) {
666 uchar no_pw[14];
667 memset(no_pw, '\0', 14);
668 E_P16(no_pw, null_pw);
669 if (!pdb_set_lanman_passwd(sampass, null_pw))
670 return False;
672 else if (pwd == NULL) {
673 DEBUG(0,("change_lanman_password: no lanman password !\n"));
674 return False;
677 /* Get the new lanman hash. */
678 D_P16(pwd, pass2, unenc_new_pw);
680 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw))
681 return False;
682 pdb_set_nt_passwd (sampass, NULL); /* We lose the NT hash. Sorry. */
684 /* Now flush the sam_passwd struct to persistent storage */
685 become_root();
686 ret = pdb_update_sam_account (sampass, False);
687 unbecome_root();
689 return ret;
692 /***********************************************************
693 Code to check and change the OEM hashed password.
694 ************************************************************/
695 BOOL pass_oem_change(char *user,
696 uchar * lmdata, uchar * lmhash,
697 uchar * ntdata, uchar * nthash)
699 fstring new_passwd;
700 SAM_ACCOUNT *sampass = NULL;
701 BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
702 &sampass, new_passwd, sizeof(new_passwd));
705 * At this point we have the new case-sensitive plaintext
706 * password in the fstring new_passwd. If we wanted to synchronise
707 * with UNIX passwords we would call a UNIX password changing
708 * function here. However it would have to be done as root
709 * as the plaintext of the old users password is not
710 * available. JRA.
713 if (ret && lp_unix_password_sync())
714 ret = chgpasswd(user, "", new_passwd, True);
716 if (ret)
717 ret = change_oem_password(sampass, new_passwd, False);
719 memset(new_passwd, 0, sizeof(new_passwd));
721 pdb_free_sam(sampass);
723 return ret;
726 /***********************************************************
727 Code to check the OEM hashed password.
729 this function ignores the 516 byte nt OEM hashed password
730 but does use the lm OEM password to check the nt hashed-hash.
732 ************************************************************/
734 BOOL check_oem_password(char *user,
735 uchar * lmdata, uchar * lmhash,
736 uchar * ntdata, uchar * nthash,
737 SAM_ACCOUNT **hnd, char *new_passwd,
738 int new_passwd_size)
740 static uchar null_pw[16];
741 static uchar null_ntpw[16];
742 SAM_ACCOUNT *sampass = NULL;
743 uint8 *lanman_pw, *nt_pw;
744 uint16 acct_ctrl;
745 int new_pw_len;
746 uchar new_ntp16[16];
747 uchar unenc_old_ntpw[16];
748 uchar new_p16[16];
749 uchar unenc_old_pw[16];
750 char no_pw[2];
751 BOOL ret;
753 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
755 *hnd = NULL;
757 pdb_init_sam(&sampass);
759 become_root();
760 ret = pdb_getsampwnam(sampass, user);
761 unbecome_root();
763 if (ret == False) {
764 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
765 pdb_free_sam(sampass);
766 return False;
769 acct_ctrl = pdb_get_acct_ctrl(sampass);
771 if (acct_ctrl & ACB_DISABLED) {
772 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
773 pdb_free_sam(sampass);
774 return False;
777 /* construct a null password (in case one is needed */
778 no_pw[0] = 0;
779 no_pw[1] = 0;
780 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
782 /* save pointers to passwords so we don't have to keep looking them up */
783 lanman_pw = pdb_get_lanman_passwd(sampass);
784 nt_pw = pdb_get_nt_passwd(sampass);
786 /* check for null passwords */
787 if (lanman_pw == NULL) {
788 if (acct_ctrl & ACB_PWNOTREQ) {
789 if (!pdb_set_lanman_passwd(sampass, null_pw)) {
790 pdb_free_sam(sampass);
791 return False;
793 lanman_pw = pdb_get_lanman_passwd(sampass);
794 if (!lanman_pw) {
795 pdb_free_sam(sampass);
796 return False;
798 } else {
799 DEBUG(0,("check_oem_password: no lanman password !\n"));
800 pdb_free_sam(sampass);
801 return False;
805 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
806 if (acct_ctrl & ACB_PWNOTREQ) {
807 pdb_set_nt_passwd(sampass, null_ntpw);
808 nt_pw = pdb_get_nt_passwd(sampass);
809 if (!nt_pw) {
810 pdb_free_sam(sampass);
811 return False;
813 } else {
814 DEBUG(0,("check_oem_password: no ntlm password !\n"));
815 pdb_free_sam(sampass);
816 return False;
821 * Call the hash function to get the new password.
823 SamOEMhash((uchar *) lmdata, (uchar *)lanman_pw, 516);
826 * The length of the new password is in the last 4 bytes of
827 * the data buffer.
830 new_pw_len = IVAL(lmdata, 512);
831 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
832 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
833 pdb_free_sam(sampass);
834 return False;
837 if (nt_pass_set) {
839 * nt passwords are in unicode
841 int uni_pw_len = new_pw_len;
842 char *pw;
843 new_pw_len /= 2;
844 pw = dos_unistrn2((uint16 *)(&lmdata[512 - uni_pw_len]), new_pw_len);
845 memcpy(new_passwd, pw, new_pw_len + 1);
846 } else {
847 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
848 new_passwd[new_pw_len] = 0;
852 * To ensure we got the correct new password, hash it and
853 * use it as a key to test the passed old password.
856 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
858 if (!nt_pass_set) {
860 * Now use new_p16 as the key to see if the old
861 * password matches.
863 D_P16(new_p16, lmhash, unenc_old_pw);
865 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
866 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
867 pdb_free_sam(sampass);
868 return False;
871 #ifdef DEBUG_PASSWORD
872 DEBUG(100,
873 ("check_oem_password: password %s ok\n", new_passwd));
874 #endif
875 *hnd = sampass;
876 return True;
880 * Now use new_p16 as the key to see if the old
881 * password matches.
883 D_P16(new_ntp16, lmhash, unenc_old_pw);
884 D_P16(new_ntp16, nthash, unenc_old_ntpw);
886 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
887 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
888 pdb_free_sam(sampass);
889 return False;
892 if (memcmp(nt_pw, unenc_old_ntpw, 16)) {
893 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
894 pdb_free_sam(sampass);
895 return False;
897 #ifdef DEBUG_PASSWORD
898 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
899 #endif
900 *hnd = sampass;
901 return True;
904 /***********************************************************
905 Code to change the oem password. Changes both the lanman
906 and NT hashes.
907 override = False, normal
908 override = True, override XXXXXXXXXX'd password
909 ************************************************************/
911 BOOL change_oem_password(SAM_ACCOUNT *hnd, char *new_passwd,
912 BOOL override)
914 BOOL ret;
915 uchar new_nt_p16[16];
916 uchar new_p16[16];
918 nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
920 if (!pdb_set_lanman_passwd (hnd, new_p16))
921 return False;
922 if (!pdb_set_nt_passwd(hnd, new_nt_p16))
923 return False;
925 /* Now write it into the file. */
926 become_root();
927 ret = pdb_update_sam_account (hnd, override);
928 unbecome_root();
930 memset(new_passwd, '\0', strlen(new_passwd));
932 return ret;
935 /***********************************************************
936 Code to check a plaintext password against smbpasswd entries.
937 ***********************************************************/
939 BOOL check_plaintext_password(char *user, char *old_passwd,
940 int old_passwd_size, SAM_ACCOUNT **hnd)
942 SAM_ACCOUNT *sampass = NULL;
943 uchar old_pw[16], old_ntpw[16];
944 BOOL ret;
946 *hnd = NULL;
948 pdb_init_sam(&sampass);
950 become_root();
951 ret = pdb_getsampwnam(sampass, user);
952 unbecome_root();
954 if (ret == False) {
955 DEBUG(0,("check_plaintext_password: getsmbpwnam returned NULL\n"));
956 pdb_free_sam(sampass);
957 return False;
960 if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
961 DEBUG(0,("check_plaintext_password: account %s disabled.\n", user));
962 pdb_free_sam(sampass);
963 return (False);
966 nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
968 #ifdef DEBUG_PASSWORD
969 DEBUG(100, ("check_plaintext_password: nt_passwd \n"));
970 dump_data(100, pdb_get_nt_passwd(sampass), 16);
971 DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
972 dump_data(100, old_ntpw, 16);
973 DEBUG(100, ("check_plaintext_password: lanman_passwd \n"));
974 dump_data(100, pdb_get_lanman_passwd(sampass), 16);
975 DEBUG(100, ("check_plaintext_password: old_pw\n"));
976 dump_data(100, old_pw, 16);
977 #endif
979 if (memcmp(pdb_get_nt_passwd(sampass), old_ntpw, 16)
980 && memcmp(pdb_get_lanman_passwd(sampass), old_pw, 16)) {
981 pdb_free_sam(sampass);
982 return (False);
983 } else {
984 *hnd = sampass;
985 return (True);