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