2
Unix SMB/CIFS implementation.
3
Samba utility functions
4
Copyright (C) Andrew Tridgell 1992-1998
5
Copyright (C) Andrew Bartlett 2001-2004
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.
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.
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/>.
21
/* These comments regard the code to change the user's unix password: */
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.
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.
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.
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
50
extern struct passdb_ops pdb_ops;
52
static NTSTATUS check_oem_password(const char *user,
53
uchar password_encrypted_with_lm_hash[516],
54
const uchar old_lm_hash_encrypted[16],
55
uchar password_encrypted_with_nt_hash[516],
56
const uchar old_nt_hash_encrypted[16],
58
char **pp_new_passwd);
60
#if ALLOW_CHANGE_PASSWORD
62
static int findpty(char **slave)
66
SMB_STRUCT_DIR *dirp = NULL;
71
#if defined(HAVE_GRANTPT)
72
/* Try to open /dev/ptmx. If that fails, fall through to old method. */
73
if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
76
line = (char *)ptsname(master);
78
*slave = SMB_STRDUP(line);
83
("findpty: Unable to create master/slave pty pair.\n"));
84
/* Stop fd leak on error. */
89
("findpty: Allocated slave pty %s\n", *slave));
93
#endif /* HAVE_GRANTPT */
95
line = SMB_STRDUP("/dev/ptyXX");
100
dirp = sys_opendir("/dev");
106
while ((dpname = readdirname(dirp)) != NULL) {
107
if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
109
("pty: try to open %s, line was %s\n", dpname,
113
if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
114
DEBUG(3, ("pty: opened %s\n", line));
127
static int dochild(int master, const char *slavedev, const struct passwd *pass,
128
const char *passwordprogram, bool as_root)
131
struct termios stermios;
134
char * const eptrs[1] = { NULL };
139
("dochild: user doesn't exist in the UNIX password database.\n"));
146
gain_root_privilege();
148
/* Start new session - gets rid of controlling terminal. */
152
("Weirdness, couldn't let go of controlling terminal\n"));
156
/* Open slave pty and acquire as new controlling terminal. */
157
if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
159
DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
162
#if defined(TIOCSCTTY) && !defined(SUNOS5)
164
* On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
165
* see the discussion under
166
* https://bugzilla.samba.org/show_bug.cgi?id=5366.
168
if (ioctl(slave, TIOCSCTTY, 0) < 0)
170
DEBUG(3, ("Error in ioctl call for slave pty\n"));
173
#elif defined(I_PUSH) && defined(I_FIND)
174
if (ioctl(slave, I_FIND, "ptem") == 0) {
175
ioctl(slave, I_PUSH, "ptem");
177
if (ioctl(slave, I_FIND, "ldterm") == 0) {
178
ioctl(slave, I_PUSH, "ldterm");
185
/* Make slave stdin/out/err of child. */
187
if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
189
DEBUG(3, ("Could not re-direct stdin\n"));
192
if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
194
DEBUG(3, ("Could not re-direct stdout\n"));
197
if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
199
DEBUG(3, ("Could not re-direct stderr\n"));
205
/* Set proper terminal attributes - no echo, canonical input processing,
206
no map NL to CR/NL on output. */
208
if (tcgetattr(0, &stermios) < 0)
211
("could not read default terminal attributes on pty\n"));
214
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
215
stermios.c_lflag |= ICANON;
217
stermios.c_oflag &= ~(ONLCR);
219
if (tcsetattr(0, TCSANOW, &stermios) < 0)
221
DEBUG(3, ("could not set attributes of pty\n"));
225
/* make us completely into the right uid */
228
become_user_permanently(uid, gid);
232
("Invoking '%s' as password change program.\n",
235
/* execl() password-change application */
236
if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
238
DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
244
static int expect(int master, char *issue, char *expected)
247
int attempts, timeout, nread;
251
for (attempts = 0; attempts < 2; attempts++) {
253
if (!strequal(issue, ".")) {
254
if (lp_passwd_chat_debug())
255
DEBUG(100, ("expect: sending [%s]\n", issue));
257
if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
258
DEBUG(2,("expect: (short) write returned %d\n",
264
if (strequal(expected, "."))
267
/* Initial timeout. */
268
timeout = lp_passwd_chat_timeout() * 1000;
273
status = read_socket_with_timeout(
274
master, buffer + nread, 1,
275
sizeof(buffer) - nread - 1,
278
if (!NT_STATUS_IS_OK(status)) {
285
/* Eat leading/trailing whitespace before match. */
286
char *str = SMB_STRDUP(buffer);
288
DEBUG(2,("expect: ENOMEM\n"));
291
trim_char(str, ' ', ' ');
293
if ((match = unix_wild_match(expected, str)) == True) {
294
/* Now data has started to return, lower timeout. */
295
timeout = lp_passwd_chat_timeout() * 100;
301
if (lp_passwd_chat_debug())
302
DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
303
expected, buffer, match ? "yes" : "no" ));
308
if (!NT_STATUS_IS_OK(status)) {
309
DEBUG(2, ("expect: %s\n", nt_errstr(status)));
314
DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
318
static void pwd_sub(char *buf)
320
all_string_sub(buf, "\\n", "\n", 0);
321
all_string_sub(buf, "\\r", "\r", 0);
322
all_string_sub(buf, "\\s", " ", 0);
323
all_string_sub(buf, "\\t", "\t", 0);
326
static int talktochild(int master, const char *seq)
328
TALLOC_CTX *frame = talloc_stackframe();
333
issue = talloc_strdup(frame, ".");
339
while (next_token_talloc(frame, &seq, &expected, NULL)) {
343
if (!expect(master, issue, expected)) {
344
DEBUG(3, ("Response %d incorrect\n", count));
349
if (!next_token_talloc(frame, &seq, &issue, NULL)) {
350
issue = talloc_strdup(frame, ".");
359
if (!strequal(issue, ".")) {
360
/* we have one final issue to send */
361
expected = talloc_strdup(frame, ".");
366
if (!expect(master, issue, expected)) {
375
static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
376
char *chatsequence, bool as_root)
378
char *slavedev = NULL;
385
DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
389
/* allocate a pseudo-terminal device */
390
if ((master = findpty(&slavedev)) < 0) {
391
DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
396
* We need to temporarily stop CatchChild from eating
397
* SIGCLD signals as it also eats the exit status code. JRA.
400
CatchChildLeaveStatus();
402
if ((pid = sys_fork()) < 0) {
403
DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
410
/* we now have a pty */
411
if (pid > 0) { /* This is the parent process */
412
/* Don't need this anymore in parent. */
415
if ((chstat = talktochild(master, chatsequence)) == False) {
416
DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
417
kill(pid, SIGKILL); /* be sure to end this process */
420
while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
421
if (errno == EINTR) {
429
DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
436
* Go back to ignoring children.
443
DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
446
if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
447
DEBUG(3, ("chat_with_program: The process exited with status %d \
448
while we were waiting\n", WEXITSTATUS(wstat)));
451
#if defined(WIFSIGNALLED) && defined(WTERMSIG)
452
else if (WIFSIGNALLED(wstat)) {
453
DEBUG(3, ("chat_with_program: The process was killed by signal %d \
454
while we were waiting\n", WTERMSIG(wstat)));
462
* Lose any elevated privileges.
464
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
465
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
467
/* make sure it doesn't freeze */
473
DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
474
(int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
475
chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
481
* The child should never return from dochild() ....
484
DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
489
DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
490
(chstat ? "" : "un"), pass->pw_name));
494
bool chgpasswd(const char *name, const struct passwd *pass,
495
const char *oldpass, const char *newpass, bool as_root)
497
char *passwordprogram = NULL;
498
char *chatsequence = NULL;
501
TALLOC_CTX *ctx = talloc_tos();
507
DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
509
#ifdef DEBUG_PASSWORD
510
DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
513
/* Take the passed information and test it for minimum criteria */
515
/* Password is same as old password */
516
if (strcmp(oldpass, newpass) == 0) {
517
/* don't allow same password */
518
DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */
519
return (False); /* inform the user */
523
* Check the old and new passwords don't contain any control
527
len = strlen(oldpass);
528
for (i = 0; i < len; i++) {
529
if (iscntrl((int)oldpass[i])) {
530
DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
535
len = strlen(newpass);
536
for (i = 0; i < len; i++) {
537
if (iscntrl((int)newpass[i])) {
538
DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
544
if (lp_pam_password_change()) {
546
#ifdef HAVE_SETLOCALE
547
const char *prevlocale = setlocale(LC_ALL, "C");
554
ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
556
ret = smb_pam_passchange(name, oldpass, newpass);
562
#ifdef HAVE_SETLOCALE
563
setlocale(LC_ALL, prevlocale);
570
/* A non-PAM password change just doen't make sense without a valid local user */
573
DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
577
passwordprogram = talloc_strdup(ctx, lp_passwd_program());
578
if (!passwordprogram || !*passwordprogram) {
579
DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
582
chatsequence = talloc_strdup(ctx, lp_passwd_chat());
583
if (!chatsequence || !*chatsequence) {
584
DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
589
/* The password program *must* contain the user name to work. Fail if not. */
590
if (strstr_m(passwordprogram, "%u") == NULL) {
591
DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
592
the string %%u, and the given string %s does not.\n", passwordprogram ));
597
passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
598
if (!passwordprogram) {
602
/* note that we do NOT substitute the %o and %n in the password program
603
as this would open up a security hole where the user could use
604
a new password containing shell escape characters */
606
chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
610
chatsequence = talloc_all_string_sub(ctx,
617
chatsequence = talloc_all_string_sub(ctx,
621
return chat_with_program(passwordprogram,
627
#else /* ALLOW_CHANGE_PASSWORD */
629
bool chgpasswd(const char *name, const struct passwd *pass,
630
const char *oldpass, const char *newpass, bool as_root)
632
DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
635
#endif /* ALLOW_CHANGE_PASSWORD */
637
/***********************************************************
638
Code to check the lanman hashed password.
639
************************************************************/
641
bool check_lanman_password(char *user, uchar * pass1,
642
uchar * pass2, struct samu **hnd)
644
uchar unenc_new_pw[16];
645
uchar unenc_old_pw[16];
646
struct samu *sampass = NULL;
648
const uint8 *lanman_pw;
651
if ( !(sampass = samu_new(NULL)) ) {
652
DEBUG(0, ("samu_new() failed!\n"));
657
ret = pdb_getsampwnam(sampass, user);
661
DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
662
TALLOC_FREE(sampass);
666
acct_ctrl = pdb_get_acct_ctrl (sampass);
667
lanman_pw = pdb_get_lanman_passwd (sampass);
669
if (acct_ctrl & ACB_DISABLED) {
670
DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
671
TALLOC_FREE(sampass);
675
if (lanman_pw == NULL) {
676
if (acct_ctrl & ACB_PWNOTREQ) {
677
/* this saves the pointer for the caller */
681
DEBUG(0, ("check_lanman_password: no lanman password !\n"));
682
TALLOC_FREE(sampass);
687
/* Get the new lanman hash. */
688
D_P16(lanman_pw, pass2, unenc_new_pw);
690
/* Use this to get the old lanman hash. */
691
D_P16(unenc_new_pw, pass1, unenc_old_pw);
693
/* Check that the two old passwords match. */
694
if (memcmp(lanman_pw, unenc_old_pw, 16)) {
695
DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
696
TALLOC_FREE(sampass);
700
/* this saves the pointer for the caller */
705
/***********************************************************
706
Code to change the lanman hashed password.
707
It nulls out the NT hashed password as it will
709
NOTE this function is designed to be called as root. Check the old password
710
is correct before calling. JRA.
711
************************************************************/
713
bool change_lanman_password(struct samu *sampass, uchar *pass2)
715
static uchar null_pw[16];
716
uchar unenc_new_pw[16];
721
if (sampass == NULL) {
722
DEBUG(0,("change_lanman_password: no smb password entry.\n"));
726
acct_ctrl = pdb_get_acct_ctrl(sampass);
727
pwd = pdb_get_lanman_passwd(sampass);
729
if (acct_ctrl & ACB_DISABLED) {
730
DEBUG(0,("change_lanman_password: account %s disabled.\n",
731
pdb_get_username(sampass)));
736
if (acct_ctrl & ACB_PWNOTREQ) {
738
memset(no_pw, '\0', 14);
739
E_P16(no_pw, null_pw);
741
/* Get the new lanman hash. */
742
D_P16(null_pw, pass2, unenc_new_pw);
744
DEBUG(0,("change_lanman_password: no lanman password !\n"));
748
/* Get the new lanman hash. */
749
D_P16(pwd, pass2, unenc_new_pw);
752
if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
756
if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
757
return False; /* We lose the NT hash. Sorry. */
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 */
766
/* Now flush the sam_passwd struct to persistent storage */
767
ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
772
/***********************************************************
773
Code to check and change the OEM hashed password.
774
************************************************************/
776
NTSTATUS 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)
783
char *new_passwd = NULL;
784
struct samu *sampass = NULL;
785
NTSTATUS nt_status = check_oem_password(user,
786
password_encrypted_with_lm_hash,
787
old_lm_hash_encrypted,
788
password_encrypted_with_nt_hash,
789
old_nt_hash_encrypted,
793
if (!NT_STATUS_IS_OK(nt_status)) {
797
/* We've already checked the old password here.... */
799
nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
802
memset(new_passwd, 0, strlen(new_passwd));
804
TALLOC_FREE(sampass);
809
/***********************************************************
810
Decrypt and verify a user password change.
812
The 516 byte long buffers are encrypted with the old NT and
813
old LM passwords, and if the NT passwords are present, both
814
buffers contain a unicode string.
816
After decrypting the buffers, check the password is correct by
817
matching the old hashed passwords with the passwords in the passdb.
819
************************************************************/
821
static NTSTATUS check_oem_password(const char *user,
822
uchar password_encrypted_with_lm_hash[516],
823
const uchar old_lm_hash_encrypted[16],
824
uchar password_encrypted_with_nt_hash[516],
825
const uchar old_nt_hash_encrypted[16],
827
char **pp_new_passwd)
829
static uchar null_pw[16];
830
static uchar null_ntpw[16];
831
struct samu *sampass = NULL;
832
uint8 *password_encrypted;
833
const uint8 *encryption_key;
834
const uint8 *lanman_pw, *nt_pw;
837
uchar new_nt_hash[16];
838
uchar new_lm_hash[16];
843
bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
844
bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
848
if ( !(sampass = samu_new( NULL )) ) {
849
return NT_STATUS_NO_MEMORY;
853
ret = pdb_getsampwnam(sampass, user);
857
DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
858
TALLOC_FREE(sampass);
859
return NT_STATUS_NO_SUCH_USER;
862
acct_ctrl = pdb_get_acct_ctrl(sampass);
864
if (acct_ctrl & ACB_DISABLED) {
865
DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
866
TALLOC_FREE(sampass);
867
return NT_STATUS_ACCOUNT_DISABLED;
870
if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
871
/* construct a null password (in case one is needed */
874
nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
879
/* save pointers to passwords so we don't have to keep looking them up */
880
if (lp_lanman_auth()) {
881
lanman_pw = pdb_get_lanman_passwd(sampass);
885
nt_pw = pdb_get_nt_passwd(sampass);
888
if (nt_pw && nt_pass_set) {
889
/* IDEAL Case: passwords are in unicode, and we can
890
* read use the password encrypted with the NT hash
892
password_encrypted = password_encrypted_with_nt_hash;
893
encryption_key = nt_pw;
894
} else if (lanman_pw && lm_pass_set) {
895
/* password may still be in unicode, but use LM hash version */
896
password_encrypted = password_encrypted_with_lm_hash;
897
encryption_key = lanman_pw;
898
} else if (nt_pass_set) {
899
DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
901
TALLOC_FREE(sampass);
902
return NT_STATUS_WRONG_PASSWORD;
903
} else if (lm_pass_set) {
904
if (lp_lanman_auth()) {
905
DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
908
DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
911
TALLOC_FREE(sampass);
912
return NT_STATUS_WRONG_PASSWORD;
914
DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
916
TALLOC_FREE(sampass);
917
return NT_STATUS_WRONG_PASSWORD;
921
* Decrypt the password with the key
923
SamOEMhash( password_encrypted, encryption_key, 516);
925
if (!decode_pw_buffer(talloc_tos(),
929
nt_pass_set ? STR_UNICODE : STR_ASCII)) {
930
TALLOC_FREE(sampass);
931
return NT_STATUS_WRONG_PASSWORD;
935
* To ensure we got the correct new password, hash it and
936
* use it as a key to test the passed old password.
940
/* NT passwords, verify the NT hash. */
942
/* Calculate the MD4 hash (NT compatible) of the password */
943
memset(new_nt_hash, '\0', 16);
944
E_md4hash(*pp_new_passwd, new_nt_hash);
948
* check the NT verifier
950
E_old_pw_hash(new_nt_hash, nt_pw, verifier);
951
if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
952
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
953
TALLOC_FREE(sampass);
954
return NT_STATUS_WRONG_PASSWORD;
957
/* We could check the LM password here, but there is
958
* little point, we already know the password is
959
* correct, and the LM password might not even be
962
/* Further, LM hash generation algorithms
963
* differ with charset, so we could
964
* incorrectly fail a perfectly valid password
966
#ifdef DEBUG_PASSWORD
968
("check_oem_password: password %s ok\n", *pp_new_passwd));
976
* check the lm verifier
978
E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
979
if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
980
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
981
TALLOC_FREE(sampass);
982
return NT_STATUS_WRONG_PASSWORD;
984
#ifdef DEBUG_PASSWORD
986
("check_oem_password: password %s ok\n", *pp_new_passwd));
993
if (lanman_pw && lm_pass_set) {
995
E_deshash(*pp_new_passwd, new_lm_hash);
998
* check the lm verifier
1000
E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
1001
if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
1002
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
1003
TALLOC_FREE(sampass);
1004
return NT_STATUS_WRONG_PASSWORD;
1007
#ifdef DEBUG_PASSWORD
1009
("check_oem_password: password %s ok\n", *pp_new_passwd));
1012
return NT_STATUS_OK;
1015
/* should not be reached */
1016
TALLOC_FREE(sampass);
1017
return NT_STATUS_WRONG_PASSWORD;
1020
/***********************************************************
1021
This routine takes the given password and checks it against
1022
the password history. Returns True if this password has been
1023
found in the history list.
1024
************************************************************/
1026
static bool check_passwd_history(struct samu *sampass, const char *plaintext)
1028
uchar new_nt_p16[NT_HASH_LEN];
1029
uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
1031
const uint8 *pwhistory;
1034
uint32 pwHisLen, curr_pwHisLen;
1036
pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
1037
if (pwHisLen == 0) {
1041
pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1042
if (!pwhistory || curr_pwHisLen == 0) {
1046
/* Only examine the minimum of the current history len and
1047
the stored history len. Avoids race conditions. */
1048
pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1050
nt_pw = pdb_get_nt_passwd(sampass);
1052
E_md4hash(plaintext, new_nt_p16);
1054
if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1055
DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1056
pdb_get_username(sampass) ));
1060
dump_data(100, new_nt_p16, NT_HASH_LEN);
1061
dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
1063
memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
1064
for (i=0; i<pwHisLen; i++) {
1065
uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1066
const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
1067
const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
1068
PW_HISTORY_SALT_LEN];
1069
if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1070
/* Ignore zero valued entries. */
1073
/* Create salted versions of new to compare. */
1074
E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
1076
if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1077
DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1078
pdb_get_username(sampass) ));
1086
/***********************************************************
1087
Code to change the oem password. Changes both the lanman
1088
and NT hashes. Old_passwd is almost always NULL.
1089
NOTE this function is designed to be called as root. Check the old password
1090
is correct before calling. JRA.
1091
************************************************************/
1093
NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1097
struct passwd *pass = NULL;
1098
const char *username = pdb_get_username(hnd);
1099
time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1101
if (samr_reject_reason) {
1102
*samr_reject_reason = Undefined;
1105
/* check to see if the secdesc has previously been set to disallow */
1106
if (!pdb_get_pass_can_change(hnd)) {
1107
DEBUG(1, ("user %s does not have permissions to change password\n", username));
1108
if (samr_reject_reason) {
1109
*samr_reject_reason = SAMR_REJECT_OTHER;
1111
return NT_STATUS_ACCOUNT_RESTRICTION;
1114
/* check to see if it is a Machine account and if the policy
1115
* denies machines to change the password. *
1116
* Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1117
if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1118
if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1119
DEBUG(1, ("Machine %s cannot change password now, "
1120
"denied by Refuse Machine Password Change policy\n",
1122
if (samr_reject_reason) {
1123
*samr_reject_reason = SAMR_REJECT_OTHER;
1125
return NT_STATUS_ACCOUNT_RESTRICTION;
1129
/* removed calculation here, becuase passdb now calculates
1130
based on policy. jmcd */
1131
if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1132
DEBUG(1, ("user %s cannot change password now, must "
1133
"wait until %s\n", username,
1134
http_timestring(can_change_time)));
1135
if (samr_reject_reason) {
1136
*samr_reject_reason = SAMR_REJECT_OTHER;
1138
return NT_STATUS_ACCOUNT_RESTRICTION;
1141
if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1142
DEBUG(1, ("user %s cannot change password - password too short\n",
1144
DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1145
if (samr_reject_reason) {
1146
*samr_reject_reason = SAMR_REJECT_TOO_SHORT;
1148
return NT_STATUS_PASSWORD_RESTRICTION;
1149
/* return NT_STATUS_PWD_TOO_SHORT; */
1152
if (check_passwd_history(hnd,new_passwd)) {
1153
if (samr_reject_reason) {
1154
*samr_reject_reason = SAMR_REJECT_IN_HISTORY;
1156
return NT_STATUS_PASSWORD_RESTRICTION;
1159
pass = Get_Pwnam_alloc(talloc_tos(), username);
1161
DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1162
return NT_STATUS_ACCESS_DENIED;
1165
/* Use external script to check password complexity */
1166
if (lp_check_password_script() && *(lp_check_password_script())) {
1169
check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
1170
DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
1172
if (check_ret != 0) {
1173
DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1174
if (samr_reject_reason) {
1175
*samr_reject_reason = SAMR_REJECT_COMPLEXITY;
1178
return NT_STATUS_PASSWORD_RESTRICTION;
1183
* If unix password sync was requested, attempt to change
1184
* the /etc/passwd database first. Return failure if this cannot
1187
* This occurs before the oem change, because we don't want to
1188
* update it if chgpasswd failed.
1190
* Conditional on lp_unix_password_sync() because we don't want
1191
* to touch the unix db unless we have admin permission.
1194
if(lp_unix_password_sync() &&
1195
!chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1197
return NT_STATUS_ACCESS_DENIED;
1202
if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1203
return NT_STATUS_ACCESS_DENIED;
1206
/* Now write it into the file. */
1207
return pdb_update_sam_account (hnd);