c61a10ba1b0c1df38ddabfbbd2dc7d40417a7e80
[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(void)
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(void)
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(void)
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,
496                                      NTSTATUS (*fn)(const char *s,
497                                                     void *private_data),
498                                      int N, void *private_data)
499 {
500         int len = strlen(s);
501         int i;
502         NTSTATUS nt_status;
503
504 #ifdef PASSWORD_LENGTH
505         len = MIN(len, PASSWORD_LENGTH);
506 #endif
507
508         if (N <= 0 || offset >= len)
509                 return (fn(s, private_data));
510
511         for (i = offset; i < (len - (N - 1)); i++) {
512                 char c = s[i];
513                 if (!islower_ascii(c))
514                         continue;
515                 s[i] = toupper_ascii(c);
516                 nt_status = string_combinations2(s, i + 1, fn, N - 1,
517                                                  private_data);
518                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
519                         return nt_status;
520                 }
521                 s[i] = c;
522         }
523         return (NT_STATUS_WRONG_PASSWORD);
524 }
525
526 /****************************************************************************
527 apply a function to upper/lower case combinations
528 of a string and return true if one of them returns true.
529 try all combinations with up to N uppercase letters.
530 offset is the first char to try and change (start with 0)
531 it assumes the string starts lowercased
532 ****************************************************************************/
533 static NTSTATUS string_combinations(char *s,
534                                     NTSTATUS (*fn)(const char *s,
535                                                    void *private_data),
536                                     int N, void *private_data)
537 {
538         int n;
539         NTSTATUS nt_status;
540         for (n = 1; n <= N; n++) {
541                 nt_status = string_combinations2(s, 0, fn, n, private_data);
542                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
543                         return nt_status;
544                 }
545         }
546         return NT_STATUS_WRONG_PASSWORD;
547 }
548
549
550 /****************************************************************************
551 core of password checking routine
552 ****************************************************************************/
553 static NTSTATUS password_check(const char *password, void *private_data)
554 {
555 #ifdef WITH_PAM
556         const char *rhost = (const char *)private_data;
557         return smb_pam_passcheck(get_this_user(), rhost, password);
558 #else
559
560         bool ret;
561
562 #ifdef WITH_AFS
563         if (afs_auth(get_this_user(), password))
564                 return NT_STATUS_OK;
565 #endif /* WITH_AFS */
566
567 #ifdef WITH_DFS
568         if (dfs_auth(get_this_user(), password))
569                 return NT_STATUS_OK;
570 #endif /* WITH_DFS */
571
572 #ifdef OSF1_ENH_SEC
573
574         ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
575                       get_this_crypted()) == 0);
576         if (!ret) {
577                 DEBUG(2,
578                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
579                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
580         }
581         if (ret) {
582                 return NT_STATUS_OK;
583         } else {
584                 return NT_STATUS_WRONG_PASSWORD;
585         }
586
587 #endif /* OSF1_ENH_SEC */
588
589 #ifdef ULTRIX_AUTH
590         ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
591         if (ret) {
592                 return NT_STATUS_OK;
593         } else {
594                 return NT_STATUS_WRONG_PASSWORD;
595         }
596
597 #endif /* ULTRIX_AUTH */
598
599 #ifdef LINUX_BIGCRYPT
600         ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
601         if (ret) {
602                 return NT_STATUS_OK;
603         } else {
604                 return NT_STATUS_WRONG_PASSWORD;
605         }
606 #endif /* LINUX_BIGCRYPT */
607
608 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
609
610         /*
611          * Some systems have bigcrypt in the C library but might not
612          * actually use it for the password hashes (HPUX 10.20) is
613          * a noteable example. So we try bigcrypt first, followed
614          * by crypt.
615          */
616
617         if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
618                 return NT_STATUS_OK;
619         else
620                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
621         if (ret) {
622                 return NT_STATUS_OK;
623         } else {
624                 return NT_STATUS_WRONG_PASSWORD;
625         }
626 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
627
628 #ifdef HAVE_BIGCRYPT
629         ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
630         if (ret) {
631                 return NT_STATUS_OK;
632         } else {
633                 return NT_STATUS_WRONG_PASSWORD;
634         }
635 #endif /* HAVE_BIGCRYPT */
636
637 #ifndef HAVE_CRYPT
638         DEBUG(1, ("Warning - no crypt available\n"));
639         return NT_STATUS_LOGON_FAILURE;
640 #else /* HAVE_CRYPT */
641         ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
642         if (ret) {
643                 return NT_STATUS_OK;
644         } else {
645                 return NT_STATUS_WRONG_PASSWORD;
646         }
647 #endif /* HAVE_CRYPT */
648 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
649 #endif /* WITH_PAM */
650 }
651
652
653
654 /****************************************************************************
655 CHECK if a username/password is OK
656 the function pointer fn() points to a function to call when a successful
657 match is found and is used to update the encrypted password file 
658 return NT_STATUS_OK on correct match, appropriate error otherwise
659 ****************************************************************************/
660
661 NTSTATUS pass_check(const struct passwd *pass,
662                     const char *user,
663                     const char *rhost,
664                     const char *password,
665                     bool run_cracker)
666 {
667         char *pass2 = NULL;
668         int level = lp_passwordlevel();
669
670         NTSTATUS nt_status;
671
672 #ifdef DEBUG_PASSWORD
673         DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
674 #endif
675
676         if (!password)
677                 return NT_STATUS_LOGON_FAILURE;
678
679         if ((!*password) && !lp_null_passwords())
680                 return NT_STATUS_LOGON_FAILURE;
681
682 #if defined(WITH_PAM) 
683
684         /*
685          * If we're using PAM we want to short-circuit all the 
686          * checks below and dive straight into the PAM code.
687          */
688
689         if (set_this_user(user) == NULL) {
690                 return NT_STATUS_NO_MEMORY;
691         }
692
693         DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
694
695 #else /* Not using PAM */
696
697         DEBUG(4, ("pass_check: Checking password for user %s\n", user));
698
699         if (!pass) {
700                 DEBUG(3, ("Couldn't find user %s\n", user));
701                 return NT_STATUS_NO_SUCH_USER;
702         }
703
704
705         /* Copy into global for the convenience of looping code */
706         /* Also the place to keep the 'password' no matter what
707            crazy struct it started in... */
708         if (set_this_crypted(pass->pw_passwd) == NULL) {
709                 return NT_STATUS_NO_MEMORY;
710         }
711         if (set_this_salt(pass->pw_passwd) == NULL) {
712                 return NT_STATUS_NO_MEMORY;
713         }
714
715 #ifdef HAVE_GETSPNAM
716         {
717                 struct spwd *spass;
718
719                 /* many shadow systems require you to be root to get
720                    the password, in most cases this should already be
721                    the case when this function is called, except
722                    perhaps for IPC password changing requests */
723
724                 spass = getspnam(pass->pw_name);
725                 if (spass && spass->sp_pwdp) {
726                         if (set_this_crypted(spass->sp_pwdp) == NULL) {
727                                 return NT_STATUS_NO_MEMORY;
728                         }
729                         if (set_this_salt(spass->sp_pwdp) == NULL) {
730                                 return NT_STATUS_NO_MEMORY;
731                         }
732                 }
733         }
734 #elif defined(IA_UINFO)
735         {
736                 /* Need to get password with SVR4.2's ia_ functions
737                    instead of get{sp,pw}ent functions. Required by
738                    UnixWare 2.x, tested on version
739                    2.1. (tangent@cyberport.com) */
740                 uinfo_t uinfo;
741                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
742                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
743         }
744 #endif
745
746 #ifdef HAVE_GETPRPWNAM
747         {
748                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
749                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
750                         if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
751                                 return NT_STATUS_NO_MEMORY;
752                         }
753                 }
754         }
755 #endif
756
757 #ifdef HAVE_GETPWANAM
758         {
759                 struct passwd_adjunct *pwret;
760                 pwret = getpwanam(s);
761                 if (pwret && pwret->pwa_passwd) {
762                         if (set_this_crypted(pwret->pwa_passwd) == NULL) {
763                                 return NT_STATUS_NO_MEMORY;
764                         }
765                 }
766         }
767 #endif
768
769 #ifdef OSF1_ENH_SEC
770         {
771                 struct pr_passwd *mypasswd;
772                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
773                           user));
774                 mypasswd = getprpwnam(user);
775                 if (mypasswd) {
776                         if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
777                                 return NT_STATUS_NO_MEMORY;
778                         }
779                         if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
780                                 return NT_STATUS_NO_MEMORY;
781                         }
782                 } else {
783                         DEBUG(5,
784                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
785                                user));
786                 }
787         }
788 #endif
789
790 #ifdef ULTRIX_AUTH
791         {
792                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
793                 if (ap) {
794                         if (set_this_crypted(ap->a_password) == NULL) {
795                                 endauthent();
796                                 return NT_STATUS_NO_MEMORY;
797                         }
798                         endauthent();
799                 }
800         }
801 #endif
802
803 #if defined(HAVE_TRUNCATED_SALT)
804         /* crypt on some platforms (HPUX in particular)
805            won't work with more than 2 salt characters. */
806         {
807                 char *trunc_salt = get_this_salt();
808                 if (!trunc_salt || strlen(trunc_salt) < 2) {
809                         return NT_STATUS_LOGON_FAILURE;
810                 }
811                 trunc_salt[2] = 0;
812                 if (set_this_salt(trunc_salt) == NULL) {
813                         return NT_STATUS_NO_MEMORY;
814                 }
815         }
816 #endif
817
818         if (!get_this_crypted() || !*get_this_crypted()) {
819                 if (!lp_null_passwords()) {
820                         DEBUG(2, ("Disallowing %s with null password\n",
821                                   get_this_user()));
822                         return NT_STATUS_LOGON_FAILURE;
823                 }
824                 if (!*password) {
825                         DEBUG(3,
826                               ("Allowing access to %s with null password\n",
827                                get_this_user()));
828                         return NT_STATUS_OK;
829                 }
830         }
831
832 #endif /* defined(WITH_PAM) */
833
834         /* try it as it came to us */
835         nt_status = password_check(password, (void *)rhost);
836         if NT_STATUS_IS_OK(nt_status) {
837                 return (nt_status);
838         } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
839                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
840                 return (nt_status);
841         }
842
843         if (!run_cracker) {
844                 return (nt_status);
845         }
846
847         /* if the password was given to us with mixed case then we don't
848          * need to proceed as we know it hasn't been case modified by the
849          * client */
850         if (strhasupper(password) && strhaslower(password)) {
851                 return nt_status;
852         }
853
854         /* make a copy of it */
855         pass2 = talloc_strdup(talloc_tos(), password);
856         if (!pass2) {
857                 return NT_STATUS_NO_MEMORY;
858         }
859
860         /* try all lowercase if it's currently all uppercase */
861         if (strhasupper(pass2)) {
862                 strlower_m(pass2);
863                 nt_status = password_check(pass2, (void *)rhost);
864                 if (NT_STATUS_IS_OK(nt_status)) {
865                         return (nt_status);
866                 }
867         }
868
869         /* give up? */
870         if (level < 1) {
871                 return NT_STATUS_WRONG_PASSWORD;
872         }
873
874         /* last chance - all combinations of up to level chars upper! */
875         strlower_m(pass2);
876
877         nt_status = string_combinations(pass2, password_check, level,
878                                         (void *)rhost);
879         if (NT_STATUS_IS_OK(nt_status)) {
880                 return nt_status;
881         }
882
883         return NT_STATUS_WRONG_PASSWORD;
884 }