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