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