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