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