1/*
2   Unix SMB/CIFS implementation.
3   Samba utility functions
4   Copyright (C) Andrew Tridgell 1992-1998
5   Copyright (C) Andrew Bartlett 2001-2004
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 3 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, see <http://www.gnu.org/licenses/>.
19*/
20
21/* These comments regard the code to change the user's unix password: */
22
23/* fork a child process to exec passwd and write to its
24 * tty to change a users password. This is running as the
25 * user who is attempting to change the password.
26 */
27
28/*
29 * This code was copied/borrowed and stolen from various sources.
30 * The primary source was the poppasswd.c from the authors of POPMail. This software
31 * was included as a client to change passwords using the 'passwd' program
32 * on the remote machine.
33 *
34 * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
35 * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
36 * and rights to modify, distribute or incorporate this change to the CAP suite or
37 * using it for any other reason are granted, so long as this disclaimer is left intact.
38 */
39
40/*
41   This code was hacked considerably for inclusion in Samba, primarily
42   by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
43   of the "password chat" option, which allows the easy runtime
44   specification of the expected sequence of events to change a
45   password.
46   */
47
48#include "includes.h"
49#include "../libcli/auth/libcli_auth.h"
50
51static NTSTATUS check_oem_password(const char *user,
52				   uchar password_encrypted_with_lm_hash[516],
53				   const uchar old_lm_hash_encrypted[16],
54				   uchar password_encrypted_with_nt_hash[516],
55				   const uchar old_nt_hash_encrypted[16],
56				   struct samu *sampass,
57				   char **pp_new_passwd);
58
59#if ALLOW_CHANGE_PASSWORD
60
61static int findpty(char **slave)
62{
63	int master = -1;
64	char *line = NULL;
65	SMB_STRUCT_DIR *dirp = NULL;
66	const char *dpname;
67
68	*slave = NULL;
69
70#if defined(HAVE_GRANTPT)
71	/* Try to open /dev/ptmx. If that fails, fall through to old method. */
72	if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
73		grantpt(master);
74		unlockpt(master);
75		line = (char *)ptsname(master);
76		if (line) {
77			*slave = SMB_STRDUP(line);
78		}
79
80		if (*slave == NULL) {
81			DEBUG(0,
82			      ("findpty: Unable to create master/slave pty pair.\n"));
83			/* Stop fd leak on error. */
84			close(master);
85			return -1;
86		} else {
87			DEBUG(10,
88			      ("findpty: Allocated slave pty %s\n", *slave));
89			return (master);
90		}
91	}
92#endif /* HAVE_GRANTPT */
93
94	line = SMB_STRDUP("/dev/ptyXX");
95	if (!line) {
96		return (-1);
97	}
98
99	dirp = sys_opendir("/dev");
100	if (!dirp) {
101		SAFE_FREE(line);
102		return (-1);
103	}
104
105	while ((dpname = readdirname(dirp)) != NULL) {
106		if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
107			DEBUG(3,
108			      ("pty: try to open %s, line was %s\n", dpname,
109			       line));
110			line[8] = dpname[3];
111			line[9] = dpname[4];
112			if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
113				DEBUG(3, ("pty: opened %s\n", line));
114				line[5] = 't';
115				*slave = line;
116				sys_closedir(dirp);
117				return (master);
118			}
119		}
120	}
121	sys_closedir(dirp);
122	SAFE_FREE(line);
123	return (-1);
124}
125
126static int dochild(int master, const char *slavedev, const struct passwd *pass,
127		   const char *passwordprogram, bool as_root)
128{
129	int slave;
130	struct termios stermios;
131	gid_t gid;
132	uid_t uid;
133	char * const eptrs[1] = { NULL };
134
135	if (pass == NULL)
136	{
137		DEBUG(0,
138		      ("dochild: user doesn't exist in the UNIX password database.\n"));
139		return False;
140	}
141
142	gid = pass->pw_gid;
143	uid = pass->pw_uid;
144
145	gain_root_privilege();
146
147	/* Start new session - gets rid of controlling terminal. */
148	if (setsid() < 0)
149	{
150		DEBUG(3,
151		      ("Weirdness, couldn't let go of controlling terminal\n"));
152		return (False);
153	}
154
155	/* Open slave pty and acquire as new controlling terminal. */
156	if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
157	{
158		DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
159		return (False);
160	}
161#if defined(TIOCSCTTY) && !defined(SUNOS5)
162	/*
163	 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
164	 * see the discussion under
165	 * https://bugzilla.samba.org/show_bug.cgi?id=5366.
166	 */
167	if (ioctl(slave, TIOCSCTTY, 0) < 0)
168	{
169		DEBUG(3, ("Error in ioctl call for slave pty\n"));
170		/* return(False); */
171	}
172#elif defined(I_PUSH) && defined(I_FIND)
173	if (ioctl(slave, I_FIND, "ptem") == 0) {
174		ioctl(slave, I_PUSH, "ptem");
175	}
176	if (ioctl(slave, I_FIND, "ldterm") == 0) {
177		ioctl(slave, I_PUSH, "ldterm");
178	}
179#endif
180
181	/* Close master. */
182	close(master);
183
184	/* Make slave stdin/out/err of child. */
185
186	if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
187	{
188		DEBUG(3, ("Could not re-direct stdin\n"));
189		return (False);
190	}
191	if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
192	{
193		DEBUG(3, ("Could not re-direct stdout\n"));
194		return (False);
195	}
196	if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
197	{
198		DEBUG(3, ("Could not re-direct stderr\n"));
199		return (False);
200	}
201	if (slave > 2)
202		close(slave);
203
204	/* Set proper terminal attributes - no echo, canonical input processing,
205	   no map NL to CR/NL on output. */
206
207	if (tcgetattr(0, &stermios) < 0)
208	{
209		DEBUG(3,
210		      ("could not read default terminal attributes on pty\n"));
211		return (False);
212	}
213	stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
214	stermios.c_lflag |= ICANON;
215#ifdef ONLCR
216 	stermios.c_oflag &= ~(ONLCR);
217#endif
218	if (tcsetattr(0, TCSANOW, &stermios) < 0)
219	{
220		DEBUG(3, ("could not set attributes of pty\n"));
221		return (False);
222	}
223
224	/* make us completely into the right uid */
225	if (!as_root)
226	{
227		become_user_permanently(uid, gid);
228	}
229
230	DEBUG(10,
231	      ("Invoking '%s' as password change program.\n",
232	       passwordprogram));
233
234	/* execl() password-change application */
235	if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
236	{
237		DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
238		return (False);
239	}
240	return (True);
241}
242
243static int expect(int master, char *issue, char *expected)
244{
245	char buffer[1024];
246	int attempts, timeout, nread;
247	size_t len;
248	bool match = False;
249
250	for (attempts = 0; attempts < 2; attempts++) {
251		NTSTATUS status;
252		if (!strequal(issue, ".")) {
253			if (lp_passwd_chat_debug())
254				DEBUG(100, ("expect: sending [%s]\n", issue));
255
256			if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
257				DEBUG(2,("expect: (short) write returned %d\n",
258					 (int)len ));
259				return False;
260			}
261		}
262
263		if (strequal(expected, "."))
264			return True;
265
266		/* Initial timeout. */
267		timeout = lp_passwd_chat_timeout() * 1000;
268		nread = 0;
269		buffer[nread] = 0;
270
271		while (True) {
272			status = read_fd_with_timeout(
273				master, buffer + nread, 1,
274				sizeof(buffer) - nread - 1,
275				timeout, &len);
276
277			if (!NT_STATUS_IS_OK(status)) {
278				break;
279			}
280			nread += len;
281			buffer[nread] = 0;
282
283			{
284				/* Eat leading/trailing whitespace before match. */
285				char *str = SMB_STRDUP(buffer);
286				if (!str) {
287					DEBUG(2,("expect: ENOMEM\n"));
288					return False;
289				}
290				trim_char(str, ' ', ' ');
291
292				if ((match = unix_wild_match(expected, str)) == True) {
293					/* Now data has started to return, lower timeout. */
294					timeout = lp_passwd_chat_timeout() * 100;
295				}
296				SAFE_FREE(str);
297			}
298		}
299
300		if (lp_passwd_chat_debug())
301			DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
302				    expected, buffer, match ? "yes" : "no" ));
303
304		if (match)
305			break;
306
307		if (!NT_STATUS_IS_OK(status)) {
308			DEBUG(2, ("expect: %s\n", nt_errstr(status)));
309			return False;
310		}
311	}
312
313	DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
314	return match;
315}
316
317static void pwd_sub(char *buf)
318{
319	all_string_sub(buf, "\\n", "\n", 0);
320	all_string_sub(buf, "\\r", "\r", 0);
321	all_string_sub(buf, "\\s", " ", 0);
322	all_string_sub(buf, "\\t", "\t", 0);
323}
324
325static int talktochild(int master, const char *seq)
326{
327	TALLOC_CTX *frame = talloc_stackframe();
328	int count = 0;
329	char *issue;
330	char *expected;
331
332	issue = talloc_strdup(frame, ".");
333	if (!issue) {
334		TALLOC_FREE(frame);
335		return false;
336	}
337
338	while (next_token_talloc(frame, &seq, &expected, NULL)) {
339		pwd_sub(expected);
340		count++;
341
342		if (!expect(master, issue, expected)) {
343			DEBUG(3, ("Response %d incorrect\n", count));
344			TALLOC_FREE(frame);
345			return false;
346		}
347
348		if (!next_token_talloc(frame, &seq, &issue, NULL)) {
349			issue = talloc_strdup(frame, ".");
350			if (!issue) {
351				TALLOC_FREE(frame);
352				return false;
353			}
354		}
355		pwd_sub(issue);
356	}
357
358	if (!strequal(issue, ".")) {
359		/* we have one final issue to send */
360		expected = talloc_strdup(frame, ".");
361		if (!expected) {
362			TALLOC_FREE(frame);
363			return false;
364		}
365		if (!expect(master, issue, expected)) {
366			TALLOC_FREE(frame);
367			return False;
368		}
369	}
370	TALLOC_FREE(frame);
371	return (count > 0);
372}
373
374static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
375			      char *chatsequence, bool as_root)
376{
377	char *slavedev = NULL;
378	int master;
379	pid_t pid, wpid;
380	int wstat;
381	bool chstat = False;
382
383	if (pass == NULL) {
384		DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
385		return False;
386	}
387
388	/* allocate a pseudo-terminal device */
389	if ((master = findpty(&slavedev)) < 0) {
390		DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
391		return (False);
392	}
393
394	/*
395	 * We need to temporarily stop CatchChild from eating
396	 * SIGCLD signals as it also eats the exit status code. JRA.
397	 */
398
399	CatchChildLeaveStatus();
400
401	if ((pid = sys_fork()) < 0) {
402		DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
403		SAFE_FREE(slavedev);
404		close(master);
405		CatchChild();
406		return (False);
407	}
408
409	/* we now have a pty */
410	if (pid > 0) {			/* This is the parent process */
411		/* Don't need this anymore in parent. */
412		SAFE_FREE(slavedev);
413
414		if ((chstat = talktochild(master, chatsequence)) == False) {
415			DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
416			kill(pid, SIGKILL);	/* be sure to end this process */
417		}
418
419		while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
420			if (errno == EINTR) {
421				errno = 0;
422				continue;
423			}
424			break;
425		}
426
427		if (wpid < 0) {
428			DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
429			close(master);
430			CatchChild();
431			return (False);
432		}
433
434		/*
435		 * Go back to ignoring children.
436		 */
437		CatchChild();
438
439		close(master);
440
441		if (pid != wpid) {
442			DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
443			return (False);
444		}
445		if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
446			DEBUG(3, ("chat_with_program: The process exited with status %d \
447while we were waiting\n", WEXITSTATUS(wstat)));
448			return (False);
449		}
450#if defined(WIFSIGNALLED) && defined(WTERMSIG)
451		else if (WIFSIGNALLED(wstat)) {
452                        DEBUG(3, ("chat_with_program: The process was killed by signal %d \
453while we were waiting\n", WTERMSIG(wstat)));
454			return (False);
455		}
456#endif
457	} else {
458		/* CHILD */
459
460		/*
461		 * Lose any elevated privileges.
462		 */
463		drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
464		drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
465
466		/* make sure it doesn't freeze */
467		alarm(20);
468
469		if (as_root)
470			become_root();
471
472		DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
473		       (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
474		chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
475
476		if (as_root)
477			unbecome_root();
478
479		/*
480		 * The child should never return from dochild() ....
481		 */
482
483		DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
484		exit(1);
485	}
486
487	if (chstat)
488		DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
489		       (chstat ? "" : "un"), pass->pw_name));
490	return (chstat);
491}
492
493bool chgpasswd(const char *name, const struct passwd *pass,
494	       const char *oldpass, const char *newpass, bool as_root)
495{
496	char *passwordprogram = NULL;
497	char *chatsequence = NULL;
498	size_t i;
499	size_t len;
500	TALLOC_CTX *ctx = talloc_tos();
501
502	if (!oldpass) {
503		oldpass = "";
504	}
505
506	DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
507
508#ifdef DEBUG_PASSWORD
509	DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
510#endif
511
512	/* Take the passed information and test it for minimum criteria */
513
514	/* Password is same as old password */
515	if (strcmp(oldpass, newpass) == 0) {
516		/* don't allow same password */
517		DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name));	/* log the attempt */
518		return (False);	/* inform the user */
519	}
520
521	/*
522	 * Check the old and new passwords don't contain any control
523	 * characters.
524	 */
525
526	len = strlen(oldpass);
527	for (i = 0; i < len; i++) {
528		if (iscntrl((int)oldpass[i])) {
529			DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
530			return False;
531		}
532	}
533
534	len = strlen(newpass);
535	for (i = 0; i < len; i++) {
536		if (iscntrl((int)newpass[i])) {
537			DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
538			return False;
539		}
540	}
541
542#ifdef WITH_PAM
543	if (lp_pam_password_change()) {
544		bool ret;
545#ifdef HAVE_SETLOCALE
546		const char *prevlocale = setlocale(LC_ALL, "C");
547#endif
548
549		if (as_root)
550			become_root();
551
552		if (pass) {
553			ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
554		} else {
555			ret = smb_pam_passchange(name, oldpass, newpass);
556		}
557
558		if (as_root)
559			unbecome_root();
560
561#ifdef HAVE_SETLOCALE
562		setlocale(LC_ALL, prevlocale);
563#endif
564
565		return ret;
566	}
567#endif
568
569	/* A non-PAM password change just doen't make sense without a valid local user */
570
571	if (pass == NULL) {
572		DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
573		return false;
574	}
575
576	passwordprogram = talloc_strdup(ctx, lp_passwd_program());
577	if (!passwordprogram || !*passwordprogram) {
578		DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
579		return false;
580	}
581	chatsequence = talloc_strdup(ctx, lp_passwd_chat());
582	if (!chatsequence || !*chatsequence) {
583		DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
584		return false;
585	}
586
587	if (as_root) {
588		/* The password program *must* contain the user name to work. Fail if not. */
589		if (strstr_m(passwordprogram, "%u") == NULL) {
590			DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
591the string %%u, and the given string %s does not.\n", passwordprogram ));
592			return false;
593		}
594	}
595
596	passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
597	if (!passwordprogram) {
598		return false;
599	}
600
601	/* note that we do NOT substitute the %o and %n in the password program
602	   as this would open up a security hole where the user could use
603	   a new password containing shell escape characters */
604
605	chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
606	if (!chatsequence) {
607		return false;
608	}
609	chatsequence = talloc_all_string_sub(ctx,
610					chatsequence,
611					"%o",
612					oldpass);
613	if (!chatsequence) {
614		return false;
615	}
616	chatsequence = talloc_all_string_sub(ctx,
617					chatsequence,
618					"%n",
619					newpass);
620	return chat_with_program(passwordprogram,
621				pass,
622				chatsequence,
623				as_root);
624}
625
626#else /* ALLOW_CHANGE_PASSWORD */
627
628bool chgpasswd(const char *name, const struct passwd *pass,
629	       const char *oldpass, const char *newpass, bool as_root)
630{
631	DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
632	return (False);
633}
634#endif /* ALLOW_CHANGE_PASSWORD */
635
636/***********************************************************
637 Code to check the lanman hashed password.
638************************************************************/
639
640bool check_lanman_password(char *user, uchar * pass1,
641			   uchar * pass2, struct samu **hnd)
642{
643	uchar unenc_new_pw[16];
644	uchar unenc_old_pw[16];
645	struct samu *sampass = NULL;
646	uint32 acct_ctrl;
647	const uint8 *lanman_pw;
648	bool ret;
649
650	if ( !(sampass = samu_new(NULL)) ) {
651		DEBUG(0, ("samu_new() failed!\n"));
652		return False;
653	}
654
655	become_root();
656	ret = pdb_getsampwnam(sampass, user);
657	unbecome_root();
658
659	if (ret == False) {
660		DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
661		TALLOC_FREE(sampass);
662		return False;
663	}
664
665	acct_ctrl = pdb_get_acct_ctrl     (sampass);
666	lanman_pw = pdb_get_lanman_passwd (sampass);
667
668	if (acct_ctrl & ACB_DISABLED) {
669		DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
670		TALLOC_FREE(sampass);
671		return False;
672	}
673
674	if (lanman_pw == NULL) {
675		if (acct_ctrl & ACB_PWNOTREQ) {
676			/* this saves the pointer for the caller */
677			*hnd = sampass;
678			return True;
679		} else {
680			DEBUG(0, ("check_lanman_password: no lanman password !\n"));
681			TALLOC_FREE(sampass);
682			return False;
683		}
684	}
685
686	/* Get the new lanman hash. */
687	D_P16(lanman_pw, pass2, unenc_new_pw);
688
689	/* Use this to get the old lanman hash. */
690	D_P16(unenc_new_pw, pass1, unenc_old_pw);
691
692	/* Check that the two old passwords match. */
693	if (memcmp(lanman_pw, unenc_old_pw, 16)) {
694		DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
695		TALLOC_FREE(sampass);
696		return False;
697	}
698
699	/* this saves the pointer for the caller */
700	*hnd = sampass;
701	return True;
702}
703
704/***********************************************************
705 Code to change the lanman hashed password.
706 It nulls out the NT hashed password as it will
707 no longer be valid.
708 NOTE this function is designed to be called as root. Check the old password
709 is correct before calling. JRA.
710************************************************************/
711
712bool change_lanman_password(struct samu *sampass, uchar *pass2)
713{
714	uchar null_pw[16];
715	uchar unenc_new_pw[16];
716	bool ret;
717	uint32 acct_ctrl;
718	const uint8 *pwd;
719
720	if (sampass == NULL) {
721		DEBUG(0,("change_lanman_password: no smb password entry.\n"));
722		return False;
723	}
724
725	acct_ctrl = pdb_get_acct_ctrl(sampass);
726	pwd = pdb_get_lanman_passwd(sampass);
727
728	if (acct_ctrl & ACB_DISABLED) {
729		DEBUG(0,("change_lanman_password: account %s disabled.\n",
730		       pdb_get_username(sampass)));
731		return False;
732	}
733
734	if (pwd == NULL) {
735		if (acct_ctrl & ACB_PWNOTREQ) {
736			uchar no_pw[14];
737
738			ZERO_STRUCT(no_pw);
739
740			E_P16(no_pw, null_pw);
741
742			pwd = null_pw;
743		} else {
744			DEBUG(0,("change_lanman_password: no lanman password !\n"));
745			return False;
746		}
747	}
748
749	/* Get the new lanman hash. */
750	D_P16(pwd, pass2, unenc_new_pw);
751
752	if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
753		return False;
754	}
755
756	if (!pdb_set_nt_passwd    (sampass, NULL, PDB_CHANGED)) {
757		return False;	/* We lose the NT hash. Sorry. */
758	}
759
760	if (!pdb_set_pass_last_set_time  (sampass, time(NULL), PDB_CHANGED)) {
761		TALLOC_FREE(sampass);
762		/* Not quite sure what this one qualifies as, but this will do */
763		return False;
764	}
765
766	/* Now flush the sam_passwd struct to persistent storage */
767	ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
768
769	return ret;
770}
771
772/***********************************************************
773 Code to check and change the OEM hashed password.
774************************************************************/
775
776NTSTATUS pass_oem_change(char *user,
777			 uchar password_encrypted_with_lm_hash[516],
778			 const uchar old_lm_hash_encrypted[16],
779			 uchar password_encrypted_with_nt_hash[516],
780			 const uchar old_nt_hash_encrypted[16],
781			 uint32 *reject_reason)
782{
783	char *new_passwd = NULL;
784	struct samu *sampass = NULL;
785	NTSTATUS nt_status;
786	bool ret = false;
787
788	if (!(sampass = samu_new(NULL))) {
789		return NT_STATUS_NO_MEMORY;
790	}
791
792	become_root();
793	ret = pdb_getsampwnam(sampass, user);
794	unbecome_root();
795
796	if (ret == false) {
797		DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
798		TALLOC_FREE(sampass);
799		return NT_STATUS_NO_SUCH_USER;
800	}
801
802	nt_status = check_oem_password(user,
803				       password_encrypted_with_lm_hash,
804				       old_lm_hash_encrypted,
805				       password_encrypted_with_nt_hash,
806				       old_nt_hash_encrypted,
807				       sampass,
808				       &new_passwd);
809
810	if (!NT_STATUS_IS_OK(nt_status)) {
811		TALLOC_FREE(sampass);
812		return nt_status;
813	}
814
815	/* We've already checked the old password here.... */
816	become_root();
817	nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
818	unbecome_root();
819
820	memset(new_passwd, 0, strlen(new_passwd));
821
822	TALLOC_FREE(sampass);
823
824	return nt_status;
825}
826
827/***********************************************************
828 Decrypt and verify a user password change.
829
830 The 516 byte long buffers are encrypted with the old NT and
831 old LM passwords, and if the NT passwords are present, both
832 buffers contain a unicode string.
833
834 After decrypting the buffers, check the password is correct by
835 matching the old hashed passwords with the passwords in the passdb.
836
837************************************************************/
838
839static NTSTATUS check_oem_password(const char *user,
840				   uchar password_encrypted_with_lm_hash[516],
841				   const uchar old_lm_hash_encrypted[16],
842				   uchar password_encrypted_with_nt_hash[516],
843				   const uchar old_nt_hash_encrypted[16],
844				   struct samu *sampass,
845				   char **pp_new_passwd)
846{
847	uchar null_pw[16];
848	uchar null_ntpw[16];
849	uint8 *password_encrypted;
850	const uint8 *encryption_key;
851	const uint8 *lanman_pw, *nt_pw;
852	uint32 acct_ctrl;
853	size_t new_pw_len;
854	uchar new_nt_hash[16];
855	uchar new_lm_hash[16];
856	uchar verifier[16];
857	char no_pw[2];
858
859	bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
860	bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
861
862	acct_ctrl = pdb_get_acct_ctrl(sampass);
863#if 0
864	/* I am convinced this check here is wrong, it is valid to
865	 * change a password of a user that has a disabled account - gd */
866
867	if (acct_ctrl & ACB_DISABLED) {
868		DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
869		return NT_STATUS_ACCOUNT_DISABLED;
870	}
871#endif
872	if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
873		/* construct a null password (in case one is needed */
874		no_pw[0] = 0;
875		no_pw[1] = 0;
876		nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
877		lanman_pw = null_pw;
878		nt_pw = null_pw;
879
880	} else {
881		/* save pointers to passwords so we don't have to keep looking them up */
882		if (lp_lanman_auth()) {
883			lanman_pw = pdb_get_lanman_passwd(sampass);
884		} else {
885			lanman_pw = NULL;
886		}
887		nt_pw = pdb_get_nt_passwd(sampass);
888	}
889
890	if (nt_pw && nt_pass_set) {
891		/* IDEAL Case: passwords are in unicode, and we can
892		 * read use the password encrypted with the NT hash
893		 */
894		password_encrypted = password_encrypted_with_nt_hash;
895		encryption_key = nt_pw;
896	} else if (lanman_pw && lm_pass_set) {
897		/* password may still be in unicode, but use LM hash version */
898		password_encrypted = password_encrypted_with_lm_hash;
899		encryption_key = lanman_pw;
900	} else if (nt_pass_set) {
901		DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
902			  user));
903		return NT_STATUS_WRONG_PASSWORD;
904	} else if (lm_pass_set) {
905		if (lp_lanman_auth()) {
906			DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
907				  user));
908		} else {
909			DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
910				  user));
911		}
912		return NT_STATUS_WRONG_PASSWORD;
913	} else {
914		DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
915			  user));
916		return NT_STATUS_WRONG_PASSWORD;
917	}
918
919	/*
920	 * Decrypt the password with the key
921	 */
922	arcfour_crypt( password_encrypted, encryption_key, 516);
923
924	if (!decode_pw_buffer(talloc_tos(),
925				password_encrypted,
926				pp_new_passwd,
927				&new_pw_len,
928				nt_pass_set ? CH_UTF16 : CH_DOS)) {
929		return NT_STATUS_WRONG_PASSWORD;
930	}
931
932	/*
933	 * To ensure we got the correct new password, hash it and
934	 * use it as a key to test the passed old password.
935	 */
936
937	if (nt_pass_set) {
938		/* NT passwords, verify the NT hash. */
939
940		/* Calculate the MD4 hash (NT compatible) of the password */
941		memset(new_nt_hash, '\0', 16);
942		E_md4hash(*pp_new_passwd, new_nt_hash);
943
944		if (nt_pw) {
945			/*
946			 * check the NT verifier
947			 */
948			E_old_pw_hash(new_nt_hash, nt_pw, verifier);
949			if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
950				DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
951				return NT_STATUS_WRONG_PASSWORD;
952			}
953
954			/* We could check the LM password here, but there is
955			 * little point, we already know the password is
956			 * correct, and the LM password might not even be
957			 * present. */
958
959			/* Further, LM hash generation algorithms
960			 * differ with charset, so we could
961			 * incorrectly fail a perfectly valid password
962			 * change */
963#ifdef DEBUG_PASSWORD
964			DEBUG(100,
965			      ("check_oem_password: password %s ok\n", *pp_new_passwd));
966#endif
967			return NT_STATUS_OK;
968		}
969
970		if (lanman_pw) {
971			/*
972			 * check the lm verifier
973			 */
974			E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
975			if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
976				DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
977				return NT_STATUS_WRONG_PASSWORD;
978			}
979#ifdef DEBUG_PASSWORD
980			DEBUG(100,
981			      ("check_oem_password: password %s ok\n", *pp_new_passwd));
982#endif
983			return NT_STATUS_OK;
984		}
985	}
986
987	if (lanman_pw && lm_pass_set) {
988
989		E_deshash(*pp_new_passwd, new_lm_hash);
990
991		/*
992		 * check the lm verifier
993		 */
994		E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
995		if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
996			DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
997			return NT_STATUS_WRONG_PASSWORD;
998		}
999
1000#ifdef DEBUG_PASSWORD
1001		DEBUG(100,
1002		      ("check_oem_password: password %s ok\n", *pp_new_passwd));
1003#endif
1004		return NT_STATUS_OK;
1005	}
1006
1007	/* should not be reached */
1008	return NT_STATUS_WRONG_PASSWORD;
1009}
1010
1011bool password_in_history(uint8_t nt_pw[NT_HASH_LEN],
1012			 uint32_t pw_history_len,
1013			 const uint8_t *pw_history)
1014{
1015	static const uint8_t zero_md5_nt_pw[SALTED_MD5_HASH_LEN] = { 0, };
1016	int i;
1017
1018	dump_data(100, nt_pw, NT_HASH_LEN);
1019	dump_data(100, pw_history, PW_HISTORY_ENTRY_LEN * pw_history_len);
1020
1021	for (i=0; i<pw_history_len; i++) {
1022		uint8_t new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1023		const uint8_t *current_salt;
1024		const uint8_t *old_nt_pw_salted_md5_hash;
1025
1026		current_salt = &pw_history[i*PW_HISTORY_ENTRY_LEN];
1027		old_nt_pw_salted_md5_hash = current_salt + PW_HISTORY_SALT_LEN;
1028
1029		if (memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash,
1030			   SALTED_MD5_HASH_LEN) == 0) {
1031			/* Ignore zero valued entries. */
1032			continue;
1033		}
1034
1035		if (memcmp(zero_md5_nt_pw, current_salt,
1036			   PW_HISTORY_SALT_LEN) == 0)
1037		{
1038			/*
1039			 * New format: zero salt and then plain nt hash.
1040			 * Directly compare the hashes.
1041			 */
1042			if (memcmp(nt_pw, old_nt_pw_salted_md5_hash,
1043				   SALTED_MD5_HASH_LEN) == 0)
1044			{
1045				return true;
1046			}
1047		} else {
1048			/*
1049			 * Old format: md5sum of salted nt hash.
1050			 * Create salted version of new pw to compare.
1051			 */
1052			E_md5hash(current_salt, nt_pw, new_nt_pw_salted_md5_hash);
1053
1054			if (memcmp(new_nt_pw_salted_md5_hash,
1055				   old_nt_pw_salted_md5_hash,
1056				   SALTED_MD5_HASH_LEN) == 0) {
1057				return true;
1058			}
1059		}
1060	}
1061	return false;
1062}
1063
1064/***********************************************************
1065 This routine takes the given password and checks it against
1066 the password history. Returns True if this password has been
1067 found in the history list.
1068************************************************************/
1069
1070static bool check_passwd_history(struct samu *sampass, const char *plaintext)
1071{
1072	uchar new_nt_p16[NT_HASH_LEN];
1073	const uint8 *nt_pw;
1074	const uint8 *pwhistory;
1075	uint32 pwHisLen, curr_pwHisLen;
1076
1077	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen);
1078	if (pwHisLen == 0) {
1079		return False;
1080	}
1081
1082	pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1083	if (!pwhistory || curr_pwHisLen == 0) {
1084		return False;
1085	}
1086
1087	/* Only examine the minimum of the current history len and
1088	   the stored history len. Avoids race conditions. */
1089	pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1090
1091	nt_pw = pdb_get_nt_passwd(sampass);
1092
1093	E_md4hash(plaintext, new_nt_p16);
1094
1095	if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1096		DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1097			pdb_get_username(sampass) ));
1098		return True;
1099	}
1100
1101	if (password_in_history(new_nt_p16, pwHisLen, pwhistory)) {
1102		DEBUG(1,("check_passwd_history: proposed new password for "
1103			 "user %s found in history list !\n",
1104			 pdb_get_username(sampass) ));
1105		return true;
1106	}
1107	return false;
1108}
1109
1110/***********************************************************
1111 Code to change the oem password. Changes both the lanman
1112 and NT hashes.  Old_passwd is almost always NULL.
1113 NOTE this function is designed to be called as root. Check the old password
1114 is correct before calling. JRA.
1115************************************************************/
1116
1117NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1118{
1119	uint32 min_len;
1120	uint32 refuse;
1121	TALLOC_CTX *tosctx = talloc_tos();
1122	struct passwd *pass = NULL;
1123	const char *username = pdb_get_username(hnd);
1124	time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1125
1126	if (samr_reject_reason) {
1127		*samr_reject_reason = Undefined;
1128	}
1129
1130	/* check to see if the secdesc has previously been set to disallow */
1131	if (!pdb_get_pass_can_change(hnd)) {
1132		DEBUG(1, ("user %s does not have permissions to change password\n", username));
1133		if (samr_reject_reason) {
1134			*samr_reject_reason = SAMR_REJECT_OTHER;
1135		}
1136		return NT_STATUS_ACCOUNT_RESTRICTION;
1137	}
1138
1139	/* check to see if it is a Machine account and if the policy
1140	 * denies machines to change the password. *
1141	 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1142	if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1143		if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1144			DEBUG(1, ("Machine %s cannot change password now, "
1145				  "denied by Refuse Machine Password Change policy\n",
1146				  username));
1147			if (samr_reject_reason) {
1148				*samr_reject_reason = SAMR_REJECT_OTHER;
1149			}
1150			return NT_STATUS_ACCOUNT_RESTRICTION;
1151		}
1152	}
1153
1154	/* removed calculation here, because passdb now calculates
1155	   based on policy.  jmcd */
1156	if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1157		DEBUG(1, ("user %s cannot change password now, must "
1158			  "wait until %s\n", username,
1159			  http_timestring(tosctx, can_change_time)));
1160		if (samr_reject_reason) {
1161			*samr_reject_reason = SAMR_REJECT_OTHER;
1162		}
1163		return NT_STATUS_ACCOUNT_RESTRICTION;
1164	}
1165
1166	if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1167		DEBUG(1, ("user %s cannot change password - password too short\n",
1168			  username));
1169		DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1170		if (samr_reject_reason) {
1171			*samr_reject_reason = SAMR_REJECT_TOO_SHORT;
1172		}
1173		return NT_STATUS_PASSWORD_RESTRICTION;
1174/* 		return NT_STATUS_PWD_TOO_SHORT; */
1175	}
1176
1177	if (check_passwd_history(hnd,new_passwd)) {
1178		if (samr_reject_reason) {
1179			*samr_reject_reason = SAMR_REJECT_IN_HISTORY;
1180		}
1181		return NT_STATUS_PASSWORD_RESTRICTION;
1182	}
1183
1184	pass = Get_Pwnam_alloc(tosctx, username);
1185	if (!pass) {
1186		DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1187		return NT_STATUS_ACCESS_DENIED;
1188	}
1189
1190	/* Use external script to check password complexity */
1191	if (lp_check_password_script() && *(lp_check_password_script())) {
1192		int check_ret;
1193		char *cmd;
1194
1195		cmd = talloc_string_sub(tosctx, lp_check_password_script(), "%u", username);
1196        	if (!cmd) {
1197                	return NT_STATUS_PASSWORD_RESTRICTION;
1198        	}
1199
1200		check_ret = smbrunsecret(cmd, new_passwd);
1201		DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", cmd, check_ret));
1202		TALLOC_FREE(cmd);
1203
1204		if (check_ret != 0) {
1205			DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1206			if (samr_reject_reason) {
1207				*samr_reject_reason = SAMR_REJECT_COMPLEXITY;
1208			}
1209			TALLOC_FREE(pass);
1210			return NT_STATUS_PASSWORD_RESTRICTION;
1211		}
1212	}
1213
1214	/*
1215	 * If unix password sync was requested, attempt to change
1216	 * the /etc/passwd database first. Return failure if this cannot
1217	 * be done.
1218	 *
1219	 * This occurs before the oem change, because we don't want to
1220	 * update it if chgpasswd failed.
1221	 *
1222	 * Conditional on lp_unix_password_sync() because we don't want
1223	 * to touch the unix db unless we have admin permission.
1224	 */
1225
1226	if(lp_unix_password_sync() &&
1227		!chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1228		TALLOC_FREE(pass);
1229		return NT_STATUS_ACCESS_DENIED;
1230	}
1231
1232	TALLOC_FREE(pass);
1233
1234	if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1235		return NT_STATUS_ACCESS_DENIED;
1236	}
1237
1238	/* Now write it into the file. */
1239	return pdb_update_sam_account (hnd);
1240}
1241