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