s3-auth: Remove obsolete 'update encrypted' option.
[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, 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,
651                     const char *user,
652                     const char *password,
653                     bool run_cracker)
654 {
655         char *pass2 = NULL;
656         int level = lp_passwordlevel();
657
658         NTSTATUS nt_status;
659
660 #ifdef DEBUG_PASSWORD
661         DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
662 #endif
663
664         if (!password)
665                 return NT_STATUS_LOGON_FAILURE;
666
667         if ((!*password) && !lp_null_passwords())
668                 return NT_STATUS_LOGON_FAILURE;
669
670 #if defined(WITH_PAM) 
671
672         /*
673          * If we're using PAM we want to short-circuit all the 
674          * checks below and dive straight into the PAM code.
675          */
676
677         if (set_this_user(user) == NULL) {
678                 return NT_STATUS_NO_MEMORY;
679         }
680
681         DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
682
683 #else /* Not using PAM */
684
685         DEBUG(4, ("pass_check: Checking password for user %s\n", user));
686
687         if (!pass) {
688                 DEBUG(3, ("Couldn't find user %s\n", user));
689                 return NT_STATUS_NO_SUCH_USER;
690         }
691
692
693         /* Copy into global for the convenience of looping code */
694         /* Also the place to keep the 'password' no matter what
695            crazy struct it started in... */
696         if (set_this_crypted(pass->pw_passwd) == NULL) {
697                 return NT_STATUS_NO_MEMORY;
698         }
699         if (set_this_salt(pass->pw_passwd) == NULL) {
700                 return NT_STATUS_NO_MEMORY;
701         }
702
703 #ifdef HAVE_GETSPNAM
704         {
705                 struct spwd *spass;
706
707                 /* many shadow systems require you to be root to get
708                    the password, in most cases this should already be
709                    the case when this function is called, except
710                    perhaps for IPC password changing requests */
711
712                 spass = getspnam(pass->pw_name);
713                 if (spass && spass->sp_pwdp) {
714                         if (set_this_crypted(spass->sp_pwdp) == NULL) {
715                                 return NT_STATUS_NO_MEMORY;
716                         }
717                         if (set_this_salt(spass->sp_pwdp) == NULL) {
718                                 return NT_STATUS_NO_MEMORY;
719                         }
720                 }
721         }
722 #elif defined(IA_UINFO)
723         {
724                 /* Need to get password with SVR4.2's ia_ functions
725                    instead of get{sp,pw}ent functions. Required by
726                    UnixWare 2.x, tested on version
727                    2.1. (tangent@cyberport.com) */
728                 uinfo_t uinfo;
729                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
730                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
731         }
732 #endif
733
734 #ifdef HAVE_GETPRPWNAM
735         {
736                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
737                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
738                         if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
739                                 return NT_STATUS_NO_MEMORY;
740                         }
741                 }
742         }
743 #endif
744
745 #ifdef HAVE_GETPWANAM
746         {
747                 struct passwd_adjunct *pwret;
748                 pwret = getpwanam(s);
749                 if (pwret && pwret->pwa_passwd) {
750                         if (set_this_crypted(pwret->pwa_passwd) == NULL) {
751                                 return NT_STATUS_NO_MEMORY;
752                         }
753                 }
754         }
755 #endif
756
757 #ifdef OSF1_ENH_SEC
758         {
759                 struct pr_passwd *mypasswd;
760                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
761                           user));
762                 mypasswd = getprpwnam(user);
763                 if (mypasswd) {
764                         if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
765                                 return NT_STATUS_NO_MEMORY;
766                         }
767                         if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
768                                 return NT_STATUS_NO_MEMORY;
769                         }
770                 } else {
771                         DEBUG(5,
772                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
773                                user));
774                 }
775         }
776 #endif
777
778 #ifdef ULTRIX_AUTH
779         {
780                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
781                 if (ap) {
782                         if (set_this_crypted(ap->a_password) == NULL) {
783                                 endauthent();
784                                 return NT_STATUS_NO_MEMORY;
785                         }
786                         endauthent();
787                 }
788         }
789 #endif
790
791 #if defined(HAVE_TRUNCATED_SALT)
792         /* crypt on some platforms (HPUX in particular)
793            won't work with more than 2 salt characters. */
794         {
795                 char *trunc_salt = get_this_salt();
796                 if (!trunc_salt || strlen(trunc_salt) < 2) {
797                         return NT_STATUS_LOGON_FAILURE;
798                 }
799                 trunc_salt[2] = 0;
800                 if (set_this_salt(trunc_salt) == NULL) {
801                         return NT_STATUS_NO_MEMORY;
802                 }
803         }
804 #endif
805
806         if (!get_this_crypted() || !*get_this_crypted()) {
807                 if (!lp_null_passwords()) {
808                         DEBUG(2, ("Disallowing %s with null password\n",
809                                   get_this_user()));
810                         return NT_STATUS_LOGON_FAILURE;
811                 }
812                 if (!*password) {
813                         DEBUG(3,
814                               ("Allowing access to %s with null password\n",
815                                get_this_user()));
816                         return NT_STATUS_OK;
817                 }
818         }
819
820 #endif /* defined(WITH_PAM) */
821
822         /* try it as it came to us */
823         nt_status = password_check(password);
824         if NT_STATUS_IS_OK(nt_status) {
825                 return (nt_status);
826         } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
827                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
828                 return (nt_status);
829         }
830
831         if (!run_cracker) {
832                 return (nt_status);
833         }
834
835         /* if the password was given to us with mixed case then we don't
836          * need to proceed as we know it hasn't been case modified by the
837          * client */
838         if (strhasupper(password) && strhaslower(password)) {
839                 return nt_status;
840         }
841
842         /* make a copy of it */
843         pass2 = talloc_strdup(talloc_tos(), password);
844         if (!pass2) {
845                 return NT_STATUS_NO_MEMORY;
846         }
847
848         /* try all lowercase if it's currently all uppercase */
849         if (strhasupper(pass2)) {
850                 strlower_m(pass2);
851                 if NT_STATUS_IS_OK(nt_status = password_check(pass2)) {
852                         return (nt_status);
853                 }
854         }
855
856         /* give up? */
857         if (level < 1) {
858                 return NT_STATUS_WRONG_PASSWORD;
859         }
860
861         /* last chance - all combinations of up to level chars upper! */
862         strlower_m(pass2);
863  
864         if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) {
865                 return nt_status;
866         }
867         
868         return NT_STATUS_WRONG_PASSWORD;
869 }