s3-samr: rework check_oem_password() to take a struct samu, not to return one.
[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_socket_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                          uint32 *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
864         if (acct_ctrl & ACB_DISABLED) {
865                 DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
866                 return NT_STATUS_ACCOUNT_DISABLED;
867         }
868
869         if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
870                 /* construct a null password (in case one is needed */
871                 no_pw[0] = 0;
872                 no_pw[1] = 0;
873                 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
874                 lanman_pw = null_pw;
875                 nt_pw = null_pw;
876
877         } else {
878                 /* save pointers to passwords so we don't have to keep looking them up */
879                 if (lp_lanman_auth()) {
880                         lanman_pw = pdb_get_lanman_passwd(sampass);
881                 } else {
882                         lanman_pw = NULL;
883                 }
884                 nt_pw = pdb_get_nt_passwd(sampass);
885         }
886
887         if (nt_pw && nt_pass_set) {
888                 /* IDEAL Case: passwords are in unicode, and we can
889                  * read use the password encrypted with the NT hash
890                  */
891                 password_encrypted = password_encrypted_with_nt_hash;
892                 encryption_key = nt_pw;
893         } else if (lanman_pw && lm_pass_set) {
894                 /* password may still be in unicode, but use LM hash version */
895                 password_encrypted = password_encrypted_with_lm_hash;
896                 encryption_key = lanman_pw;
897         } else if (nt_pass_set) {
898                 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", 
899                           user));
900                 return NT_STATUS_WRONG_PASSWORD;
901         } else if (lm_pass_set) {
902                 if (lp_lanman_auth()) {
903                         DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", 
904                                   user));
905                 } else {
906                         DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", 
907                                   user));
908                 }
909                 return NT_STATUS_WRONG_PASSWORD;
910         } else {
911                 DEBUG(1, ("password change requested for user %s, but no password supplied!\n", 
912                           user));
913                 return NT_STATUS_WRONG_PASSWORD;
914         }
915
916         /*
917          * Decrypt the password with the key
918          */
919         arcfour_crypt( password_encrypted, encryption_key, 516);
920
921         if (!decode_pw_buffer(talloc_tos(),
922                                 password_encrypted,
923                                 pp_new_passwd,
924                                 &new_pw_len,
925                                 nt_pass_set ? CH_UTF16 : CH_DOS)) {
926                 return NT_STATUS_WRONG_PASSWORD;
927         }
928
929         /*
930          * To ensure we got the correct new password, hash it and
931          * use it as a key to test the passed old password.
932          */
933
934         if (nt_pass_set) {
935                 /* NT passwords, verify the NT hash. */
936
937                 /* Calculate the MD4 hash (NT compatible) of the password */
938                 memset(new_nt_hash, '\0', 16);
939                 E_md4hash(*pp_new_passwd, new_nt_hash);
940
941                 if (nt_pw) {
942                         /*
943                          * check the NT verifier
944                          */
945                         E_old_pw_hash(new_nt_hash, nt_pw, verifier);
946                         if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
947                                 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
948                                 return NT_STATUS_WRONG_PASSWORD;
949                         }
950
951                         /* We could check the LM password here, but there is
952                          * little point, we already know the password is
953                          * correct, and the LM password might not even be
954                          * present. */
955
956                         /* Further, LM hash generation algorithms
957                          * differ with charset, so we could
958                          * incorrectly fail a perfectly valid password
959                          * change */
960 #ifdef DEBUG_PASSWORD
961                         DEBUG(100,
962                               ("check_oem_password: password %s ok\n", *pp_new_passwd));
963 #endif
964                         return NT_STATUS_OK;
965                 }
966
967                 if (lanman_pw) {
968                         /*
969                          * check the lm verifier
970                          */
971                         E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
972                         if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
973                                 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
974                                 return NT_STATUS_WRONG_PASSWORD;
975                         }
976 #ifdef DEBUG_PASSWORD
977                         DEBUG(100,
978                               ("check_oem_password: password %s ok\n", *pp_new_passwd));
979 #endif
980                         return NT_STATUS_OK;
981                 }
982         }
983
984         if (lanman_pw && lm_pass_set) {
985
986                 E_deshash(*pp_new_passwd, new_lm_hash);
987
988                 /*
989                  * check the lm verifier
990                  */
991                 E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
992                 if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
993                         DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
994                         return NT_STATUS_WRONG_PASSWORD;
995                 }
996
997 #ifdef DEBUG_PASSWORD
998                 DEBUG(100,
999                       ("check_oem_password: password %s ok\n", *pp_new_passwd));
1000 #endif
1001                 return NT_STATUS_OK;
1002         }
1003
1004         /* should not be reached */
1005         return NT_STATUS_WRONG_PASSWORD;
1006 }
1007
1008 /***********************************************************
1009  This routine takes the given password and checks it against
1010  the password history. Returns True if this password has been
1011  found in the history list.
1012 ************************************************************/
1013
1014 static bool check_passwd_history(struct samu *sampass, const char *plaintext)
1015 {
1016         uchar new_nt_p16[NT_HASH_LEN];
1017         uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
1018         const uint8 *nt_pw;
1019         const uint8 *pwhistory;
1020         bool found = False;
1021         int i;
1022         uint32 pwHisLen, curr_pwHisLen;
1023
1024         pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
1025         if (pwHisLen == 0) {
1026                 return False;
1027         }
1028
1029         pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1030         if (!pwhistory || curr_pwHisLen == 0) {
1031                 return False;
1032         }
1033
1034         /* Only examine the minimum of the current history len and
1035            the stored history len. Avoids race conditions. */
1036         pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1037
1038         nt_pw = pdb_get_nt_passwd(sampass);
1039
1040         E_md4hash(plaintext, new_nt_p16);
1041
1042         if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1043                 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1044                         pdb_get_username(sampass) ));
1045                 return True;
1046         }
1047
1048         dump_data(100, new_nt_p16, NT_HASH_LEN);
1049         dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
1050
1051         memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
1052         for (i=0; i<pwHisLen; i++) {
1053                 uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1054                 const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
1055                 const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
1056                                                         PW_HISTORY_SALT_LEN];
1057                 if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1058                         /* Ignore zero valued entries. */
1059                         continue;
1060                 }
1061                 /* Create salted versions of new to compare. */
1062                 E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
1063
1064                 if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1065                         DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1066                                 pdb_get_username(sampass) ));
1067                         found = True;
1068                         break;
1069                 }
1070         }
1071         return found;
1072 }
1073
1074 /***********************************************************
1075  Code to change the oem password. Changes both the lanman
1076  and NT hashes.  Old_passwd is almost always NULL.
1077  NOTE this function is designed to be called as root. Check the old password
1078  is correct before calling. JRA.
1079 ************************************************************/
1080
1081 NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1082 {
1083         uint32 min_len;
1084         uint32 refuse;
1085         struct passwd *pass = NULL;
1086         const char *username = pdb_get_username(hnd);
1087         time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1088
1089         if (samr_reject_reason) {
1090                 *samr_reject_reason = Undefined;
1091         }
1092
1093         /* check to see if the secdesc has previously been set to disallow */
1094         if (!pdb_get_pass_can_change(hnd)) {
1095                 DEBUG(1, ("user %s does not have permissions to change password\n", username));
1096                 if (samr_reject_reason) {
1097                         *samr_reject_reason = SAMR_REJECT_OTHER;
1098                 }
1099                 return NT_STATUS_ACCOUNT_RESTRICTION;
1100         }
1101
1102         /* check to see if it is a Machine account and if the policy
1103          * denies machines to change the password. *
1104          * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1105         if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1106                 if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1107                         DEBUG(1, ("Machine %s cannot change password now, "
1108                                   "denied by Refuse Machine Password Change policy\n",
1109                                   username));
1110                         if (samr_reject_reason) {
1111                                 *samr_reject_reason = SAMR_REJECT_OTHER;
1112                         }
1113                         return NT_STATUS_ACCOUNT_RESTRICTION;
1114                 }
1115         }
1116
1117         /* removed calculation here, becuase passdb now calculates
1118            based on policy.  jmcd */
1119         if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1120                 DEBUG(1, ("user %s cannot change password now, must "
1121                           "wait until %s\n", username,
1122                           http_timestring(talloc_tos(), can_change_time)));
1123                 if (samr_reject_reason) {
1124                         *samr_reject_reason = SAMR_REJECT_OTHER;
1125                 }
1126                 return NT_STATUS_ACCOUNT_RESTRICTION;
1127         }
1128
1129         if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1130                 DEBUG(1, ("user %s cannot change password - password too short\n", 
1131                           username));
1132                 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1133                 if (samr_reject_reason) {
1134                         *samr_reject_reason = SAMR_REJECT_TOO_SHORT;
1135                 }
1136                 return NT_STATUS_PASSWORD_RESTRICTION;
1137 /*              return NT_STATUS_PWD_TOO_SHORT; */
1138         }
1139
1140         if (check_passwd_history(hnd,new_passwd)) {
1141                 if (samr_reject_reason) {
1142                         *samr_reject_reason = SAMR_REJECT_IN_HISTORY;
1143                 }
1144                 return NT_STATUS_PASSWORD_RESTRICTION;
1145         }
1146
1147         pass = Get_Pwnam_alloc(talloc_tos(), username);
1148         if (!pass) {
1149                 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1150                 return NT_STATUS_ACCESS_DENIED;
1151         }
1152
1153         /* Use external script to check password complexity */
1154         if (lp_check_password_script() && *(lp_check_password_script())) {
1155                 int check_ret;
1156
1157                 check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
1158                 DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
1159
1160                 if (check_ret != 0) {
1161                         DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1162                         if (samr_reject_reason) {
1163                                 *samr_reject_reason = SAMR_REJECT_COMPLEXITY;
1164                         }
1165                         TALLOC_FREE(pass);
1166                         return NT_STATUS_PASSWORD_RESTRICTION;
1167                 }
1168         }
1169
1170         /*
1171          * If unix password sync was requested, attempt to change
1172          * the /etc/passwd database first. Return failure if this cannot
1173          * be done.
1174          *
1175          * This occurs before the oem change, because we don't want to
1176          * update it if chgpasswd failed.
1177          *
1178          * Conditional on lp_unix_password_sync() because we don't want
1179          * to touch the unix db unless we have admin permission.
1180          */
1181         
1182         if(lp_unix_password_sync() &&
1183                 !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1184                 TALLOC_FREE(pass);
1185                 return NT_STATUS_ACCESS_DENIED;
1186         }
1187
1188         TALLOC_FREE(pass);
1189
1190         if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1191                 return NT_STATUS_ACCESS_DENIED;
1192         }
1193
1194         /* Now write it into the file. */
1195         return pdb_update_sam_account (hnd);
1196 }