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