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