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