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
52extern int DEBUGLEVEL;
53
54#if ALLOW_CHANGE_PASSWORD
55
56static 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
104static 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
194static 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
244static 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
252static 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
279static 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
380BOOL 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 */
456BOOL 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
467BOOL 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
527BOOL 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************************************************************/
573BOOL 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************************************************************/
614BOOL 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
772BOOL 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}
792
793/***********************************************************
794 Code to check a plaintext password against smbpasswd entries.
795***********************************************************/
796
797BOOL check_plaintext_password(char *user,char *old_passwd,
798                              int old_passwd_size, struct smb_passwd **psmbpw)
799{
800  struct smb_passwd *smbpw = NULL;
801  uchar old_pw[16],old_ntpw[16];
802
803  become_root(False);
804  *psmbpw = smbpw = getsmbpwnam(user);
805  unbecome_root(False);
806
807  if (smbpw == NULL) {
808    DEBUG(0,("check_plaintext_password: getsmbpwnam returned NULL\n"));
809    return False;
810  }
811
812  if (smbpw->acct_ctrl & ACB_DISABLED) {
813    DEBUG(0,("check_plaintext_password: account %s disabled.\n", user));
814    return(False);
815  }
816
817  nt_lm_owf_gen(old_passwd,old_ntpw,old_pw);
818
819#ifdef DEBUG_PASSWORD
820  DEBUG(100,("check_plaintext_password: smbpw->smb_nt_passwd \n"));
821  dump_data(100,smbpw->smb_nt_passwd,16);
822  DEBUG(100,("check_plaintext_password: old_ntpw \n"));
823  dump_data(100,old_ntpw,16);
824  DEBUG(100,("check_plaintext_password: smbpw->smb_passwd \n"));
825  dump_data(100,smbpw->smb_passwd,16);
826  DEBUG(100,("check_plaintext_password: old_pw\n"));
827  dump_data(100,old_pw,16);
828#endif
829
830  if(memcmp(smbpw->smb_nt_passwd,old_ntpw,16) && memcmp(smbpw->smb_passwd,old_pw,16))
831    return(False);
832  else
833    return(True);
834}
835