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