root/source3/auth/pass_check.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_this_user
  2. set_this_user
  3. get_this_salt
  4. set_this_salt
  5. get_this_crypted
  6. set_this_crypted
  7. afs_auth
  8. dfs_auth
  9. dfs_unlogin
  10. linux_bigcrypt
  11. osf1_bigcrypt
  12. string_combinations2
  13. string_combinations
  14. password_check
  15. pass_check

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

/* [<][>][^][v][top][bottom][index][help] */