c22f26868486a9129c000761fb30ddb9ec18b8e7
[samba.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 #define MINPASSWDLENGTH 5
56 #define BUFSIZE 512
57
58 static int findpty(char **slave)
59 {
60   int master;
61 #ifndef HAVE_GRANTPT
62   static fstring line;
63   void *dirp;
64   char *dpname;
65 #endif /* !HAVE_GRANTPT */
66   
67 #if defined(HAVE_GRANTPT)
68   if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 1) {
69     grantpt(master);
70     unlockpt(master);
71     *slave = ptsname(master);
72     if (*slave == NULL) {
73       DEBUG(0,("findpty: Unable to create master/slave pty pair.\n"));
74       /* Stop fd leak on error. */
75       close(master);
76       return -1;
77     } else {
78       DEBUG(10, ("findpty: Allocated slave pty %s\n", *slave));
79       return (master);
80     }
81   }
82 #else /* HAVE_GRANTPT */
83   fstrcpy( line, "/dev/ptyXX" );
84
85   dirp = OpenDir(NULL, "/dev", False);
86   if (!dirp)
87     return(-1);
88   while ((dpname = ReadDirName(dirp)) != NULL) {
89     if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
90       DEBUG(3,("pty: try to open %s, line was %s\n", dpname, line ) );
91       line[8] = dpname[3];
92       line[9] = dpname[4];
93       if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
94         DEBUG(3,("pty: opened %s\n", line ) );
95         line[5] = 't';
96         *slave = line;
97         CloseDir(dirp);
98         return (master);
99       }
100     }
101   }
102   CloseDir(dirp);
103 #endif /* HAVE_GRANTPT */
104   return (-1);
105 }
106
107 static int dochild(int master,char *slavedev, char *name, char *passwordprogram, BOOL as_root)
108 {
109   int slave;
110   struct termios stermios;
111   struct passwd *pass = Get_Pwnam(name,True);
112   int gid;
113   int uid;
114
115   if (pass == NULL) {
116     DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n",
117               name));
118     return False;
119   }
120
121   gid = pass->pw_gid;
122   uid = pass->pw_uid;
123 #ifdef HAVE_SETRESUID
124   setresuid(0,0,0);
125 #else 
126   setuid(0);
127 #endif
128
129   /* Start new session - gets rid of controlling terminal. */
130   if (setsid() < 0) {
131     DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
132     return(False);
133   }
134
135   /* Open slave pty and acquire as new controlling terminal. */
136   if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) {
137     DEBUG(3,("More weirdness, could not open %s\n", 
138              slavedev));
139     return(False);
140   }
141 #ifdef I_PUSH
142   ioctl(slave, I_PUSH, "ptem");
143   ioctl(slave, I_PUSH, "ldterm");
144 #elif defined(TIOCSCTTY)
145   if (ioctl(slave,TIOCSCTTY,0) <0) {
146      DEBUG(3,("Error in ioctl call for slave pty\n"));
147      /* return(False); */
148   }
149 #endif 
150
151   /* Close master. */
152   close(master);
153
154   /* Make slave stdin/out/err of child. */
155
156   if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
157     DEBUG(3,("Could not re-direct stdin\n"));
158     return(False);
159   }
160   if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
161     DEBUG(3,("Could not re-direct stdout\n"));
162     return(False);
163   }
164   if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
165     DEBUG(3,("Could not re-direct stderr\n"));
166     return(False);
167   }
168   if (slave > 2) close(slave);
169
170   /* Set proper terminal attributes - no echo, canonical input processing,
171      no map NL to CR/NL on output. */
172
173   if (tcgetattr(0, &stermios) < 0) {
174     DEBUG(3,("could not read default terminal attributes on pty\n"));
175     return(False);
176   }
177   stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
178   stermios.c_lflag |= ICANON;
179   stermios.c_oflag &= ~(ONLCR);
180   if (tcsetattr(0, TCSANOW, &stermios) < 0) {
181     DEBUG(3,("could not set attributes of pty\n"));
182     return(False);
183   }
184
185   /* make us completely into the right uid */
186   if (!as_root) {
187 #ifdef HAVE_SETRESUID
188           setresgid(0,0,0);
189           setresuid(0,0,0);
190           setresgid(gid,gid,gid);
191           setresuid(uid,uid,uid);      
192 #else      
193           setuid(0);
194           seteuid(0);
195           setgid(gid);
196           setegid(gid);
197           setuid(uid);
198           seteuid(uid);
199 #endif
200   }
201
202   DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram));
203
204   /* execl() password-change application */
205   if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) {
206     DEBUG(3,("Bad status returned from %s\n",passwordprogram));
207     return(False);
208   }
209   return(True);
210 }
211
212 static int expect(int master,char *expected,char *buf)
213 {
214   int n, m;
215  
216   n = 0;
217   buf[0] = 0;
218   while (1) {
219     if (n >= BUFSIZE-1) {
220       return False;
221     }
222
223     /* allow 4 seconds for some output to appear */
224     m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
225     if (m < 0) 
226       return False;
227
228     n += m;
229     buf[n] = 0;
230
231     {
232       pstring s1,s2;
233       pstrcpy(s1,buf);
234       pstrcpy(s2,expected);
235       if (do_match(s1, s2, False))
236         return(True);
237     }
238   }
239 }
240
241 static void pwd_sub(char *buf)
242 {
243   string_sub(buf,"\\n","\n");
244   string_sub(buf,"\\r","\r");
245   string_sub(buf,"\\s"," ");
246   string_sub(buf,"\\t","\t");
247 }
248
249 static void writestring(int fd,char *s)
250 {
251   int l;
252   
253   l = strlen (s);
254   write (fd, s, l);
255 }
256
257
258 static int talktochild(int master, char *chatsequence)
259 {
260   char buf[BUFSIZE];
261   int count=0;
262   char *ptr=chatsequence;
263   fstring chatbuf;
264
265   *buf = 0;
266   sleep(1);
267
268   while (next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) {
269     BOOL ok=True;
270     count++;
271     pwd_sub(chatbuf);
272     if (!strequal(chatbuf,"."))
273       ok = expect(master,chatbuf,buf);
274
275     if (lp_passwd_chat_debug())
276       DEBUG(100,("talktochild: chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
277
278     if (!ok) {
279       DEBUG(3,("response %d incorrect\n",count));
280       return(False);
281     }
282
283     if (!next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) break;
284     pwd_sub(chatbuf);
285     if (!strequal(chatbuf,"."))
286       writestring(master,chatbuf);
287
288     if (lp_passwd_chat_debug())
289       DEBUG(100,("talktochild: sendbuf=[%s]\n",chatbuf));
290   }
291
292   if (count<1) return(False);
293
294   return (True);
295 }
296
297
298 static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root)
299 {
300   char *slavedev;
301   int master;
302   pid_t pid, wpid;
303   int wstat;
304   BOOL chstat = False;    
305
306   /* allocate a pseudo-terminal device */
307   if ((master = findpty (&slavedev)) < 0) {
308     DEBUG(3,("Cannot Allocate pty for password change: %s\n",name));
309     return(False);
310   }
311
312   if ((pid = fork()) < 0) {
313     DEBUG(3,("Cannot fork() child for password change: %s\n",name));
314     close(master);
315     return(False);
316   }
317
318   /* we now have a pty */
319   if (pid > 0){                 /* This is the parent process */
320     if ((chstat = talktochild(master, chatsequence)) == False) {
321       DEBUG(3,("Child failed to change password: %s\n",name));
322       kill(pid, SIGKILL); /* be sure to end this process */
323     }
324
325     if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
326       DEBUG(3,("The process is no longer waiting!\n\n"));
327       close(master);
328       return(False);
329     }
330
331     close(master);
332
333     if (pid != wpid) {
334       DEBUG(3,("We were waiting for the wrong process ID\n"));  
335       return(False);
336     }
337     if (WIFEXITED(wstat) == 0) {
338       DEBUG(3,("The process exited while we were waiting\n"));
339       return(False);
340     }
341     if (WEXITSTATUS(wstat) != 0) {
342       DEBUG(3,("The status of the process exiting was %d\n", wstat));
343       return(False);
344     }
345     
346   } else {
347     /* CHILD */
348
349     /*
350      * Lose any oplock capabilities.
351      */
352     set_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
353     set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
354
355     /* make sure it doesn't freeze */
356     alarm(20);
357
358     if (as_root)
359       become_root(False);
360     DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid()));
361     chstat = dochild(master, slavedev, name, passwordprogram, as_root);
362
363     if (as_root)
364       unbecome_root(False);
365   }
366
367   if (chstat)
368     DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name));
369   return (chstat);
370 }
371
372
373 BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
374 {
375   pstring passwordprogram;
376   pstring chatsequence;
377   int i;
378   int len;
379
380   strlower(name); 
381   DEBUG(3,("Password change for user: %s\n",name));
382
383 #if DEBUG_PASSWORD
384   DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass)); 
385 #endif
386
387   /* Take the passed information and test it for minimum criteria */
388   /* Minimum password length */
389   if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */ 
390     {
391       DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
392       return (False);           /* inform the user */
393     }
394   
395   /* Password is same as old password */
396   if (strcmp(oldpass,newpass) == 0) /* don't allow same password */
397     {
398       DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */
399       return (False);           /* inform the user */
400     }
401
402   pstrcpy(passwordprogram,lp_passwd_program());
403   pstrcpy(chatsequence,lp_passwd_chat());
404
405   if (!*chatsequence) {
406     DEBUG(2,("Null chat sequence - no password changing\n"));
407     return(False);
408   }
409
410   if (!*passwordprogram) {
411     DEBUG(2,("Null password program - no password changing\n"));
412     return(False);
413   }
414
415   /* 
416    * Check the old and new passwords don't contain any control
417    * characters.
418    */
419
420   len = strlen(oldpass); 
421   for(i = 0; i < len; i++) {
422     if (iscntrl((int)oldpass[i])) {
423       DEBUG(0,("chat_with_program: oldpass contains control characters (disallowed).\n"));
424       return False;
425     }
426   }
427
428   len = strlen(newpass);
429   for(i = 0; i < len; i++) {
430     if (iscntrl((int)newpass[i])) {
431       DEBUG(0,("chat_with_program: newpass contains control characters (disallowed).\n"));
432       return False;
433     }
434   }
435
436   string_sub(passwordprogram,"%u",name);
437   all_string_sub(passwordprogram,"%o",oldpass);
438   all_string_sub(passwordprogram,"%n",newpass);
439
440   string_sub(chatsequence,"%u",name);
441   all_string_sub(chatsequence,"%o",oldpass);
442   all_string_sub(chatsequence,"%n",newpass);
443   return(chat_with_program(passwordprogram,name,chatsequence, as_root));
444 }
445
446 #else /* ALLOW_CHANGE_PASSWORD */
447 BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
448 {
449   DEBUG(0,("Password changing not compiled in (user=%s)\n",name));
450   return(False);
451 }
452 #endif /* ALLOW_CHANGE_PASSWORD */
453
454 /***********************************************************
455  Code to check the lanman hashed password.
456 ************************************************************/
457
458 BOOL check_lanman_password(char *user, uchar *pass1, 
459                            uchar *pass2, struct smb_passwd **psmbpw)
460 {
461   static uchar null_pw[16];
462   uchar unenc_new_pw[16];
463   uchar unenc_old_pw[16];
464   struct smb_passwd *smbpw;
465
466   *psmbpw = NULL;
467
468   become_root(0);
469   smbpw = getsmbpwnam(user);
470   unbecome_root(0);
471
472   if (smbpw == NULL)
473   {
474     DEBUG(0,("check_lanman_password: getsmbpwnam returned NULL\n"));
475     return False;
476   }
477
478   if (smbpw->acct_ctrl & ACB_DISABLED)
479   {
480     DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
481     return False;
482   }
483
484   if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
485   {
486     uchar no_pw[14];
487     memset(no_pw, '\0', 14);
488     E_P16(no_pw, null_pw);
489     smbpw->smb_passwd = null_pw;
490   } else if (smbpw->smb_passwd == NULL) {
491     DEBUG(0,("check_lanman_password: no lanman password !\n"));
492     return False;
493   }
494
495   /* Get the new lanman hash. */
496   D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
497
498   /* Use this to get the old lanman hash. */
499   D_P16(unenc_new_pw, pass1, unenc_old_pw);
500
501   /* Check that the two old passwords match. */
502   if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
503   {
504     DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
505     return False;
506   }
507
508   *psmbpw = smbpw;
509   return True;
510 }
511
512 /***********************************************************
513  Code to change the lanman hashed password.
514  It nulls out the NT hashed password as it will
515  no longer be valid.
516 ************************************************************/
517
518 BOOL change_lanman_password(struct smb_passwd *smbpw, uchar *pass1, uchar *pass2)
519 {
520   static uchar null_pw[16];
521   uchar unenc_new_pw[16];
522   BOOL ret;
523
524   if (smbpw == NULL)
525   { 
526     DEBUG(0,("change_lanman_password: no smb password entry.\n"));
527     return False;
528   }
529
530   if (smbpw->acct_ctrl & ACB_DISABLED)
531   {
532     DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->unix_name));
533     return False;
534   }
535
536   if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
537   {
538     uchar no_pw[14];
539     memset(no_pw, '\0', 14);
540     E_P16(no_pw, null_pw);
541     smbpw->smb_passwd = null_pw;
542   } else if (smbpw->smb_passwd == NULL) {
543     DEBUG(0,("change_lanman_password: no lanman password !\n"));
544     return False;
545   }
546
547   /* Get the new lanman hash. */
548   D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
549
550   smbpw->smb_passwd = unenc_new_pw;
551   smbpw->smb_nt_passwd = NULL; /* We lose the NT hash. Sorry. */
552
553   /* Now write it into the file. */
554   become_root(0);
555   ret = mod_smbpwd_entry(smbpw,False);
556   unbecome_root(0);
557     
558   return ret;
559 }
560
561 /***********************************************************
562  Code to check and change the OEM hashed password.
563 ************************************************************/
564 BOOL pass_oem_change(char *user,
565                         uchar *lmdata, uchar *lmhash,
566                         uchar *ntdata, uchar *nthash)
567 {
568         fstring new_passwd;
569         struct smb_passwd *sampw;
570         BOOL ret = check_oem_password( user, lmdata, lmhash, ntdata, nthash,
571                                        &sampw, 
572                                        new_passwd, sizeof(new_passwd));
573
574         /* now we check to see if we are actually allowed to change the
575            password. */
576            
577         if (ret && (sampw->acct_ctrl & ACB_PWLOCK))
578         {
579                 ret = False;
580         }
581         
582         /* 
583          * At this point we have the new case-sensitive plaintext
584          * password in the fstring new_passwd. If we wanted to synchronise
585          * with UNIX passwords we would call a UNIX password changing 
586          * function here. However it would have to be done as root
587          * as the plaintext of the old users password is not 
588          * available. JRA.
589          */
590
591         if ( ret && lp_unix_password_sync())
592         {
593                 ret = chgpasswd(user,"", new_passwd, True);
594         }
595
596         if (ret)
597         {
598                 ret = change_oem_password( sampw, new_passwd, False );
599         }
600
601         memset(new_passwd, 0, sizeof(new_passwd));
602
603         return ret;
604 }
605
606 /***********************************************************
607  decode a password buffer
608 ************************************************************/
609 BOOL decode_pw_buffer(const char buffer[516], char *new_passwd,
610                         int new_passwd_size, BOOL nt_pass_set)
611 {
612         /* 
613          * The length of the new password is in the last 4 bytes of
614          * the data buffer.
615          */
616
617         uint32 new_pw_len = IVAL(buffer, 512);
618         if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1)
619         {
620                 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
621                 return False;
622         }
623
624         if (nt_pass_set)
625         {
626                 /*
627                  * nt passwords are in unicode
628                  */
629                 int uni_pw_len = new_pw_len;
630                 new_pw_len /= 2;
631                 unibuf_to_ascii(new_passwd, &buffer[512-uni_pw_len], new_pw_len);
632         }
633         else
634         {
635                 memcpy(new_passwd, &buffer[512-new_pw_len], new_pw_len);
636                 new_passwd[new_pw_len] = '\0';
637         }
638
639         return True;
640 }
641
642 /***********************************************************
643  Code to check the OEM hashed password.
644
645  this function ignores the 516 byte nt OEM hashed password
646  but does use the lm OEM password to check the nt hashed-hash.
647
648 ************************************************************/
649 BOOL check_oem_password(char *user,
650                         uchar *lmdata, uchar *lmhash,
651                         uchar *ntdata, uchar *nthash,
652                         struct smb_passwd **psmbpw, char *new_passwd,
653                         int new_passwd_size)
654 {
655         static uchar null_pw[16];
656         static uchar null_ntpw[16];
657         struct smb_passwd *smbpw = NULL;
658         uchar new_ntp16[16];
659         uchar unenc_old_ntpw[16];
660         uchar new_p16[16];
661         uchar unenc_old_pw[16];
662         char no_pw[2];
663
664         BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
665
666         become_root(False);
667         *psmbpw = smbpw = getsmbpwnam(user);
668         unbecome_root(False);
669
670         if (smbpw == NULL)
671         {
672                 DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n"));
673                 return False;
674         }
675
676         if (smbpw->acct_ctrl & ACB_DISABLED)
677         {
678                 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
679                 return False;
680         }
681
682         /* construct a null password (in case one is needed */
683         no_pw[0] = 0;
684         no_pw[1] = 0;
685         nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
686
687         /* check for null passwords */
688         if (smbpw->smb_passwd == NULL)
689         {
690                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
691                 {
692                         smbpw->smb_passwd = null_pw;
693                 }
694                 else 
695                 {
696                         DEBUG(0,("check_oem_password: no lanman password !\n"));
697                         return False;
698                 }
699         }
700
701         if (smbpw->smb_nt_passwd == NULL && nt_pass_set)
702         {
703                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
704                 {
705                         smbpw->smb_nt_passwd = null_pw;
706                 }
707                 else 
708                 {
709                         DEBUG(0,("check_oem_password: no ntlm password !\n"));
710                         return False;
711                 }
712         }
713
714         /* 
715          * Call the hash function to get the new password.
716          */
717         SamOEMhash( (uchar *)lmdata, (uchar *)smbpw->smb_passwd, True);
718
719         if (!decode_pw_buffer(lmdata, new_passwd, new_passwd_size, nt_pass_set))
720         {
721                 return False;
722         }
723
724         /*
725          * To ensure we got the correct new password, hash it and
726          * use it as a key to test the passed old password.
727          */
728
729         nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
730
731         if (!nt_pass_set)
732         {
733                 /*
734                  * Now use new_p16 as the key to see if the old
735                  * password matches.
736                  */
737                 D_P16(new_p16  , lmhash, unenc_old_pw);
738
739                 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
740                 {
741                         DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
742                         return False;
743                 }
744
745 #ifdef DEBUG_PASSWORD
746                 DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
747 #endif
748                 return True;
749         }
750
751         /*
752          * Now use new_p16 as the key to see if the old
753          * password matches.
754          */
755         D_P16(new_ntp16, lmhash, unenc_old_pw);
756         D_P16(new_ntp16, nthash, unenc_old_ntpw);
757
758         if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
759         {
760                 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
761                 return False;
762         }
763
764         if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16))
765         {
766                 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
767                 return False;
768         }
769 #ifdef DEBUG_PASSWORD
770         DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
771 #endif
772         return True;
773 }
774
775 /***********************************************************
776  Code to change the oem password. Changes both the lanman
777  and NT hashes.
778  override = False, normal
779  override = True, override XXXXXXXXXX'd password
780 ************************************************************/
781
782 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override)
783 {
784   int ret;
785   uchar new_nt_p16[16];
786   uchar new_p16[16];
787
788   nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
789
790   smbpw->smb_passwd = new_p16;
791   smbpw->smb_nt_passwd = new_nt_p16;
792   
793   /* Now write it into the file. */
794   become_root(0);
795   ret = mod_smbpwd_entry(smbpw,override);
796   unbecome_root(0);
797
798   memset(new_passwd, '\0', strlen(new_passwd));
799
800   return ret;
801 }