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