changed string_sub() to replace " ; and ` in the inserted string with _
[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 #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->smb_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         /* 
575          * At this point we have the new case-sensitive plaintext
576          * password in the fstring new_passwd. If we wanted to synchronise
577          * with UNIX passwords we would call a UNIX password changing 
578          * function here. However it would have to be done as root
579          * as the plaintext of the old users password is not 
580          * available. JRA.
581          */
582
583         if ( ret && lp_unix_password_sync())
584         {
585                 ret = chgpasswd(user,"", new_passwd, True);
586         }
587
588         if (ret)
589         {
590                 ret = change_oem_password( sampw, new_passwd, False );
591         }
592
593         memset(new_passwd, 0, sizeof(new_passwd));
594
595         return ret;
596 }
597
598 /***********************************************************
599  Code to check the OEM hashed password.
600
601  this function ignores the 516 byte nt OEM hashed password
602  but does use the lm OEM password to check the nt hashed-hash.
603
604 ************************************************************/
605 BOOL check_oem_password(char *user,
606                         uchar *lmdata, uchar *lmhash,
607                         uchar *ntdata, uchar *nthash,
608                         struct smb_passwd **psmbpw, char *new_passwd,
609                         int new_passwd_size)
610 {
611         static uchar null_pw[16];
612         static uchar null_ntpw[16];
613         struct smb_passwd *smbpw = NULL;
614         int new_pw_len;
615         uchar new_ntp16[16];
616         uchar unenc_old_ntpw[16];
617         uchar new_p16[16];
618         uchar unenc_old_pw[16];
619         char no_pw[2];
620
621         BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
622
623         become_root(False);
624         *psmbpw = smbpw = getsmbpwnam(user);
625         unbecome_root(False);
626
627         if (smbpw == NULL)
628         {
629                 DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n"));
630                 return False;
631         }
632
633         if (smbpw->acct_ctrl & ACB_DISABLED)
634         {
635                 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
636                 return False;
637         }
638
639         /* construct a null password (in case one is needed */
640         no_pw[0] = 0;
641         no_pw[1] = 0;
642         nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
643
644         /* check for null passwords */
645         if (smbpw->smb_passwd == NULL)
646         {
647                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
648                 {
649                         smbpw->smb_passwd = null_pw;
650                 }
651                 else 
652                 {
653                         DEBUG(0,("check_oem_password: no lanman password !\n"));
654                         return False;
655                 }
656         }
657
658         if (smbpw->smb_nt_passwd == NULL && nt_pass_set)
659         {
660                 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
661                 {
662                         smbpw->smb_nt_passwd = null_pw;
663                 }
664                 else 
665                 {
666                         DEBUG(0,("check_oem_password: no ntlm password !\n"));
667                         return False;
668                 }
669         }
670
671         /* 
672          * Call the hash function to get the new password.
673          */
674         SamOEMhash( (uchar *)lmdata, (uchar *)smbpw->smb_passwd, True);
675
676         /* 
677          * The length of the new password is in the last 4 bytes of
678          * the data buffer.
679          */
680
681         new_pw_len = IVAL(lmdata, 512);
682         if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1)
683         {
684                 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
685                 return False;
686         }
687
688         if (nt_pass_set)
689         {
690                 /*
691                  * nt passwords are in unicode
692                  */
693                 int uni_pw_len = new_pw_len;
694                 char *pw;
695                 new_pw_len /= 2;
696                 pw = unistrn2((uint16*)(&lmdata[512-uni_pw_len]), new_pw_len);
697                 memcpy(new_passwd, pw, new_pw_len+1);
698         }
699         else
700         {
701                 memcpy(new_passwd, &lmdata[512-new_pw_len], new_pw_len);
702                 new_passwd[new_pw_len] = '\0';
703         }
704
705         /*
706          * To ensure we got the correct new password, hash it and
707          * use it as a key to test the passed old password.
708          */
709
710         nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
711
712         if (!nt_pass_set)
713         {
714                 /*
715                  * Now use new_p16 as the key to see if the old
716                  * password matches.
717                  */
718                 D_P16(new_p16  , lmhash, unenc_old_pw);
719
720                 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
721                 {
722                         DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
723                         return False;
724                 }
725
726 #ifdef DEBUG_PASSWORD
727                 DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
728 #endif
729                 return True;
730         }
731
732         /*
733          * Now use new_p16 as the key to see if the old
734          * password matches.
735          */
736         D_P16(new_ntp16, lmhash, unenc_old_pw);
737         D_P16(new_ntp16, nthash, unenc_old_ntpw);
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         if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16))
746         {
747                 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
748                 return False;
749         }
750 #ifdef DEBUG_PASSWORD
751         DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
752 #endif
753         return True;
754 }
755
756 /***********************************************************
757  Code to change the oem password. Changes both the lanman
758  and NT hashes.
759  override = False, normal
760  override = True, override XXXXXXXXXX'd password
761 ************************************************************/
762
763 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override)
764 {
765   int ret;
766   uchar new_nt_p16[16];
767   uchar new_p16[16];
768
769   nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
770
771   smbpw->smb_passwd = new_p16;
772   smbpw->smb_nt_passwd = new_nt_p16;
773   
774   /* Now write it into the file. */
775   become_root(0);
776   ret = mod_smbpwd_entry(smbpw,override);
777   unbecome_root(0);
778
779   memset(new_passwd, '\0', strlen(new_passwd));
780
781   return ret;
782 }