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