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