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