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