ReadDirName calls vfs->readdirname calls dos_readdirname.
[ira/wip.git] / source3 / smbd / chgpasswd.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba utility functions
5    Copyright (C) Andrew Tridgell 1992-1998
6    
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.
11    
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.
16    
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.
20 */
21
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.
25 */
26
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.
32  *
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.
35  *
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.
40  */
41
42 /*
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.
48    */
49
50 #include "includes.h"
51
52 extern int DEBUGLEVEL;
53
54 #if ALLOW_CHANGE_PASSWORD
55
56 static int findpty(char **slave)
57 {
58         int master;
59         static fstring line;
60         DIR *dirp;
61         char *dpname;
62
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)
66         {
67                 grantpt(master);
68                 unlockpt(master);
69                 *slave = (char *)ptsname(master);
70                 if (*slave == NULL)
71                 {
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;
77                 }
78                 else
79                 {
80                         DEBUG(10,
81                               ("findpty: Allocated slave pty %s\n", *slave));
82                         return (master);
83                 }
84         }
85 #endif /* HAVE_GRANTPT */
86
87         fstrcpy(line, "/dev/ptyXX");
88
89         dirp = opendir("/dev");
90         if (!dirp)
91                 return (-1);
92         while ((dpname = readdirname(dirp)) != NULL)
93         {
94                 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
95                 {
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)
102                         {
103                                 DEBUG(3, ("pty: opened %s\n", line));
104                                 line[5] = 't';
105                                 *slave = line;
106                                 closedir(dirp);
107                                 return (master);
108                         }
109                 }
110         }
111         closedir(dirp);
112         return (-1);
113 }
114
115 static int dochild(int master, char *slavedev, char *name,
116                    char *passwordprogram, BOOL as_root)
117 {
118         int slave;
119         struct termios stermios;
120         struct passwd *pass = Get_Pwnam(name, True);
121         gid_t gid;
122         uid_t uid;
123
124         if (pass == NULL)
125         {
126                 DEBUG(0,
127                       ("dochild: user name %s doesn't exist in the UNIX password database.\n",
128                        name));
129                 return False;
130         }
131
132         gid = pass->pw_gid;
133         uid = pass->pw_uid;
134
135         gain_root_privilege();
136
137         /* Start new session - gets rid of controlling terminal. */
138         if (setsid() < 0)
139         {
140                 DEBUG(3,
141                       ("Weirdness, couldn't let go of controlling terminal\n"));
142                 return (False);
143         }
144
145         /* Open slave pty and acquire as new controlling terminal. */
146         if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
147         {
148                 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
149                 return (False);
150         }
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)
156         {
157                 DEBUG(3, ("Error in ioctl call for slave pty\n"));
158                 /* return(False); */
159         }
160 #endif
161
162         /* Close master. */
163         close(master);
164
165         /* Make slave stdin/out/err of child. */
166
167         if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
168         {
169                 DEBUG(3, ("Could not re-direct stdin\n"));
170                 return (False);
171         }
172         if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
173         {
174                 DEBUG(3, ("Could not re-direct stdout\n"));
175                 return (False);
176         }
177         if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
178         {
179                 DEBUG(3, ("Could not re-direct stderr\n"));
180                 return (False);
181         }
182         if (slave > 2)
183                 close(slave);
184
185         /* Set proper terminal attributes - no echo, canonical input processing,
186            no map NL to CR/NL on output. */
187
188         if (tcgetattr(0, &stermios) < 0)
189         {
190                 DEBUG(3,
191                       ("could not read default terminal attributes on pty\n"));
192                 return (False);
193         }
194         stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
195         stermios.c_lflag |= ICANON;
196         stermios.c_oflag &= ~(ONLCR);
197         if (tcsetattr(0, TCSANOW, &stermios) < 0)
198         {
199                 DEBUG(3, ("could not set attributes of pty\n"));
200                 return (False);
201         }
202
203         /* make us completely into the right uid */
204         if (!as_root)
205         {
206                 become_user_permanently(uid, gid);
207         }
208
209         DEBUG(10,
210               ("Invoking '%s' as password change program.\n",
211                passwordprogram));
212
213         /* execl() password-change application */
214         if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
215         {
216                 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
217                 return (False);
218         }
219         return (True);
220 }
221
222 static int expect(int master, char *issue, char *expected)
223 {
224         pstring buffer;
225         int attempts, timeout, nread, len;
226         BOOL match = False;
227
228         for (attempts = 0; attempts < 2; attempts++)
229         {
230                 if (!strequal(issue, "."))
231                 {
232                         if (lp_passwd_chat_debug())
233                                 DEBUG(100, ("expect: sending [%s]\n", issue));
234
235                         write(master, issue, strlen(issue));
236                 }
237
238                 if (strequal(expected, "."))
239                         return True;
240
241                 timeout = 2000;
242                 nread = 0;
243                 buffer[nread] = 0;
244
245                 while ((len = read_with_timeout(master, buffer + nread, 1,
246                                                 sizeof(buffer) - nread - 1,
247                                                 timeout)) > 0)
248                 {
249                         nread += len;
250                         buffer[nread] = 0;
251
252                         if ((match = unix_do_match(buffer, expected, False)))
253                                 timeout = 200;
254                 }
255
256                 if (lp_passwd_chat_debug())
257                         DEBUG(100, ("expect: expected [%s] received [%s]\n",
258                                     expected, buffer));
259
260                 if (match)
261                         break;
262
263                 if (len < 0)
264                 {
265                         DEBUG(2, ("expect: %s\n", strerror(errno)));
266                         return False;
267                 }
268         }
269
270         return match;
271 }
272
273 static void pwd_sub(char *buf)
274 {
275         all_string_sub(buf, "\\n", "\n", 0);
276         all_string_sub(buf, "\\r", "\r", 0);
277         all_string_sub(buf, "\\s", " ", 0);
278         all_string_sub(buf, "\\t", "\t", 0);
279 }
280
281 static int talktochild(int master, char *seq)
282 {
283         int count = 0;
284         fstring issue, expected;
285
286         fstrcpy(issue, ".");
287
288         while (next_token(&seq, expected, NULL, sizeof(expected)))
289         {
290                 pwd_sub(expected);
291                 count++;
292
293                 if (!expect(master, issue, expected))
294                 {
295                         DEBUG(3, ("Response %d incorrect\n", count));
296                         return False;
297                 }
298
299                 if (!next_token(&seq, issue, NULL, sizeof(issue)))
300                         fstrcpy(issue, ".");
301
302                 pwd_sub(issue);
303         }
304
305         return (count > 0);
306 }
307
308 static BOOL chat_with_program(char *passwordprogram, char *name,
309                               char *chatsequence, BOOL as_root)
310 {
311         char *slavedev;
312         int master;
313         pid_t pid, wpid;
314         int wstat;
315         BOOL chstat = False;
316
317         /* allocate a pseudo-terminal device */
318         if ((master = findpty(&slavedev)) < 0)
319         {
320                 DEBUG(3,
321                       ("Cannot Allocate pty for password change: %s\n",
322                        name));
323                 return (False);
324         }
325
326         /*
327          * We need to temporarily stop CatchChild from eating
328          * SIGCLD signals as it also eats the exit status code. JRA.
329          */
330
331         CatchChildLeaveStatus();
332
333         if ((pid = fork()) < 0)
334         {
335                 DEBUG(3,
336                       ("Cannot fork() child for password change: %s\n",
337                        name));
338                 close(master);
339                 CatchChild();
340                 return (False);
341         }
342
343         /* we now have a pty */
344         if (pid > 0)
345         {                       /* This is the parent process */
346                 if ((chstat = talktochild(master, chatsequence)) == False)
347                 {
348                         DEBUG(3,
349                               ("Child failed to change password: %s\n",
350                                name));
351                         kill(pid, SIGKILL);     /* be sure to end this process */
352                 }
353
354                 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0)
355                 {
356                         if (errno == EINTR)
357                         {
358                                 errno = 0;
359                                 continue;
360                         }
361                         break;
362                 }
363
364                 if (wpid < 0)
365                 {
366                         DEBUG(3, ("The process is no longer waiting!\n\n"));
367                         close(master);
368                         CatchChild();
369                         return (False);
370                 }
371
372                 /*
373                  * Go back to ignoring children.
374                  */
375                 CatchChild();
376
377                 close(master);
378
379                 if (pid != wpid)
380                 {
381                         DEBUG(3,
382                               ("We were waiting for the wrong process ID\n"));
383                         return (False);
384                 }
385                 if (WIFEXITED(wstat) == 0)
386                 {
387                         DEBUG(3,
388                               ("The process exited while we were waiting\n"));
389                         return (False);
390                 }
391                 if (WEXITSTATUS(wstat) != 0)
392                 {
393                         DEBUG(3,
394                               ("The status of the process exiting was %d\n",
395                                wstat));
396                         return (False);
397                 }
398
399         }
400         else
401         {
402                 /* CHILD */
403
404                 /*
405                  * Lose any oplock capabilities.
406                  */
407                 set_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
408                 set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY,
409                                                  False);
410
411                 /* make sure it doesn't freeze */
412                 alarm(20);
413
414                 if (as_root)
415                         become_root(False);
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);
422
423                 /*
424                  * The child should never return from dochild() ....
425                  */
426
427                 DEBUG(0,
428                       ("chat_with_program: Error: dochild() returned %d\n",
429                        chstat));
430                 exit(1);
431         }
432
433         if (chstat)
434                 DEBUG(3,
435                       ("Password change %ssuccessful for user %s\n",
436                        (chstat ? "" : "un"), name));
437         return (chstat);
438 }
439
440
441 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
442 {
443         pstring passwordprogram;
444         pstring chatsequence;
445         size_t i;
446         size_t len;
447
448         strlower(name);
449         DEBUG(3, ("Password change for user: %s\n", name));
450
451 #if DEBUG_PASSWORD
452         DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
453 #endif
454
455         /* Take the passed information and test it for minimum criteria */
456         /* Minimum password length */
457         if (strlen(newpass) < lp_min_passwd_length())   /* too short, must be at least MINPASSWDLENGTH */
458         {
459                 DEBUG(0,
460                       ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
461                        name, lp_min_passwd_length()));
462                 return (False); /* inform the user */
463         }
464
465         /* Password is same as old password */
466         if (strcmp(oldpass, newpass) == 0)      /* don't allow same password */
467         {
468                 DEBUG(2,
469                       ("Password Change: %s, New password is same as old\n", name));    /* log the attempt */
470                 return (False); /* inform the user */
471         }
472
473         pstrcpy(passwordprogram, lp_passwd_program());
474         pstrcpy(chatsequence, lp_passwd_chat());
475
476         if (!*chatsequence)
477         {
478                 DEBUG(2, ("Null chat sequence - no password changing\n"));
479                 return (False);
480         }
481
482         if (!*passwordprogram)
483         {
484                 DEBUG(2, ("Null password program - no password changing\n"));
485                 return (False);
486         }
487
488         /* 
489          * Check the old and new passwords don't contain any control
490          * characters.
491          */
492
493         len = strlen(oldpass);
494         for (i = 0; i < len; i++)
495         {
496                 if (iscntrl((int)oldpass[i]))
497                 {
498                         DEBUG(0,
499                               ("chat_with_program: oldpass contains control characters (disallowed).\n"));
500                         return False;
501                 }
502         }
503
504         len = strlen(newpass);
505         for (i = 0; i < len; i++)
506         {
507                 if (iscntrl((int)newpass[i]))
508                 {
509                         DEBUG(0,
510                               ("chat_with_program: newpass contains control characters (disallowed).\n"));
511                         return False;
512                 }
513         }
514
515         pstring_sub(passwordprogram, "%u", name);
516         /* note that we do NOT substitute the %o and %n in the password program
517            as this would open up a security hole where the user could use
518            a new password containing shell escape characters */
519
520         pstring_sub(chatsequence, "%u", name);
521         all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
522         all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
523         return (chat_with_program
524                 (passwordprogram, name, chatsequence, as_root));
525 }
526
527 #else /* ALLOW_CHANGE_PASSWORD */
528 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
529 {
530         DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
531         return (False);
532 }
533 #endif /* ALLOW_CHANGE_PASSWORD */
534
535 /***********************************************************
536  Code to check the lanman hashed password.
537 ************************************************************/
538
539 BOOL check_lanman_password(char *user, uchar * pass1,
540                            uchar * pass2, struct smb_passwd **psmbpw)
541 {
542         static uchar null_pw[16];
543         uchar unenc_new_pw[16];
544         uchar unenc_old_pw[16];
545         struct smb_passwd *smbpw;
546
547         *psmbpw = NULL;
548
549         become_root(0);
550         smbpw = getsmbpwnam(user);
551         unbecome_root(0);
552
553         if (smbpw == NULL)
554         {
555                 DEBUG(0,
556                       ("check_lanman_password: getsmbpwnam returned NULL\n"));
557                 return False;
558         }
559
560         if (smbpw->acct_ctrl & ACB_DISABLED)
561         {
562                 DEBUG(0,
563                       ("check_lanman_password: account %s disabled.\n",
564                        user));
565                 return False;
566         }
567
568         if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
569         {
570                 uchar no_pw[14];
571                 memset(no_pw, '\0', 14);
572                 E_P16(no_pw, null_pw);
573                 smbpw->smb_passwd = null_pw;
574         }
575         else if (smbpw->smb_passwd == NULL)
576         {
577                 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
578                 return False;
579         }
580
581         /* Get the new lanman hash. */
582         D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
583
584         /* Use this to get the old lanman hash. */
585         D_P16(unenc_new_pw, pass1, unenc_old_pw);
586
587         /* Check that the two old passwords match. */
588         if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
589         {
590                 DEBUG(0,
591                       ("check_lanman_password: old password doesn't match.\n"));
592                 return False;
593         }
594
595         *psmbpw = smbpw;
596         return True;
597 }
598
599 /***********************************************************
600  Code to change the lanman hashed password.
601  It nulls out the NT hashed password as it will
602  no longer be valid.
603 ************************************************************/
604
605 BOOL change_lanman_password(struct smb_passwd *smbpw, uchar * pass1,
606                             uchar * pass2)
607 {
608         static uchar null_pw[16];
609         uchar unenc_new_pw[16];
610         BOOL ret;
611
612         if (smbpw == NULL)
613         {
614                 DEBUG(0,
615                       ("change_lanman_password: no smb password entry.\n"));
616                 return False;
617         }
618
619         if (smbpw->acct_ctrl & ACB_DISABLED)
620         {
621                 DEBUG(0,
622                       ("change_lanman_password: account %s disabled.\n",
623                        smbpw->smb_name));
624                 return False;
625         }
626
627         if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
628         {
629                 uchar no_pw[14];
630                 memset(no_pw, '\0', 14);
631                 E_P16(no_pw, null_pw);
632                 smbpw->smb_passwd = null_pw;
633         }
634         else if (smbpw->smb_passwd == NULL)
635         {
636                 DEBUG(0, ("change_lanman_password: no lanman password !\n"));
637                 return False;
638         }
639
640         /* Get the new lanman hash. */
641         D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
642
643         smbpw->smb_passwd = unenc_new_pw;
644         smbpw->smb_nt_passwd = NULL;    /* We lose the NT hash. Sorry. */
645
646         /* Now write it into the file. */
647         become_root(0);
648         ret = mod_smbpwd_entry(smbpw, False);
649         unbecome_root(0);
650
651         return ret;
652 }
653
654 /***********************************************************
655  Code to check and change the OEM hashed password.
656 ************************************************************/
657 BOOL pass_oem_change(char *user,
658                      uchar * lmdata, uchar * lmhash,
659                      uchar * ntdata, uchar * nthash)
660 {
661         fstring new_passwd;
662         struct smb_passwd *sampw;
663         BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
664                                       &sampw,
665                                       new_passwd, sizeof(new_passwd));
666
667         /* 
668          * At this point we have the new case-sensitive plaintext
669          * password in the fstring new_passwd. If we wanted to synchronise
670          * with UNIX passwords we would call a UNIX password changing 
671          * function here. However it would have to be done as root
672          * as the plaintext of the old users password is not 
673          * available. JRA.
674          */
675
676         if (ret && lp_unix_password_sync())
677         {
678                 ret = chgpasswd(user, "", new_passwd, True);
679         }
680
681         if (ret)
682         {
683                 ret = change_oem_password(sampw, new_passwd, False);
684         }
685
686         memset(new_passwd, 0, sizeof(new_passwd));
687
688         return ret;
689 }
690
691 /***********************************************************
692  Code to check the OEM hashed password.
693
694  this function ignores the 516 byte nt OEM hashed password
695  but does use the lm OEM password to check the nt hashed-hash.
696
697 ************************************************************/
698 BOOL check_oem_password(char *user,
699                         uchar * lmdata, uchar * lmhash,
700                         uchar * ntdata, uchar * nthash,
701                         struct smb_passwd **psmbpw, char *new_passwd,
702                         int new_passwd_size)
703 {
704         static uchar null_pw[16];
705         static uchar null_ntpw[16];
706         struct smb_passwd *smbpw = NULL;
707         int new_pw_len;
708         uchar new_ntp16[16];
709         uchar unenc_old_ntpw[16];
710         uchar new_p16[16];
711         uchar unenc_old_pw[16];
712         char no_pw[2];
713
714         BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
715
716         become_root(False);
717         *psmbpw = smbpw = getsmbpwnam(user);
718         unbecome_root(False);
719
720         if (smbpw == NULL)
721         {
722                 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
723                 return False;
724         }
725
726         if (smbpw->acct_ctrl & ACB_DISABLED)
727         {
728                 DEBUG(0,
729                       ("check_lanman_password: account %s disabled.\n",
730                        user));
731                 return False;
732         }
733
734         /* construct a null password (in case one is needed */
735         no_pw[0] = 0;
736         no_pw[1] = 0;
737         nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
738
739         /* check for null passwords */
740         if (smbpw->smb_passwd == NULL)
741         {
742                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
743                 {
744                         smbpw->smb_passwd = null_pw;
745                 }
746                 else
747                 {
748                         DEBUG(0,
749                               ("check_oem_password: no lanman password !\n"));
750                         return False;
751                 }
752         }
753
754         if (smbpw->smb_nt_passwd == NULL && nt_pass_set)
755         {
756                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
757                 {
758                         smbpw->smb_nt_passwd = null_pw;
759                 }
760                 else
761                 {
762                         DEBUG(0,
763                               ("check_oem_password: no ntlm password !\n"));
764                         return False;
765                 }
766         }
767
768         /* 
769          * Call the hash function to get the new password.
770          */
771         SamOEMhash((uchar *) lmdata, (uchar *) smbpw->smb_passwd, True);
772
773         /* 
774          * The length of the new password is in the last 4 bytes of
775          * the data buffer.
776          */
777
778         new_pw_len = IVAL(lmdata, 512);
779         if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1)
780         {
781                 DEBUG(0,
782                       ("check_oem_password: incorrect password length (%d).\n",
783                        new_pw_len));
784                 return False;
785         }
786
787         if (nt_pass_set)
788         {
789                 /*
790                  * nt passwords are in unicode
791                  */
792                 int uni_pw_len = new_pw_len;
793                 char *pw;
794                 new_pw_len /= 2;
795                 pw =
796                         dos_unistrn2((uint16 *)(&lmdata[512 - uni_pw_len]),
797                                      new_pw_len);
798                 memcpy(new_passwd, pw, new_pw_len + 1);
799         }
800         else
801         {
802                 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
803                 new_passwd[new_pw_len] = '\0';
804         }
805
806         /*
807          * To ensure we got the correct new password, hash it and
808          * use it as a key to test the passed old password.
809          */
810
811         nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
812
813         if (!nt_pass_set)
814         {
815                 /*
816                  * Now use new_p16 as the key to see if the old
817                  * password matches.
818                  */
819                 D_P16(new_p16, lmhash, unenc_old_pw);
820
821                 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
822                 {
823                         DEBUG(0,
824                               ("check_oem_password: old lm password doesn't match.\n"));
825                         return False;
826                 }
827
828 #ifdef DEBUG_PASSWORD
829                 DEBUG(100,
830                       ("check_oem_password: password %s ok\n", new_passwd));
831 #endif
832                 return True;
833         }
834
835         /*
836          * Now use new_p16 as the key to see if the old
837          * password matches.
838          */
839         D_P16(new_ntp16, lmhash, unenc_old_pw);
840         D_P16(new_ntp16, nthash, unenc_old_ntpw);
841
842         if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
843         {
844                 DEBUG(0,
845                       ("check_oem_password: old lm password doesn't match.\n"));
846                 return False;
847         }
848
849         if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16))
850         {
851                 DEBUG(0,
852                       ("check_oem_password: old nt password doesn't match.\n"));
853                 return False;
854         }
855 #ifdef DEBUG_PASSWORD
856         DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
857 #endif
858         return True;
859 }
860
861 /***********************************************************
862  Code to change the oem password. Changes both the lanman
863  and NT hashes.
864  override = False, normal
865  override = True, override XXXXXXXXXX'd password
866 ************************************************************/
867
868 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd,
869                          BOOL override)
870 {
871         int ret;
872         uchar new_nt_p16[16];
873         uchar new_p16[16];
874
875         nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
876
877         smbpw->smb_passwd = new_p16;
878         smbpw->smb_nt_passwd = new_nt_p16;
879
880         /* Now write it into the file. */
881         become_root(0);
882         ret = mod_smbpwd_entry(smbpw, override);
883         unbecome_root(0);
884
885         memset(new_passwd, '\0', strlen(new_passwd));
886
887         return ret;
888 }
889
890 /***********************************************************
891  Code to check a plaintext password against smbpasswd entries.
892 ***********************************************************/
893
894 BOOL check_plaintext_password(char *user, char *old_passwd,
895                               int old_passwd_size, struct smb_passwd **psmbpw)
896 {
897         struct smb_passwd *smbpw = NULL;
898         uchar old_pw[16], old_ntpw[16];
899
900         become_root(False);
901         *psmbpw = smbpw = getsmbpwnam(user);
902         unbecome_root(False);
903
904         if (smbpw == NULL)
905         {
906                 DEBUG(0,
907                       ("check_plaintext_password: getsmbpwnam returned NULL\n"));
908                 return False;
909         }
910
911         if (smbpw->acct_ctrl & ACB_DISABLED)
912         {
913                 DEBUG(0,
914                       ("check_plaintext_password: account %s disabled.\n",
915                        user));
916                 return (False);
917         }
918
919         nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
920
921 #ifdef DEBUG_PASSWORD
922         DEBUG(100, ("check_plaintext_password: smbpw->smb_nt_passwd \n"));
923         dump_data(100, smbpw->smb_nt_passwd, 16);
924         DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
925         dump_data(100, old_ntpw, 16);
926         DEBUG(100, ("check_plaintext_password: smbpw->smb_passwd \n"));
927         dump_data(100, smbpw->smb_passwd, 16);
928         DEBUG(100, ("check_plaintext_password: old_pw\n"));
929         dump_data(100, old_pw, 16);
930 #endif
931
932         if (memcmp(smbpw->smb_nt_passwd, old_ntpw, 16)
933             && memcmp(smbpw->smb_passwd, old_pw, 16))
934                 return (False);
935         else
936                 return (True);
937 }