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