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