s3: Lift smbd_server_fd() from smb_pam_passcheck
[Samba/ita.git] / source3 / auth / pass_check.c
bloba4bc6b509c0a2f62b02c202583281bd78f6c7023
1 /*
2 Unix SMB/CIFS implementation.
3 Password checking
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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/>.
20 /* this module is for checking a username/password against a system
21 password database. The SMB encrypted password support is elsewhere */
23 #include "includes.h"
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_AUTH
28 /* these are kept here to keep the string_combinations function simple */
29 static char *ths_user;
31 static const char *get_this_user(void)
33 if (!ths_user) {
34 return "";
36 return ths_user;
39 #if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
40 static const char *set_this_user(const char *newuser)
42 char *orig_user = ths_user;
43 ths_user = SMB_STRDUP(newuser);
44 SAFE_FREE(orig_user);
45 return ths_user;
47 #endif
49 #if !defined(WITH_PAM)
50 static char *ths_salt;
51 /* This must be writable. */
52 static char *get_this_salt(void)
54 return ths_salt;
57 /* We may be setting a modified version of the same
58 * string, so don't free before use. */
60 static const char *set_this_salt(const char *newsalt)
62 char *orig_salt = ths_salt;
63 ths_salt = SMB_STRDUP(newsalt);
64 SAFE_FREE(orig_salt);
65 return ths_salt;
68 static char *ths_crypted;
69 static const char *get_this_crypted(void)
71 if (!ths_crypted) {
72 return "";
74 return ths_crypted;
77 static const char *set_this_crypted(const char *newcrypted)
79 char *orig_crypted = ths_crypted;
80 ths_crypted = SMB_STRDUP(newcrypted);
81 SAFE_FREE(orig_crypted);
82 return ths_crypted;
84 #endif
86 #ifdef WITH_AFS
88 #include <afs/stds.h>
89 #include <afs/kautils.h>
91 /*******************************************************************
92 check on AFS authentication
93 ********************************************************************/
94 static bool afs_auth(char *user, char *password)
96 long password_expires = 0;
97 char *reason;
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)
110 return (True);
112 DEBUG(1,
113 ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
114 return (False);
116 #endif
119 #ifdef WITH_DFS
121 #include <dce/dce_error.h>
122 #include <dce/sec_login.h>
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 :
129 - Server credentials may expire
130 - Client credential cache files have wrong owner
131 - purge_context() function is called with invalid argument
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 ******************************************************************/
137 sec_login_handle_t my_dce_sec_context;
138 int dcelogin_atmost_once = 0;
140 /*******************************************************************
141 check on a DCE/DFS authentication
142 ********************************************************************/
143 static bool dfs_auth(char *user, char *password)
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;
157 if (dcelogin_atmost_once)
158 return (False);
160 #ifdef HAVE_CRYPT
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!
167 if (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()))
169 return (False);
171 #endif
173 sec_login_get_current_context(&my_dce_sec_context, &err);
174 if (err != error_status_ok)
176 dce_error_inq_text(err, dce_errstr, &err2);
177 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
179 return (False);
182 sec_login_certify_identity(my_dce_sec_context, &err);
183 if (err != error_status_ok)
185 dce_error_inq_text(err, dce_errstr, &err2);
186 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
188 return (False);
191 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
192 if (err != error_status_ok)
194 dce_error_inq_text(err, dce_errstr, &err2);
195 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
197 return (False);
200 time(&current_time);
202 if (expire_time < (current_time + 60))
204 struct passwd *pw;
205 sec_passwd_rec_t *key;
207 sec_login_get_pwent(my_dce_sec_context,
208 (sec_login_passwd_t *) & pw, &err);
209 if (err != error_status_ok)
211 dce_error_inq_text(err, dce_errstr, &err2);
212 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
214 return (False);
217 sec_login_refresh_identity(my_dce_sec_context, &err);
218 if (err != error_status_ok)
220 dce_error_inq_text(err, dce_errstr, &err2);
221 DEBUG(0, ("DCE can't refresh identity. %s\n",
222 dce_errstr));
224 return (False);
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)
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));
237 return (False);
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)
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));
251 sec_key_mgmt_free_key(key, &err);
252 if (err != error_status_ok)
254 dce_error_inq_text(err, dce_errstr, &err2);
255 DEBUG(0, ("DCE can't free key.\n", dce_errstr));
259 if (sec_login_setup_identity((unsigned char *)user,
260 sec_login_no_flags,
261 &my_dce_sec_context, &err) == 0)
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);
269 sec_login_get_pwent(my_dce_sec_context,
270 (sec_login_passwd_t *) & pw, &err);
271 if (err != error_status_ok)
273 dce_error_inq_text(err, dce_errstr, &err2);
274 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
276 return (False);
279 sec_login_purge_context(&my_dce_sec_context, &err);
280 if (err != error_status_ok)
282 dce_error_inq_text(err, dce_errstr, &err2);
283 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
285 return (False);
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.
297 egid = getegid();
299 set_effective_gid(pw->pw_gid);
300 set_effective_uid(pw->pw_uid);
302 if (sec_login_setup_identity((unsigned char *)user,
303 sec_login_no_flags,
304 &my_dce_sec_context, &err) == 0)
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;
312 sec_login_get_pwent(my_dce_sec_context,
313 (sec_login_passwd_t *) & pw, &err);
314 if (err != error_status_ok)
316 dce_error_inq_text(err, dce_errstr, &err2);
317 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
318 goto err;
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;
326 sec_login_validate_identity(my_dce_sec_context,
327 &passwd_rec, &password_reset,
328 &auth_src, &err);
329 if (err != error_status_ok)
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;
338 sec_login_certify_identity(my_dce_sec_context, &err);
339 if (err != error_status_ok)
341 dce_error_inq_text(err, dce_errstr, &err2);
342 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
343 goto err;
346 if (auth_src != sec_login_auth_src_network)
348 DEBUG(0, ("DCE context has no network credentials.\n"));
351 sec_login_set_context(my_dce_sec_context, &err);
352 if (err != error_status_ok)
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));
359 sec_login_purge_context(&my_dce_sec_context, &err);
360 goto err;
363 sec_login_get_pwent(my_dce_sec_context,
364 (sec_login_passwd_t *) & pw, &err);
365 if (err != error_status_ok)
367 dce_error_inq_text(err, dce_errstr, &err2);
368 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
369 goto err;
372 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
373 user, sys_getpid()));
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));
384 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
385 if (err != error_status_ok)
387 dce_error_inq_text(err, dce_errstr, &err2);
388 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
389 goto err;
392 set_effective_uid(0);
393 set_effective_gid(0);
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));
403 dcelogin_atmost_once = 1;
404 return (True);
406 err:
408 /* Go back to root, JRA. */
409 set_effective_uid(0);
410 set_effective_gid(egid);
411 return (False);
414 void dfs_unlogin(void)
416 error_status_t err;
417 int err2;
418 unsigned char dce_errstr[dce_c_error_string_len];
420 sec_login_purge_context(&my_dce_sec_context, &err);
421 if (err != error_status_ok)
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));
429 #endif
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)
437 #define LINUX_PASSWORD_SEG_CHARS 8
438 char salt[3];
439 int i;
441 StrnCpy(salt, salt1, 2);
442 crypted += 2;
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);
452 return (1);
454 #endif
456 #ifdef OSF1_ENH_SEC
457 /****************************************************************************
458 an enhanced crypt for OSF1
459 ****************************************************************************/
460 static char *osf1_bigcrypt(char *password, char *salt1)
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++;
471 StrnCpy(salt, salt1, 2);
472 StrnCpy(result, salt1, 2);
473 result[2] = '\0';
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;
483 return (result);
485 #endif
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)
500 int len = strlen(s);
501 int i;
502 NTSTATUS nt_status;
504 #ifdef PASSWORD_LENGTH
505 len = MIN(len, PASSWORD_LENGTH);
506 #endif
508 if (N <= 0 || offset >= len)
509 return (fn(s, private_data));
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;
521 s[i] = c;
523 return (NT_STATUS_WRONG_PASSWORD);
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)
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;
546 return NT_STATUS_WRONG_PASSWORD;
550 /****************************************************************************
551 core of password checking routine
552 ****************************************************************************/
553 static NTSTATUS password_check(const char *password, void *private_data)
555 #ifdef WITH_PAM
556 const char *rhost;
557 char addr[INET6_ADDRSTRLEN];
559 rhost = client_name(smbd_server_fd());
560 if (strequal(rhost,"UNKNOWN"))
561 rhost = client_addr(smbd_server_fd(), addr, sizeof(addr));
563 return smb_pam_passcheck(get_this_user(), rhost, password);
564 #else
566 bool ret;
568 #ifdef WITH_AFS
569 if (afs_auth(get_this_user(), password))
570 return NT_STATUS_OK;
571 #endif /* WITH_AFS */
573 #ifdef WITH_DFS
574 if (dfs_auth(get_this_user(), password))
575 return NT_STATUS_OK;
576 #endif /* WITH_DFS */
578 #ifdef OSF1_ENH_SEC
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);
587 if (ret) {
588 return NT_STATUS_OK;
589 } else {
590 return NT_STATUS_WRONG_PASSWORD;
593 #endif /* OSF1_ENH_SEC */
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;
603 #endif /* ULTRIX_AUTH */
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;
612 #endif /* LINUX_BIGCRYPT */
614 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
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.
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;
632 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
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;
641 #endif /* HAVE_BIGCRYPT */
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;
653 #endif /* HAVE_CRYPT */
654 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
655 #endif /* WITH_PAM */
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 ****************************************************************************/
667 NTSTATUS pass_check(const struct passwd *pass,
668 const char *user,
669 const char *password,
670 bool run_cracker)
672 char *pass2 = NULL;
673 int level = lp_passwordlevel();
675 NTSTATUS nt_status;
677 #ifdef DEBUG_PASSWORD
678 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
679 #endif
681 if (!password)
682 return NT_STATUS_LOGON_FAILURE;
684 if ((!*password) && !lp_null_passwords())
685 return NT_STATUS_LOGON_FAILURE;
687 #if defined(WITH_PAM)
690 * If we're using PAM we want to short-circuit all the
691 * checks below and dive straight into the PAM code.
694 if (set_this_user(user) == NULL) {
695 return NT_STATUS_NO_MEMORY;
698 DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
700 #else /* Not using PAM */
702 DEBUG(4, ("pass_check: Checking password for user %s\n", user));
704 if (!pass) {
705 DEBUG(3, ("Couldn't find user %s\n", user));
706 return NT_STATUS_NO_SUCH_USER;
710 /* Copy into global for the convenience of looping code */
711 /* Also the place to keep the 'password' no matter what
712 crazy struct it started in... */
713 if (set_this_crypted(pass->pw_passwd) == NULL) {
714 return NT_STATUS_NO_MEMORY;
716 if (set_this_salt(pass->pw_passwd) == NULL) {
717 return NT_STATUS_NO_MEMORY;
720 #ifdef HAVE_GETSPNAM
722 struct spwd *spass;
724 /* many shadow systems require you to be root to get
725 the password, in most cases this should already be
726 the case when this function is called, except
727 perhaps for IPC password changing requests */
729 spass = getspnam(pass->pw_name);
730 if (spass && spass->sp_pwdp) {
731 if (set_this_crypted(spass->sp_pwdp) == NULL) {
732 return NT_STATUS_NO_MEMORY;
734 if (set_this_salt(spass->sp_pwdp) == NULL) {
735 return NT_STATUS_NO_MEMORY;
739 #elif defined(IA_UINFO)
741 /* Need to get password with SVR4.2's ia_ functions
742 instead of get{sp,pw}ent functions. Required by
743 UnixWare 2.x, tested on version
744 2.1. (tangent@cyberport.com) */
745 uinfo_t uinfo;
746 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
747 ia_get_logpwd(uinfo, &(pass->pw_passwd));
749 #endif
751 #ifdef HAVE_GETPRPWNAM
753 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
754 if (pr_pw && pr_pw->ufld.fd_encrypt) {
755 if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
756 return NT_STATUS_NO_MEMORY;
760 #endif
762 #ifdef HAVE_GETPWANAM
764 struct passwd_adjunct *pwret;
765 pwret = getpwanam(s);
766 if (pwret && pwret->pwa_passwd) {
767 if (set_this_crypted(pwret->pwa_passwd) == NULL) {
768 return NT_STATUS_NO_MEMORY;
772 #endif
774 #ifdef OSF1_ENH_SEC
776 struct pr_passwd *mypasswd;
777 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
778 user));
779 mypasswd = getprpwnam(user);
780 if (mypasswd) {
781 if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
782 return NT_STATUS_NO_MEMORY;
784 if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
785 return NT_STATUS_NO_MEMORY;
787 } else {
788 DEBUG(5,
789 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
790 user));
793 #endif
795 #ifdef ULTRIX_AUTH
797 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
798 if (ap) {
799 if (set_this_crypted(ap->a_password) == NULL) {
800 endauthent();
801 return NT_STATUS_NO_MEMORY;
803 endauthent();
806 #endif
808 #if defined(HAVE_TRUNCATED_SALT)
809 /* crypt on some platforms (HPUX in particular)
810 won't work with more than 2 salt characters. */
812 char *trunc_salt = get_this_salt();
813 if (!trunc_salt || strlen(trunc_salt) < 2) {
814 return NT_STATUS_LOGON_FAILURE;
816 trunc_salt[2] = 0;
817 if (set_this_salt(trunc_salt) == NULL) {
818 return NT_STATUS_NO_MEMORY;
821 #endif
823 if (!get_this_crypted() || !*get_this_crypted()) {
824 if (!lp_null_passwords()) {
825 DEBUG(2, ("Disallowing %s with null password\n",
826 get_this_user()));
827 return NT_STATUS_LOGON_FAILURE;
829 if (!*password) {
830 DEBUG(3,
831 ("Allowing access to %s with null password\n",
832 get_this_user()));
833 return NT_STATUS_OK;
837 #endif /* defined(WITH_PAM) */
839 /* try it as it came to us */
840 nt_status = password_check(password, NULL);
841 if NT_STATUS_IS_OK(nt_status) {
842 return (nt_status);
843 } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
844 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
845 return (nt_status);
848 if (!run_cracker) {
849 return (nt_status);
852 /* if the password was given to us with mixed case then we don't
853 * need to proceed as we know it hasn't been case modified by the
854 * client */
855 if (strhasupper(password) && strhaslower(password)) {
856 return nt_status;
859 /* make a copy of it */
860 pass2 = talloc_strdup(talloc_tos(), password);
861 if (!pass2) {
862 return NT_STATUS_NO_MEMORY;
865 /* try all lowercase if it's currently all uppercase */
866 if (strhasupper(pass2)) {
867 strlower_m(pass2);
868 nt_status = password_check(pass2, NULL);
869 if NT_STATUS_IS_OK(nt_status) {
870 return (nt_status);
874 /* give up? */
875 if (level < 1) {
876 return NT_STATUS_WRONG_PASSWORD;
879 /* last chance - all combinations of up to level chars upper! */
880 strlower_m(pass2);
882 nt_status = string_combinations(pass2, password_check, level, NULL);
883 if (NT_STATUS_IS_OK(nt_status)) {
884 return nt_status;
887 return NT_STATUS_WRONG_PASSWORD;