Added John Reilly's enumports/addprinter/delprinter scripting code plus the
[sfrench/samba-autobuild/.git] / source / 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                 oplock_set_capability(False, False);
410
411                 /* make sure it doesn't freeze */
412                 alarm(20);
413
414                 if (as_root)
415                         become_root();
416
417                 DEBUG(3,
418                       ("Dochild for user %s (uid=%d,gid=%d)\n", name,
419                        (int)getuid(), (int)getgid()));
420                 chstat =
421                         dochild(master, slavedev, name, passwordprogram,
422                                 as_root);
423
424                 if (as_root)
425                         unbecome_root();
426
427                 /*
428                  * The child should never return from dochild() ....
429                  */
430
431                 DEBUG(0,
432                       ("chat_with_program: Error: dochild() returned %d\n",
433                        chstat));
434                 exit(1);
435         }
436
437         if (chstat)
438                 DEBUG(3,
439                       ("Password change %ssuccessful for user %s\n",
440                        (chstat ? "" : "un"), name));
441         return (chstat);
442 }
443
444
445 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
446 {
447         pstring passwordprogram;
448         pstring chatsequence;
449         size_t i;
450         size_t len;
451
452         strlower(name);
453         DEBUG(3, ("Password change for user: %s\n", name));
454
455 #if DEBUG_PASSWORD
456         DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
457 #endif
458
459         /* Take the passed information and test it for minimum criteria */
460         /* Minimum password length */
461         if (strlen(newpass) < lp_min_passwd_length())   /* too short, must be at least MINPASSWDLENGTH */
462         {
463                 DEBUG(0,
464                       ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
465                        name, lp_min_passwd_length()));
466                 return (False); /* inform the user */
467         }
468
469         /* Password is same as old password */
470         if (strcmp(oldpass, newpass) == 0)      /* don't allow same password */
471         {
472                 DEBUG(2,
473                       ("Password Change: %s, New password is same as old\n", name));    /* log the attempt */
474                 return (False); /* inform the user */
475         }
476
477         pstrcpy(passwordprogram, lp_passwd_program());
478         pstrcpy(chatsequence, lp_passwd_chat());
479
480         if (!*chatsequence)
481         {
482                 DEBUG(2, ("Null chat sequence - no password changing\n"));
483                 return (False);
484         }
485
486         if (!*passwordprogram)
487         {
488                 DEBUG(2, ("Null password program - no password changing\n"));
489                 return (False);
490         }
491
492         /* 
493          * Check the old and new passwords don't contain any control
494          * characters.
495          */
496
497         len = strlen(oldpass);
498         for (i = 0; i < len; i++)
499         {
500                 if (iscntrl((int)oldpass[i]))
501                 {
502                         DEBUG(0,
503                               ("chat_with_program: oldpass contains control characters (disallowed).\n"));
504                         return False;
505                 }
506         }
507
508         len = strlen(newpass);
509         for (i = 0; i < len; i++)
510         {
511                 if (iscntrl((int)newpass[i]))
512                 {
513                         DEBUG(0,
514                               ("chat_with_program: newpass contains control characters (disallowed).\n"));
515                         return False;
516                 }
517         }
518
519         pstring_sub(passwordprogram, "%u", name);
520         /* note that we do NOT substitute the %o and %n in the password program
521            as this would open up a security hole where the user could use
522            a new password containing shell escape characters */
523
524         pstring_sub(chatsequence, "%u", name);
525         all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
526         all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
527         return (chat_with_program
528                 (passwordprogram, name, chatsequence, as_root));
529 }
530
531 #else /* ALLOW_CHANGE_PASSWORD */
532 BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
533 {
534         DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
535         return (False);
536 }
537 #endif /* ALLOW_CHANGE_PASSWORD */
538
539 /***********************************************************
540  Code to check the lanman hashed password.
541 ************************************************************/
542
543 BOOL check_lanman_password(char *user, uchar * pass1,
544                            uchar * pass2, struct smb_passwd **psmbpw)
545 {
546         static uchar null_pw[16];
547         uchar unenc_new_pw[16];
548         uchar unenc_old_pw[16];
549         struct smb_passwd *smbpw;
550
551         *psmbpw = NULL;
552
553         become_root();
554         smbpw = getsmbpwnam(user);
555         unbecome_root();
556
557         if (smbpw == NULL)
558         {
559                 DEBUG(0,
560                       ("check_lanman_password: getsmbpwnam returned NULL\n"));
561                 return False;
562         }
563
564         if (smbpw->acct_ctrl & ACB_DISABLED)
565         {
566                 DEBUG(0,
567                       ("check_lanman_password: account %s disabled.\n",
568                        user));
569                 return False;
570         }
571
572         if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
573         {
574                 uchar no_pw[14];
575                 memset(no_pw, '\0', 14);
576                 E_P16(no_pw, null_pw);
577                 smbpw->smb_passwd = null_pw;
578         }
579         else if (smbpw->smb_passwd == NULL)
580         {
581                 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
582                 return False;
583         }
584
585         /* Get the new lanman hash. */
586         D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
587
588         /* Use this to get the old lanman hash. */
589         D_P16(unenc_new_pw, pass1, unenc_old_pw);
590
591         /* Check that the two old passwords match. */
592         if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
593         {
594                 DEBUG(0,
595                       ("check_lanman_password: old password doesn't match.\n"));
596                 return False;
597         }
598
599         *psmbpw = smbpw;
600         return True;
601 }
602
603 /***********************************************************
604  Code to change the lanman hashed password.
605  It nulls out the NT hashed password as it will
606  no longer be valid.
607 ************************************************************/
608
609 BOOL change_lanman_password(struct smb_passwd *smbpw, uchar * pass1,
610                             uchar * pass2)
611 {
612         static uchar null_pw[16];
613         uchar unenc_new_pw[16];
614         BOOL ret;
615
616         if (smbpw == NULL)
617         {
618                 DEBUG(0,
619                       ("change_lanman_password: no smb password entry.\n"));
620                 return False;
621         }
622
623         if (smbpw->acct_ctrl & ACB_DISABLED)
624         {
625                 DEBUG(0,
626                       ("change_lanman_password: account %s disabled.\n",
627                        smbpw->smb_name));
628                 return False;
629         }
630
631         if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
632         {
633                 uchar no_pw[14];
634                 memset(no_pw, '\0', 14);
635                 E_P16(no_pw, null_pw);
636                 smbpw->smb_passwd = null_pw;
637         }
638         else if (smbpw->smb_passwd == NULL)
639         {
640                 DEBUG(0, ("change_lanman_password: no lanman password !\n"));
641                 return False;
642         }
643
644         /* Get the new lanman hash. */
645         D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
646
647         smbpw->smb_passwd = unenc_new_pw;
648         smbpw->smb_nt_passwd = NULL;    /* We lose the NT hash. Sorry. */
649
650         /* Now write it into the file. */
651         become_root();
652         ret = mod_smbpwd_entry(smbpw, False);
653         unbecome_root();
654
655         return ret;
656 }
657
658 /***********************************************************
659  Code to check and change the OEM hashed password.
660 ************************************************************/
661 BOOL pass_oem_change(char *user,
662                      uchar * lmdata, uchar * lmhash,
663                      uchar * ntdata, uchar * nthash)
664 {
665         fstring new_passwd;
666         struct smb_passwd *sampw;
667         BOOL ret = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
668                                       &sampw,
669                                       new_passwd, sizeof(new_passwd));
670
671         /* 
672          * At this point we have the new case-sensitive plaintext
673          * password in the fstring new_passwd. If we wanted to synchronise
674          * with UNIX passwords we would call a UNIX password changing 
675          * function here. However it would have to be done as root
676          * as the plaintext of the old users password is not 
677          * available. JRA.
678          */
679
680         if (ret && lp_unix_password_sync())
681         {
682                 ret = chgpasswd(user, "", new_passwd, True);
683         }
684
685         if (ret)
686         {
687                 ret = change_oem_password(sampw, new_passwd, False);
688         }
689
690         memset(new_passwd, 0, sizeof(new_passwd));
691
692         return ret;
693 }
694
695 /***********************************************************
696  Code to check the OEM hashed password.
697
698  this function ignores the 516 byte nt OEM hashed password
699  but does use the lm OEM password to check the nt hashed-hash.
700
701 ************************************************************/
702 BOOL check_oem_password(char *user,
703                         uchar * lmdata, uchar * lmhash,
704                         uchar * ntdata, uchar * nthash,
705                         struct smb_passwd **psmbpw, char *new_passwd,
706                         int new_passwd_size)
707 {
708         static uchar null_pw[16];
709         static uchar null_ntpw[16];
710         struct smb_passwd *smbpw = NULL;
711         int new_pw_len;
712         uchar new_ntp16[16];
713         uchar unenc_old_ntpw[16];
714         uchar new_p16[16];
715         uchar unenc_old_pw[16];
716         char no_pw[2];
717
718         BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
719
720         become_root();
721         *psmbpw = smbpw = getsmbpwnam(user);
722         unbecome_root();
723
724         if (smbpw == NULL)
725         {
726                 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
727                 return False;
728         }
729
730         if (smbpw->acct_ctrl & ACB_DISABLED)
731         {
732                 DEBUG(0,
733                       ("check_lanman_password: account %s disabled.\n",
734                        user));
735                 return False;
736         }
737
738         /* construct a null password (in case one is needed */
739         no_pw[0] = 0;
740         no_pw[1] = 0;
741         nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
742
743         /* check for null passwords */
744         if (smbpw->smb_passwd == NULL)
745         {
746                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
747                 {
748                         smbpw->smb_passwd = null_pw;
749                 }
750                 else
751                 {
752                         DEBUG(0,
753                               ("check_oem_password: no lanman password !\n"));
754                         return False;
755                 }
756         }
757
758         if (smbpw->smb_nt_passwd == NULL && nt_pass_set)
759         {
760                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
761                 {
762                         smbpw->smb_nt_passwd = null_pw;
763                 }
764                 else
765                 {
766                         DEBUG(0,
767                               ("check_oem_password: no ntlm password !\n"));
768                         return False;
769                 }
770         }
771
772         /* 
773          * Call the hash function to get the new password.
774          */
775         SamOEMhash((uchar *) lmdata, (uchar *) smbpw->smb_passwd, True);
776
777         /* 
778          * The length of the new password is in the last 4 bytes of
779          * the data buffer.
780          */
781
782         new_pw_len = IVAL(lmdata, 512);
783         if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1)
784         {
785                 DEBUG(0,
786                       ("check_oem_password: incorrect password length (%d).\n",
787                        new_pw_len));
788                 return False;
789         }
790
791         if (nt_pass_set)
792         {
793                 /*
794                  * nt passwords are in unicode
795                  */
796                 int uni_pw_len = new_pw_len;
797                 char *pw;
798                 new_pw_len /= 2;
799                 pw =
800                         dos_unistrn2((uint16 *)(&lmdata[512 - uni_pw_len]),
801                                      new_pw_len);
802                 memcpy(new_passwd, pw, new_pw_len + 1);
803         }
804         else
805         {
806                 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
807                 new_passwd[new_pw_len] = '\0';
808         }
809
810         /*
811          * To ensure we got the correct new password, hash it and
812          * use it as a key to test the passed old password.
813          */
814
815         nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
816
817         if (!nt_pass_set)
818         {
819                 /*
820                  * Now use new_p16 as the key to see if the old
821                  * password matches.
822                  */
823                 D_P16(new_p16, lmhash, unenc_old_pw);
824
825                 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
826                 {
827                         DEBUG(0,
828                               ("check_oem_password: old lm password doesn't match.\n"));
829                         return False;
830                 }
831
832 #ifdef DEBUG_PASSWORD
833                 DEBUG(100,
834                       ("check_oem_password: password %s ok\n", new_passwd));
835 #endif
836                 return True;
837         }
838
839         /*
840          * Now use new_p16 as the key to see if the old
841          * password matches.
842          */
843         D_P16(new_ntp16, lmhash, unenc_old_pw);
844         D_P16(new_ntp16, nthash, unenc_old_ntpw);
845
846         if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
847         {
848                 DEBUG(0,
849                       ("check_oem_password: old lm password doesn't match.\n"));
850                 return False;
851         }
852
853         if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16))
854         {
855                 DEBUG(0,
856                       ("check_oem_password: old nt password doesn't match.\n"));
857                 return False;
858         }
859 #ifdef DEBUG_PASSWORD
860         DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
861 #endif
862         return True;
863 }
864
865 /***********************************************************
866  Code to change the oem password. Changes both the lanman
867  and NT hashes.
868  override = False, normal
869  override = True, override XXXXXXXXXX'd password
870 ************************************************************/
871
872 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd,
873                          BOOL override)
874 {
875         int ret;
876         uchar new_nt_p16[16];
877         uchar new_p16[16];
878
879         nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
880
881         smbpw->smb_passwd = new_p16;
882         smbpw->smb_nt_passwd = new_nt_p16;
883
884         /* Now write it into the file. */
885         become_root();
886         ret = mod_smbpwd_entry(smbpw, override);
887         unbecome_root();
888
889         memset(new_passwd, '\0', strlen(new_passwd));
890
891         return ret;
892 }
893
894 /***********************************************************
895  Code to check a plaintext password against smbpasswd entries.
896 ***********************************************************/
897
898 BOOL check_plaintext_password(char *user, char *old_passwd,
899                               int old_passwd_size, struct smb_passwd **psmbpw)
900 {
901         struct smb_passwd *smbpw = NULL;
902         uchar old_pw[16], old_ntpw[16];
903
904         become_root();
905         *psmbpw = smbpw = getsmbpwnam(user);
906         unbecome_root();
907
908         if (smbpw == NULL)
909         {
910                 DEBUG(0,
911                       ("check_plaintext_password: getsmbpwnam returned NULL\n"));
912                 return False;
913         }
914
915         if (smbpw->acct_ctrl & ACB_DISABLED)
916         {
917                 DEBUG(0,
918                       ("check_plaintext_password: account %s disabled.\n",
919                        user));
920                 return (False);
921         }
922
923         nt_lm_owf_gen(old_passwd, old_ntpw, old_pw);
924
925 #ifdef DEBUG_PASSWORD
926         DEBUG(100, ("check_plaintext_password: smbpw->smb_nt_passwd \n"));
927         dump_data(100, smbpw->smb_nt_passwd, 16);
928         DEBUG(100, ("check_plaintext_password: old_ntpw \n"));
929         dump_data(100, old_ntpw, 16);
930         DEBUG(100, ("check_plaintext_password: smbpw->smb_passwd \n"));
931         dump_data(100, smbpw->smb_passwd, 16);
932         DEBUG(100, ("check_plaintext_password: old_pw\n"));
933         dump_data(100, old_pw, 16);
934 #endif
935
936         if (memcmp(smbpw->smb_nt_passwd, old_ntpw, 16)
937             && memcmp(smbpw->smb_passwd, old_pw, 16))
938                 return (False);
939         else
940                 return (True);
941 }
942
943 #undef OLD_NTDOMAIN