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