1/* 2 Unix SMB/CIFS implementation. 3 Password checking 4 Copyright (C) Andrew Tridgell 1992-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21/* this module is for checking a username/password against a system 22 password database. The SMB encrypted password support is elsewhere */ 23 24#include "includes.h" 25 26#undef DBGC_CLASS 27#define DBGC_CLASS DBGC_AUTH 28 29/* these are kept here to keep the string_combinations function simple */ 30static fstring this_user; 31#if !defined(WITH_PAM) 32static fstring this_salt; 33static fstring this_crypted; 34#endif 35 36#ifdef WITH_AFS 37 38#include <afs/stds.h> 39#include <afs/kautils.h> 40 41/******************************************************************* 42check on AFS authentication 43********************************************************************/ 44static BOOL afs_auth(char *user, char *password) 45{ 46 long password_expires = 0; 47 char *reason; 48 49 /* For versions of AFS prior to 3.3, this routine has few arguments, */ 50 /* but since I can't find the old documentation... :-) */ 51 setpag(); 52 if (ka_UserAuthenticateGeneral 53 (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */ 54 (char *)0, /* cell */ 55 password, 0, /* lifetime, default */ 56 &password_expires, /*days 'til it expires */ 57 0, /* spare 2 */ 58 &reason) == 0) 59 { 60 return (True); 61 } 62 DEBUG(1, 63 ("AFS authentication for \"%s\" failed (%s)\n", user, reason)); 64 return (False); 65} 66#endif 67 68 69#ifdef WITH_DFS 70 71#include <dce/dce_error.h> 72#include <dce/sec_login.h> 73 74/***************************************************************** 75 This new version of the DFS_AUTH code was donated by Karsten Muuss 76 <muuss@or.uni-bonn.de>. It fixes the following problems with the 77 old code : 78 79 - Server credentials may expire 80 - Client credential cache files have wrong owner 81 - purge_context() function is called with invalid argument 82 83 This new code was modified to ensure that on exit the uid/gid is 84 still root, and the original directory is restored. JRA. 85******************************************************************/ 86 87sec_login_handle_t my_dce_sec_context; 88int dcelogin_atmost_once = 0; 89 90/******************************************************************* 91check on a DCE/DFS authentication 92********************************************************************/ 93static BOOL dfs_auth(char *user, char *password) 94{ 95 error_status_t err; 96 int err2; 97 int prterr; 98 signed32 expire_time, current_time; 99 boolean32 password_reset; 100 struct passwd *pw; 101 sec_passwd_rec_t passwd_rec; 102 sec_login_auth_src_t auth_src = sec_login_auth_src_network; 103 unsigned char dce_errstr[dce_c_error_string_len]; 104 gid_t egid; 105 106 if (dcelogin_atmost_once) 107 return (False); 108 109#ifdef HAVE_CRYPT 110 /* 111 * We only go for a DCE login context if the given password 112 * matches that stored in the local password file.. 113 * Assumes local passwd file is kept in sync w/ DCE RGY! 114 */ 115 116 if (strcmp((char *)crypt(password, this_salt), this_crypted)) 117 { 118 return (False); 119 } 120#endif 121 122 sec_login_get_current_context(&my_dce_sec_context, &err); 123 if (err != error_status_ok) 124 { 125 dce_error_inq_text(err, dce_errstr, &err2); 126 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); 127 128 return (False); 129 } 130 131 sec_login_certify_identity(my_dce_sec_context, &err); 132 if (err != error_status_ok) 133 { 134 dce_error_inq_text(err, dce_errstr, &err2); 135 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); 136 137 return (False); 138 } 139 140 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); 141 if (err != error_status_ok) 142 { 143 dce_error_inq_text(err, dce_errstr, &err2); 144 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); 145 146 return (False); 147 } 148 149 time(¤t_time); 150 151 if (expire_time < (current_time + 60)) 152 { 153 struct passwd *pw; 154 sec_passwd_rec_t *key; 155 156 sec_login_get_pwent(my_dce_sec_context, 157 (sec_login_passwd_t *) & pw, &err); 158 if (err != error_status_ok) 159 { 160 dce_error_inq_text(err, dce_errstr, &err2); 161 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); 162 163 return (False); 164 } 165 166 sec_login_refresh_identity(my_dce_sec_context, &err); 167 if (err != error_status_ok) 168 { 169 dce_error_inq_text(err, dce_errstr, &err2); 170 DEBUG(0, ("DCE can't refresh identity. %s\n", 171 dce_errstr)); 172 173 return (False); 174 } 175 176 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL, 177 (unsigned char *)pw->pw_name, 178 sec_c_key_version_none, 179 (void **)&key, &err); 180 if (err != error_status_ok) 181 { 182 dce_error_inq_text(err, dce_errstr, &err2); 183 DEBUG(0, ("DCE can't get key for %s. %s\n", 184 pw->pw_name, dce_errstr)); 185 186 return (False); 187 } 188 189 sec_login_valid_and_cert_ident(my_dce_sec_context, key, 190 &password_reset, &auth_src, 191 &err); 192 if (err != error_status_ok) 193 { 194 dce_error_inq_text(err, dce_errstr, &err2); 195 DEBUG(0, 196 ("DCE can't validate and certify identity for %s. %s\n", 197 pw->pw_name, dce_errstr)); 198 } 199 200 sec_key_mgmt_free_key(key, &err); 201 if (err != error_status_ok) 202 { 203 dce_error_inq_text(err, dce_errstr, &err2); 204 DEBUG(0, ("DCE can't free key.\n", dce_errstr)); 205 } 206 } 207 208 if (sec_login_setup_identity((unsigned char *)user, 209 sec_login_no_flags, 210 &my_dce_sec_context, &err) == 0) 211 { 212 dce_error_inq_text(err, dce_errstr, &err2); 213 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", 214 user, dce_errstr)); 215 return (False); 216 } 217 218 sec_login_get_pwent(my_dce_sec_context, 219 (sec_login_passwd_t *) & pw, &err); 220 if (err != error_status_ok) 221 { 222 dce_error_inq_text(err, dce_errstr, &err2); 223 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); 224 225 return (False); 226 } 227 228 sec_login_purge_context(&my_dce_sec_context, &err); 229 if (err != error_status_ok) 230 { 231 dce_error_inq_text(err, dce_errstr, &err2); 232 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr)); 233 234 return (False); 235 } 236 237 /* 238 * NB. I'd like to change these to call something like change_to_user() 239 * instead but currently we don't have a connection 240 * context to become the correct user. This is already 241 * fairly platform specific code however, so I think 242 * this should be ok. I have added code to go 243 * back to being root on error though. JRA. 244 */ 245 246 egid = getegid(); 247 248 set_effective_gid(pw->pw_gid); 249 set_effective_uid(pw->pw_uid); 250 251 if (sec_login_setup_identity((unsigned char *)user, 252 sec_login_no_flags, 253 &my_dce_sec_context, &err) == 0) 254 { 255 dce_error_inq_text(err, dce_errstr, &err2); 256 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", 257 user, dce_errstr)); 258 goto err; 259 } 260 261 sec_login_get_pwent(my_dce_sec_context, 262 (sec_login_passwd_t *) & pw, &err); 263 if (err != error_status_ok) 264 { 265 dce_error_inq_text(err, dce_errstr, &err2); 266 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); 267 goto err; 268 } 269 270 passwd_rec.version_number = sec_passwd_c_version_none; 271 passwd_rec.pepper = NULL; 272 passwd_rec.key.key_type = sec_passwd_plain; 273 passwd_rec.key.tagged_union.plain = (idl_char *) password; 274 275 sec_login_validate_identity(my_dce_sec_context, 276 &passwd_rec, &password_reset, 277 &auth_src, &err); 278 if (err != error_status_ok) 279 { 280 dce_error_inq_text(err, dce_errstr, &err2); 281 DEBUG(0, 282 ("DCE Identity Validation failed for principal %s: %s\n", 283 user, dce_errstr)); 284 goto err; 285 } 286 287 sec_login_certify_identity(my_dce_sec_context, &err); 288 if (err != error_status_ok) 289 { 290 dce_error_inq_text(err, dce_errstr, &err2); 291 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr)); 292 goto err; 293 } 294 295 if (auth_src != sec_login_auth_src_network) 296 { 297 DEBUG(0, ("DCE context has no network credentials.\n")); 298 } 299 300 sec_login_set_context(my_dce_sec_context, &err); 301 if (err != error_status_ok) 302 { 303 dce_error_inq_text(err, dce_errstr, &err2); 304 DEBUG(0, 305 ("DCE login failed for principal %s, cant set context: %s\n", 306 user, dce_errstr)); 307 308 sec_login_purge_context(&my_dce_sec_context, &err); 309 goto err; 310 } 311 312 sec_login_get_pwent(my_dce_sec_context, 313 (sec_login_passwd_t *) & pw, &err); 314 if (err != error_status_ok) 315 { 316 dce_error_inq_text(err, dce_errstr, &err2); 317 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); 318 goto err; 319 } 320 321 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n", 322 user, sys_getpid())); 323 324 DEBUG(3, ("DCE principal: %s\n" 325 " uid: %d\n" 326 " gid: %d\n", 327 pw->pw_name, pw->pw_uid, pw->pw_gid)); 328 DEBUG(3, (" info: %s\n" 329 " dir: %s\n" 330 " shell: %s\n", 331 pw->pw_gecos, pw->pw_dir, pw->pw_shell)); 332 333 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); 334 if (err != error_status_ok) 335 { 336 dce_error_inq_text(err, dce_errstr, &err2); 337 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); 338 goto err; 339 } 340 341 set_effective_uid(0); 342 set_effective_gid(0); 343 344 DEBUG(0, 345 ("DCE context expires: %s", asctime(localtime(&expire_time)))); 346 347 dcelogin_atmost_once = 1; 348 return (True); 349 350 err: 351 352 /* Go back to root, JRA. */ 353 set_effective_uid(0); 354 set_effective_gid(egid); 355 return (False); 356} 357 358void dfs_unlogin(void) 359{ 360 error_status_t err; 361 int err2; 362 unsigned char dce_errstr[dce_c_error_string_len]; 363 364 sec_login_purge_context(&my_dce_sec_context, &err); 365 if (err != error_status_ok) 366 { 367 dce_error_inq_text(err, dce_errstr, &err2); 368 DEBUG(0, 369 ("DCE purge login context failed for server instance %d: %s\n", 370 sys_getpid(), dce_errstr)); 371 } 372} 373#endif 374 375#ifdef LINUX_BIGCRYPT 376/**************************************************************************** 377an enhanced crypt for Linux to handle password longer than 8 characters 378****************************************************************************/ 379static int linux_bigcrypt(char *password, char *salt1, char *crypted) 380{ 381#define LINUX_PASSWORD_SEG_CHARS 8 382 char salt[3]; 383 int i; 384 385 StrnCpy(salt, salt1, 2); 386 crypted += 2; 387 388 for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) { 389 char *p = crypt(password, salt) + 2; 390 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0) 391 return (0); 392 password += LINUX_PASSWORD_SEG_CHARS; 393 crypted += strlen(p); 394 } 395 396 return (1); 397} 398#endif 399 400#ifdef OSF1_ENH_SEC 401/**************************************************************************** 402an enhanced crypt for OSF1 403****************************************************************************/ 404static char *osf1_bigcrypt(char *password, char *salt1) 405{ 406 static char result[AUTH_MAX_PASSWD_LENGTH] = ""; 407 char *p1; 408 char *p2 = password; 409 char salt[3]; 410 int i; 411 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS; 412 if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS) 413 parts++; 414 415 StrnCpy(salt, salt1, 2); 416 StrnCpy(result, salt1, 2); 417 result[2] = '\0'; 418 419 for (i = 0; i < parts; i++) { 420 p1 = crypt(p2, salt); 421 strncat(result, p1 + 2, 422 AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1); 423 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2); 424 p2 += AUTH_CLEARTEXT_SEG_CHARS; 425 } 426 427 return (result); 428} 429#endif 430 431 432/**************************************************************************** 433apply a function to upper/lower case combinations 434of a string and return true if one of them returns true. 435try all combinations with N uppercase letters. 436offset is the first char to try and change (start with 0) 437it assumes the string starts lowercased 438****************************************************************************/ 439static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (const char *), 440 int N) 441{ 442 int len = strlen(s); 443 int i; 444 NTSTATUS nt_status; 445 446#ifdef PASSWORD_LENGTH 447 len = MIN(len, PASSWORD_LENGTH); 448#endif 449 450 if (N <= 0 || offset >= len) 451 return (fn(s)); 452 453 for (i = offset; i < (len - (N - 1)); i++) { 454 char c = s[i]; 455 if (!islower(c)) 456 continue; 457 s[i] = toupper(c); 458 if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) { 459 return (nt_status); 460 } 461 s[i] = c; 462 } 463 return (NT_STATUS_WRONG_PASSWORD); 464} 465 466/**************************************************************************** 467apply a function to upper/lower case combinations 468of a string and return true if one of them returns true. 469try all combinations with up to N uppercase letters. 470offset is the first char to try and change (start with 0) 471it assumes the string starts lowercased 472****************************************************************************/ 473static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (const char *), int N) 474{ 475 int n; 476 NTSTATUS nt_status; 477 for (n = 1; n <= N; n++) 478 if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD)) 479 return nt_status; 480 return NT_STATUS_WRONG_PASSWORD; 481} 482 483 484/**************************************************************************** 485core of password checking routine 486****************************************************************************/ 487static NTSTATUS password_check(const char *password) 488{ 489#ifdef WITH_PAM 490 return smb_pam_passcheck(this_user, password); 491#else 492 493 BOOL ret; 494 495#ifdef WITH_AFS 496 if (afs_auth(this_user, password)) 497 return NT_STATUS_OK; 498#endif /* WITH_AFS */ 499 500#ifdef WITH_DFS 501 if (dfs_auth(this_user, password)) 502 return NT_STATUS_OK; 503#endif /* WITH_DFS */ 504 505#ifdef OSF1_ENH_SEC 506 507 ret = (strcmp(osf1_bigcrypt(password, this_salt), 508 this_crypted) == 0); 509 if (!ret) { 510 DEBUG(2, 511 ("OSF1_ENH_SEC failed. Trying normal crypt.\n")); 512 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0); 513 } 514 if (ret) { 515 return NT_STATUS_OK; 516 } else { 517 return NT_STATUS_WRONG_PASSWORD; 518 } 519 520#endif /* OSF1_ENH_SEC */ 521 522#ifdef ULTRIX_AUTH 523 ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0); 524 if (ret) { 525 return NT_STATUS_OK; 526 } else { 527 return NT_STATUS_WRONG_PASSWORD; 528 } 529 530#endif /* ULTRIX_AUTH */ 531 532#ifdef LINUX_BIGCRYPT 533 ret = (linux_bigcrypt(password, this_salt, this_crypted)); 534 if (ret) { 535 return NT_STATUS_OK; 536 } else { 537 return NT_STATUS_WRONG_PASSWORD; 538 } 539#endif /* LINUX_BIGCRYPT */ 540 541#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS) 542 543 /* 544 * Some systems have bigcrypt in the C library but might not 545 * actually use it for the password hashes (HPUX 10.20) is 546 * a noteable example. So we try bigcrypt first, followed 547 * by crypt. 548 */ 549 550 if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0) 551 return NT_STATUS_OK; 552 else 553 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0); 554 if (ret) { 555 return NT_STATUS_OK; 556 } else { 557 return NT_STATUS_WRONG_PASSWORD; 558 } 559#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ 560 561#ifdef HAVE_BIGCRYPT 562 ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0); 563 if (ret) { 564 return NT_STATUS_OK; 565 } else { 566 return NT_STATUS_WRONG_PASSWORD; 567 } 568#endif /* HAVE_BIGCRYPT */ 569 570#ifndef HAVE_CRYPT 571 DEBUG(1, ("Warning - no crypt available\n")); 572 return NT_STATUS_LOGON_FAILURE; 573#else /* HAVE_CRYPT */ 574 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0); 575 if (ret) { 576 return NT_STATUS_OK; 577 } else { 578 return NT_STATUS_WRONG_PASSWORD; 579 } 580#endif /* HAVE_CRYPT */ 581#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ 582#endif /* WITH_PAM */ 583} 584 585 586 587/**************************************************************************** 588CHECK if a username/password is OK 589the function pointer fn() points to a function to call when a successful 590match is found and is used to update the encrypted password file 591return NT_STATUS_OK on correct match, appropriate error otherwise 592****************************************************************************/ 593 594NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password, 595 int pwlen, BOOL (*fn) (const char *, const char *), BOOL run_cracker) 596{ 597 pstring pass2; 598 int level = lp_passwordlevel(); 599 600 NTSTATUS nt_status; 601 602#ifdef DEBUG_PASSWORD 603 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password)); 604#endif 605 606 if (!password) 607 return NT_STATUS_LOGON_FAILURE; 608 609 if (((!*password) || (!pwlen)) && !lp_null_passwords()) 610 return NT_STATUS_LOGON_FAILURE; 611 612#if defined(WITH_PAM) 613 614 /* 615 * If we're using PAM we want to short-circuit all the 616 * checks below and dive straight into the PAM code. 617 */ 618 619 fstrcpy(this_user, user); 620 621 DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen)); 622 623#else /* Not using PAM */ 624 625 DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen)); 626 627 if (!pass) { 628 DEBUG(3, ("Couldn't find user %s\n", user)); 629 return NT_STATUS_NO_SUCH_USER; 630 } 631 632 633 /* Copy into global for the convenience of looping code */ 634 /* Also the place to keep the 'password' no matter what 635 crazy struct it started in... */ 636 fstrcpy(this_crypted, pass->pw_passwd); 637 fstrcpy(this_salt, pass->pw_passwd); 638 639#ifdef HAVE_GETSPNAM 640 { 641 struct spwd *spass; 642 643 /* many shadow systems require you to be root to get 644 the password, in most cases this should already be 645 the case when this function is called, except 646 perhaps for IPC password changing requests */ 647 648 spass = getspnam(pass->pw_name); 649 if (spass && spass->sp_pwdp) { 650 fstrcpy(this_crypted, spass->sp_pwdp); 651 fstrcpy(this_salt, spass->sp_pwdp); 652 } 653 } 654#elif defined(IA_UINFO) 655 { 656 /* Need to get password with SVR4.2's ia_ functions 657 instead of get{sp,pw}ent functions. Required by 658 UnixWare 2.x, tested on version 659 2.1. (tangent@cyberport.com) */ 660 uinfo_t uinfo; 661 if (ia_openinfo(pass->pw_name, &uinfo) != -1) 662 ia_get_logpwd(uinfo, &(pass->pw_passwd)); 663 } 664#endif 665 666#ifdef HAVE_GETPRPWNAM 667 { 668 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name); 669 if (pr_pw && pr_pw->ufld.fd_encrypt) 670 fstrcpy(this_crypted, pr_pw->ufld.fd_encrypt); 671 } 672#endif 673 674#ifdef HAVE_GETPWANAM 675 { 676 struct passwd_adjunct *pwret; 677 pwret = getpwanam(s); 678 if (pwret && pwret->pwa_passwd) 679 fstrcpy(this_crypted, pwret->pwa_passwd); 680 } 681#endif 682 683#ifdef OSF1_ENH_SEC 684 { 685 struct pr_passwd *mypasswd; 686 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n", 687 user)); 688 mypasswd = getprpwnam(user); 689 if (mypasswd) { 690 fstrcpy(this_user, mypasswd->ufld.fd_name); 691 fstrcpy(this_crypted, mypasswd->ufld.fd_encrypt); 692 } else { 693 DEBUG(5, 694 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n", 695 user)); 696 } 697 } 698#endif 699 700#ifdef ULTRIX_AUTH 701 { 702 AUTHORIZATION *ap = getauthuid(pass->pw_uid); 703 if (ap) { 704 fstrcpy(this_crypted, ap->a_password); 705 endauthent(); 706 } 707 } 708#endif 709 710#if defined(HAVE_TRUNCATED_SALT) 711 /* crypt on some platforms (HPUX in particular) 712 won't work with more than 2 salt characters. */ 713 this_salt[2] = 0; 714#endif 715 716 if (!*this_crypted) { 717 if (!lp_null_passwords()) { 718 DEBUG(2, ("Disallowing %s with null password\n", 719 this_user)); 720 return NT_STATUS_LOGON_FAILURE; 721 } 722 if (!*password) { 723 DEBUG(3, 724 ("Allowing access to %s with null password\n", 725 this_user)); 726 return NT_STATUS_OK; 727 } 728 } 729 730#endif /* defined(WITH_PAM) */ 731 732 /* try it as it came to us */ 733 nt_status = password_check(password); 734 if NT_STATUS_IS_OK(nt_status) { 735 if (fn) { 736 fn(user, password); 737 } 738 return (nt_status); 739 } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { 740 /* No point continuing if its not the password thats to blame (ie PAM disabled). */ 741 return (nt_status); 742 } 743 744 if (!run_cracker) { 745 return (nt_status); 746 } 747 748 /* if the password was given to us with mixed case then we don't 749 * need to proceed as we know it hasn't been case modified by the 750 * client */ 751 if (strhasupper(password) && strhaslower(password)) { 752 return nt_status; 753 } 754 755 /* make a copy of it */ 756 pstrcpy(pass2, password); 757 758 /* try all lowercase if it's currently all uppercase */ 759 if (strhasupper(pass2)) { 760 strlower_m(pass2); 761 if NT_STATUS_IS_OK(nt_status = password_check(pass2)) { 762 if (fn) 763 fn(user, pass2); 764 return (nt_status); 765 } 766 } 767 768 /* give up? */ 769 if (level < 1) { 770 return NT_STATUS_WRONG_PASSWORD; 771 } 772 773 /* last chance - all combinations of up to level chars upper! */ 774 strlower_m(pass2); 775 776 if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) { 777 if (fn) 778 fn(user, pass2); 779 return nt_status; 780 } 781 782 return NT_STATUS_WRONG_PASSWORD; 783} 784