s3-includes: move some chgpasswd related defines to the locations where they are...
[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 /* what is the longest significant password available on your system?
29  Knowing this speeds up password searches a lot */
30 #ifndef PASSWORD_LENGTH
31 #define PASSWORD_LENGTH 8
32 #endif
33
34 /* these are kept here to keep the string_combinations function simple */
35 static char *ths_user;
36
37 static const char *get_this_user(void)
38 {
39         if (!ths_user) {
40                 return "";
41         }
42         return ths_user;
43 }
44
45 #if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
46 static const char *set_this_user(const char *newuser)
47 {
48         char *orig_user = ths_user;
49         ths_user = SMB_STRDUP(newuser);
50         SAFE_FREE(orig_user);
51         return ths_user;
52 }
53 #endif
54
55 #if !defined(WITH_PAM)
56 static char *ths_salt;
57 /* This must be writable. */
58 static char *get_this_salt(void)
59 {
60         return ths_salt;
61 }
62
63 /* We may be setting a modified version of the same
64  * string, so don't free before use. */
65
66 static const char *set_this_salt(const char *newsalt)
67 {
68         char *orig_salt = ths_salt;
69         ths_salt = SMB_STRDUP(newsalt);
70         SAFE_FREE(orig_salt);
71         return ths_salt;
72 }
73
74 static char *ths_crypted;
75 static const char *get_this_crypted(void)
76 {
77         if (!ths_crypted) {
78                 return "";
79         }
80         return ths_crypted;
81 }
82
83 static const char *set_this_crypted(const char *newcrypted)
84 {
85         char *orig_crypted = ths_crypted;
86         ths_crypted = SMB_STRDUP(newcrypted);
87         SAFE_FREE(orig_crypted);
88         return ths_crypted;
89 }
90 #endif
91
92 #ifdef WITH_AFS
93
94 #include <afs/stds.h>
95 #include <afs/kautils.h>
96
97 /*******************************************************************
98 check on AFS authentication
99 ********************************************************************/
100 static bool afs_auth(char *user, char *password)
101 {
102         long password_expires = 0;
103         char *reason;
104
105         /* For versions of AFS prior to 3.3, this routine has few arguments, */
106         /* but since I can't find the old documentation... :-)               */
107         setpag();
108         if (ka_UserAuthenticateGeneral
109             (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0,       /* instance */
110              (char *)0,         /* cell */
111              password, 0,       /* lifetime, default */
112              &password_expires, /*days 'til it expires */
113              0,                 /* spare 2 */
114              &reason) == 0)
115         {
116                 return (True);
117         }
118         DEBUG(1,
119               ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
120         return (False);
121 }
122 #endif
123
124
125 #ifdef WITH_DFS
126
127 #include <dce/dce_error.h>
128 #include <dce/sec_login.h>
129
130 /*****************************************************************
131  This new version of the DFS_AUTH code was donated by Karsten Muuss
132  <muuss@or.uni-bonn.de>. It fixes the following problems with the
133  old code :
134
135   - Server credentials may expire
136   - Client credential cache files have wrong owner
137   - purge_context() function is called with invalid argument
138
139  This new code was modified to ensure that on exit the uid/gid is
140  still root, and the original directory is restored. JRA.
141 ******************************************************************/
142
143 sec_login_handle_t my_dce_sec_context;
144 int dcelogin_atmost_once = 0;
145
146 /*******************************************************************
147 check on a DCE/DFS authentication
148 ********************************************************************/
149 static bool dfs_auth(char *user, char *password)
150 {
151         struct tm *t;
152         error_status_t err;
153         int err2;
154         int prterr;
155         signed32 expire_time, current_time;
156         boolean32 password_reset;
157         struct passwd *pw;
158         sec_passwd_rec_t passwd_rec;
159         sec_login_auth_src_t auth_src = sec_login_auth_src_network;
160         unsigned char dce_errstr[dce_c_error_string_len];
161         gid_t egid;
162
163         if (dcelogin_atmost_once)
164                 return (False);
165
166 #ifdef HAVE_CRYPT
167         /*
168          * We only go for a DCE login context if the given password
169          * matches that stored in the local password file.. 
170          * Assumes local passwd file is kept in sync w/ DCE RGY!
171          */
172
173         if (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()))
174         {
175                 return (False);
176         }
177 #endif
178
179         sec_login_get_current_context(&my_dce_sec_context, &err);
180         if (err != error_status_ok)
181         {
182                 dce_error_inq_text(err, dce_errstr, &err2);
183                 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
184
185                 return (False);
186         }
187
188         sec_login_certify_identity(my_dce_sec_context, &err);
189         if (err != error_status_ok)
190         {
191                 dce_error_inq_text(err, dce_errstr, &err2);
192                 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
193
194                 return (False);
195         }
196
197         sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
198         if (err != error_status_ok)
199         {
200                 dce_error_inq_text(err, dce_errstr, &err2);
201                 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
202
203                 return (False);
204         }
205
206         time(&current_time);
207
208         if (expire_time < (current_time + 60))
209         {
210                 struct passwd *pw;
211                 sec_passwd_rec_t *key;
212
213                 sec_login_get_pwent(my_dce_sec_context,
214                                     (sec_login_passwd_t *) & pw, &err);
215                 if (err != error_status_ok)
216                 {
217                         dce_error_inq_text(err, dce_errstr, &err2);
218                         DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
219
220                         return (False);
221                 }
222
223                 sec_login_refresh_identity(my_dce_sec_context, &err);
224                 if (err != error_status_ok)
225                 {
226                         dce_error_inq_text(err, dce_errstr, &err2);
227                         DEBUG(0, ("DCE can't refresh identity. %s\n",
228                                   dce_errstr));
229
230                         return (False);
231                 }
232
233                 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
234                                      (unsigned char *)pw->pw_name,
235                                      sec_c_key_version_none,
236                                      (void **)&key, &err);
237                 if (err != error_status_ok)
238                 {
239                         dce_error_inq_text(err, dce_errstr, &err2);
240                         DEBUG(0, ("DCE can't get key for %s. %s\n",
241                                   pw->pw_name, dce_errstr));
242
243                         return (False);
244                 }
245
246                 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
247                                                &password_reset, &auth_src,
248                                                &err);
249                 if (err != error_status_ok)
250                 {
251                         dce_error_inq_text(err, dce_errstr, &err2);
252                         DEBUG(0,
253                               ("DCE can't validate and certify identity for %s. %s\n",
254                                pw->pw_name, dce_errstr));
255                 }
256
257                 sec_key_mgmt_free_key(key, &err);
258                 if (err != error_status_ok)
259                 {
260                         dce_error_inq_text(err, dce_errstr, &err2);
261                         DEBUG(0, ("DCE can't free key.\n", dce_errstr));
262                 }
263         }
264
265         if (sec_login_setup_identity((unsigned char *)user,
266                                      sec_login_no_flags,
267                                      &my_dce_sec_context, &err) == 0)
268         {
269                 dce_error_inq_text(err, dce_errstr, &err2);
270                 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
271                           user, dce_errstr));
272                 return (False);
273         }
274
275         sec_login_get_pwent(my_dce_sec_context,
276                             (sec_login_passwd_t *) & pw, &err);
277         if (err != error_status_ok)
278         {
279                 dce_error_inq_text(err, dce_errstr, &err2);
280                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
281
282                 return (False);
283         }
284
285         sec_login_purge_context(&my_dce_sec_context, &err);
286         if (err != error_status_ok)
287         {
288                 dce_error_inq_text(err, dce_errstr, &err2);
289                 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
290
291                 return (False);
292         }
293
294         /*
295          * NB. I'd like to change these to call something like change_to_user()
296          * instead but currently we don't have a connection
297          * context to become the correct user. This is already
298          * fairly platform specific code however, so I think
299          * this should be ok. I have added code to go
300          * back to being root on error though. JRA.
301          */
302
303         egid = getegid();
304
305         set_effective_gid(pw->pw_gid);
306         set_effective_uid(pw->pw_uid);
307
308         if (sec_login_setup_identity((unsigned char *)user,
309                                      sec_login_no_flags,
310                                      &my_dce_sec_context, &err) == 0)
311         {
312                 dce_error_inq_text(err, dce_errstr, &err2);
313                 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
314                           user, dce_errstr));
315                 goto err;
316         }
317
318         sec_login_get_pwent(my_dce_sec_context,
319                             (sec_login_passwd_t *) & pw, &err);
320         if (err != error_status_ok)
321         {
322                 dce_error_inq_text(err, dce_errstr, &err2);
323                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
324                 goto err;
325         }
326
327         passwd_rec.version_number = sec_passwd_c_version_none;
328         passwd_rec.pepper = NULL;
329         passwd_rec.key.key_type = sec_passwd_plain;
330         passwd_rec.key.tagged_union.plain = (idl_char *) password;
331
332         sec_login_validate_identity(my_dce_sec_context,
333                                     &passwd_rec, &password_reset,
334                                     &auth_src, &err);
335         if (err != error_status_ok)
336         {
337                 dce_error_inq_text(err, dce_errstr, &err2);
338                 DEBUG(0,
339                       ("DCE Identity Validation failed for principal %s: %s\n",
340                        user, dce_errstr));
341                 goto err;
342         }
343
344         sec_login_certify_identity(my_dce_sec_context, &err);
345         if (err != error_status_ok)
346         {
347                 dce_error_inq_text(err, dce_errstr, &err2);
348                 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
349                 goto err;
350         }
351
352         if (auth_src != sec_login_auth_src_network)
353         {
354                 DEBUG(0, ("DCE context has no network credentials.\n"));
355         }
356
357         sec_login_set_context(my_dce_sec_context, &err);
358         if (err != error_status_ok)
359         {
360                 dce_error_inq_text(err, dce_errstr, &err2);
361                 DEBUG(0,
362                       ("DCE login failed for principal %s, cant set context: %s\n",
363                        user, dce_errstr));
364
365                 sec_login_purge_context(&my_dce_sec_context, &err);
366                 goto err;
367         }
368
369         sec_login_get_pwent(my_dce_sec_context,
370                             (sec_login_passwd_t *) & pw, &err);
371         if (err != error_status_ok)
372         {
373                 dce_error_inq_text(err, dce_errstr, &err2);
374                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
375                 goto err;
376         }
377
378         DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
379                   user, sys_getpid()));
380
381         DEBUG(3, ("DCE principal: %s\n"
382                   "          uid: %d\n"
383                   "          gid: %d\n",
384                   pw->pw_name, pw->pw_uid, pw->pw_gid));
385         DEBUG(3, ("         info: %s\n"
386                   "          dir: %s\n"
387                   "        shell: %s\n",
388                   pw->pw_gecos, pw->pw_dir, pw->pw_shell));
389
390         sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
391         if (err != error_status_ok)
392         {
393                 dce_error_inq_text(err, dce_errstr, &err2);
394                 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
395                 goto err;
396         }
397
398         set_effective_uid(0);
399         set_effective_gid(0);
400
401         t = localtime(&expire_time);
402         if (t) {
403                 const char *asct = asctime(t);
404                 if (asct) {
405                         DEBUG(0,("DCE context expires: %s", asct));
406                 }
407         }
408
409         dcelogin_atmost_once = 1;
410         return (True);
411
412       err:
413
414         /* Go back to root, JRA. */
415         set_effective_uid(0);
416         set_effective_gid(egid);
417         return (False);
418 }
419
420 void dfs_unlogin(void)
421 {
422         error_status_t err;
423         int err2;
424         unsigned char dce_errstr[dce_c_error_string_len];
425
426         sec_login_purge_context(&my_dce_sec_context, &err);
427         if (err != error_status_ok)
428         {
429                 dce_error_inq_text(err, dce_errstr, &err2);
430                 DEBUG(0,
431                       ("DCE purge login context failed for server instance %d: %s\n",
432                        sys_getpid(), dce_errstr));
433         }
434 }
435 #endif
436
437 #ifdef LINUX_BIGCRYPT
438 /****************************************************************************
439 an enhanced crypt for Linux to handle password longer than 8 characters
440 ****************************************************************************/
441 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
442 {
443 #define LINUX_PASSWORD_SEG_CHARS 8
444         char salt[3];
445         int i;
446
447         StrnCpy(salt, salt1, 2);
448         crypted += 2;
449
450         for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
451                 char *p = crypt(password, salt) + 2;
452                 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
453                         return (0);
454                 password += LINUX_PASSWORD_SEG_CHARS;
455                 crypted += strlen(p);
456         }
457
458         return (1);
459 }
460 #endif
461
462 #ifdef OSF1_ENH_SEC
463 /****************************************************************************
464 an enhanced crypt for OSF1
465 ****************************************************************************/
466 static char *osf1_bigcrypt(char *password, char *salt1)
467 {
468         static char result[AUTH_MAX_PASSWD_LENGTH] = "";
469         char *p1;
470         char *p2 = password;
471         char salt[3];
472         int i;
473         int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
474         if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
475                 parts++;
476
477         StrnCpy(salt, salt1, 2);
478         StrnCpy(result, salt1, 2);
479         result[2] = '\0';
480
481         for (i = 0; i < parts; i++) {
482                 p1 = crypt(p2, salt);
483                 strncat(result, p1 + 2,
484                         AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
485                 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
486                 p2 += AUTH_CLEARTEXT_SEG_CHARS;
487         }
488
489         return (result);
490 }
491 #endif
492
493
494 /****************************************************************************
495 apply a function to upper/lower case combinations
496 of a string and return true if one of them returns true.
497 try all combinations with N uppercase letters.
498 offset is the first char to try and change (start with 0)
499 it assumes the string starts lowercased
500 ****************************************************************************/
501 static NTSTATUS string_combinations2(char *s, int offset,
502                                      NTSTATUS (*fn)(const char *s,
503                                                     void *private_data),
504                                      int N, void *private_data)
505 {
506         int len = strlen(s);
507         int i;
508         NTSTATUS nt_status;
509
510 #ifdef PASSWORD_LENGTH
511         len = MIN(len, PASSWORD_LENGTH);
512 #endif
513
514         if (N <= 0 || offset >= len)
515                 return (fn(s, private_data));
516
517         for (i = offset; i < (len - (N - 1)); i++) {
518                 char c = s[i];
519                 if (!islower_ascii(c))
520                         continue;
521                 s[i] = toupper_ascii(c);
522                 nt_status = string_combinations2(s, i + 1, fn, N - 1,
523                                                  private_data);
524                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
525                         return nt_status;
526                 }
527                 s[i] = c;
528         }
529         return (NT_STATUS_WRONG_PASSWORD);
530 }
531
532 /****************************************************************************
533 apply a function to upper/lower case combinations
534 of a string and return true if one of them returns true.
535 try all combinations with up to N uppercase letters.
536 offset is the first char to try and change (start with 0)
537 it assumes the string starts lowercased
538 ****************************************************************************/
539 static NTSTATUS string_combinations(char *s,
540                                     NTSTATUS (*fn)(const char *s,
541                                                    void *private_data),
542                                     int N, void *private_data)
543 {
544         int n;
545         NTSTATUS nt_status;
546         for (n = 1; n <= N; n++) {
547                 nt_status = string_combinations2(s, 0, fn, n, private_data);
548                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
549                         return nt_status;
550                 }
551         }
552         return NT_STATUS_WRONG_PASSWORD;
553 }
554
555
556 /****************************************************************************
557 core of password checking routine
558 ****************************************************************************/
559 static NTSTATUS password_check(const char *password, void *private_data)
560 {
561 #ifdef WITH_PAM
562         const char *rhost = (const char *)private_data;
563         return smb_pam_passcheck(get_this_user(), rhost, password);
564 #else
565
566         bool ret;
567
568 #ifdef WITH_AFS
569         if (afs_auth(get_this_user(), password))
570                 return NT_STATUS_OK;
571 #endif /* WITH_AFS */
572
573 #ifdef WITH_DFS
574         if (dfs_auth(get_this_user(), password))
575                 return NT_STATUS_OK;
576 #endif /* WITH_DFS */
577
578 #ifdef OSF1_ENH_SEC
579
580         ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
581                       get_this_crypted()) == 0);
582         if (!ret) {
583                 DEBUG(2,
584                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
585                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
586         }
587         if (ret) {
588                 return NT_STATUS_OK;
589         } else {
590                 return NT_STATUS_WRONG_PASSWORD;
591         }
592
593 #endif /* OSF1_ENH_SEC */
594
595 #ifdef ULTRIX_AUTH
596         ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
597         if (ret) {
598                 return NT_STATUS_OK;
599         } else {
600                 return NT_STATUS_WRONG_PASSWORD;
601         }
602
603 #endif /* ULTRIX_AUTH */
604
605 #ifdef LINUX_BIGCRYPT
606         ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
607         if (ret) {
608                 return NT_STATUS_OK;
609         } else {
610                 return NT_STATUS_WRONG_PASSWORD;
611         }
612 #endif /* LINUX_BIGCRYPT */
613
614 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
615
616         /*
617          * Some systems have bigcrypt in the C library but might not
618          * actually use it for the password hashes (HPUX 10.20) is
619          * a noteable example. So we try bigcrypt first, followed
620          * by crypt.
621          */
622
623         if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
624                 return NT_STATUS_OK;
625         else
626                 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
627         if (ret) {
628                 return NT_STATUS_OK;
629         } else {
630                 return NT_STATUS_WRONG_PASSWORD;
631         }
632 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
633
634 #ifdef HAVE_BIGCRYPT
635         ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
636         if (ret) {
637                 return NT_STATUS_OK;
638         } else {
639                 return NT_STATUS_WRONG_PASSWORD;
640         }
641 #endif /* HAVE_BIGCRYPT */
642
643 #ifndef HAVE_CRYPT
644         DEBUG(1, ("Warning - no crypt available\n"));
645         return NT_STATUS_LOGON_FAILURE;
646 #else /* HAVE_CRYPT */
647         ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
648         if (ret) {
649                 return NT_STATUS_OK;
650         } else {
651                 return NT_STATUS_WRONG_PASSWORD;
652         }
653 #endif /* HAVE_CRYPT */
654 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
655 #endif /* WITH_PAM */
656 }
657
658
659
660 /****************************************************************************
661 CHECK if a username/password is OK
662 the function pointer fn() points to a function to call when a successful
663 match is found and is used to update the encrypted password file 
664 return NT_STATUS_OK on correct match, appropriate error otherwise
665 ****************************************************************************/
666
667 NTSTATUS pass_check(const struct passwd *pass,
668                     const char *user,
669                     const char *rhost,
670                     const char *password,
671                     bool run_cracker)
672 {
673         char *pass2 = NULL;
674         int level = lp_passwordlevel();
675
676         NTSTATUS nt_status;
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 }