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