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