docs: Remove duplicate synonym min protocol.
[Samba.git] / source3 / auth / pass_check.c
blobf2d1fc241bcf8a4f4d060c868855cf8bfb337d2f
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"
24 #include "system/passwd.h"
25 #include "auth.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_AUTH
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
36 /* these are kept here to keep the string_combinations function simple */
37 static char *ths_user;
39 static const char *get_this_user(void)
41 if (!ths_user) {
42 return "";
44 return ths_user;
47 #if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
48 static const char *set_this_user(const char *newuser)
50 char *orig_user = ths_user;
51 ths_user = SMB_STRDUP(newuser);
52 SAFE_FREE(orig_user);
53 return ths_user;
55 #endif
57 #if !defined(WITH_PAM)
58 static char *ths_salt;
59 /* This must be writable. */
60 static char *get_this_salt(void)
62 return ths_salt;
65 /* We may be setting a modified version of the same
66 * string, so don't free before use. */
68 static const char *set_this_salt(const char *newsalt)
70 char *orig_salt = ths_salt;
71 ths_salt = SMB_STRDUP(newsalt);
72 SAFE_FREE(orig_salt);
73 return ths_salt;
76 static char *ths_crypted;
77 static const char *get_this_crypted(void)
79 if (!ths_crypted) {
80 return "";
82 return ths_crypted;
85 static const char *set_this_crypted(const char *newcrypted)
87 char *orig_crypted = ths_crypted;
88 ths_crypted = SMB_STRDUP(newcrypted);
89 SAFE_FREE(orig_crypted);
90 return ths_crypted;
92 #endif
94 #ifdef WITH_AFS
96 #include <afs/stds.h>
97 #include <afs/kautils.h>
99 /*******************************************************************
100 check on AFS authentication
101 ********************************************************************/
102 static bool afs_auth(char *user, char *password)
104 long password_expires = 0;
105 char *reason;
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)
118 return (True);
120 DEBUG(1,
121 ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
122 return (False);
124 #endif
127 #ifdef WITH_DFS
129 #include <dce/dce_error.h>
130 #include <dce/sec_login.h>
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 :
137 - Server credentials may expire
138 - Client credential cache files have wrong owner
139 - purge_context() function is called with invalid argument
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 ******************************************************************/
145 sec_login_handle_t my_dce_sec_context;
146 int dcelogin_atmost_once = 0;
148 /*******************************************************************
149 check on a DCE/DFS authentication
150 ********************************************************************/
151 static bool dfs_auth(char *user, char *password)
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;
165 if (dcelogin_atmost_once)
166 return (False);
168 #ifdef HAVE_CRYPT
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!
175 if (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()))
177 return (False);
179 #endif
181 sec_login_get_current_context(&my_dce_sec_context, &err);
182 if (err != error_status_ok)
184 dce_error_inq_text(err, dce_errstr, &err2);
185 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
187 return (False);
190 sec_login_certify_identity(my_dce_sec_context, &err);
191 if (err != error_status_ok)
193 dce_error_inq_text(err, dce_errstr, &err2);
194 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
196 return (False);
199 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
200 if (err != error_status_ok)
202 dce_error_inq_text(err, dce_errstr, &err2);
203 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
205 return (False);
208 time(&current_time);
210 if (expire_time < (current_time + 60))
212 struct passwd *pw;
213 sec_passwd_rec_t *key;
215 sec_login_get_pwent(my_dce_sec_context,
216 (sec_login_passwd_t *) & pw, &err);
217 if (err != error_status_ok)
219 dce_error_inq_text(err, dce_errstr, &err2);
220 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
222 return (False);
225 sec_login_refresh_identity(my_dce_sec_context, &err);
226 if (err != error_status_ok)
228 dce_error_inq_text(err, dce_errstr, &err2);
229 DEBUG(0, ("DCE can't refresh identity. %s\n",
230 dce_errstr));
232 return (False);
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)
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));
245 return (False);
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)
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));
259 sec_key_mgmt_free_key(key, &err);
260 if (err != error_status_ok)
262 dce_error_inq_text(err, dce_errstr, &err2);
263 DEBUG(0, ("DCE can't free key.\n", dce_errstr));
267 if (sec_login_setup_identity((unsigned char *)user,
268 sec_login_no_flags,
269 &my_dce_sec_context, &err) == 0)
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);
277 sec_login_get_pwent(my_dce_sec_context,
278 (sec_login_passwd_t *) & pw, &err);
279 if (err != error_status_ok)
281 dce_error_inq_text(err, dce_errstr, &err2);
282 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
284 return (False);
287 sec_login_purge_context(&my_dce_sec_context, &err);
288 if (err != error_status_ok)
290 dce_error_inq_text(err, dce_errstr, &err2);
291 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
293 return (False);
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.
305 egid = getegid();
307 set_effective_gid(pw->pw_gid);
308 set_effective_uid(pw->pw_uid);
310 if (sec_login_setup_identity((unsigned char *)user,
311 sec_login_no_flags,
312 &my_dce_sec_context, &err) == 0)
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;
320 sec_login_get_pwent(my_dce_sec_context,
321 (sec_login_passwd_t *) & pw, &err);
322 if (err != error_status_ok)
324 dce_error_inq_text(err, dce_errstr, &err2);
325 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
326 goto err;
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;
334 sec_login_validate_identity(my_dce_sec_context,
335 &passwd_rec, &password_reset,
336 &auth_src, &err);
337 if (err != error_status_ok)
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;
346 sec_login_certify_identity(my_dce_sec_context, &err);
347 if (err != error_status_ok)
349 dce_error_inq_text(err, dce_errstr, &err2);
350 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
351 goto err;
354 if (auth_src != sec_login_auth_src_network)
356 DEBUG(0, ("DCE context has no network credentials.\n"));
359 sec_login_set_context(my_dce_sec_context, &err);
360 if (err != error_status_ok)
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));
367 sec_login_purge_context(&my_dce_sec_context, &err);
368 goto err;
371 sec_login_get_pwent(my_dce_sec_context,
372 (sec_login_passwd_t *) & pw, &err);
373 if (err != error_status_ok)
375 dce_error_inq_text(err, dce_errstr, &err2);
376 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
377 goto err;
380 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
381 user, getpid()));
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));
392 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
393 if (err != error_status_ok)
395 dce_error_inq_text(err, dce_errstr, &err2);
396 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
397 goto err;
400 set_effective_uid(0);
401 set_effective_gid(0);
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));
411 dcelogin_atmost_once = 1;
412 return (True);
414 err:
416 /* Go back to root, JRA. */
417 set_effective_uid(0);
418 set_effective_gid(egid);
419 return (False);
422 void dfs_unlogin(void)
424 error_status_t err;
425 int err2;
426 unsigned char dce_errstr[dce_c_error_string_len];
428 sec_login_purge_context(&my_dce_sec_context, &err);
429 if (err != error_status_ok)
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));
437 #endif
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)
445 #define LINUX_PASSWORD_SEG_CHARS 8
446 char salt[3];
447 int i;
449 StrnCpy(salt, salt1, 2);
450 crypted += 2;
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);
460 return (1);
462 #endif
464 #ifdef OSF1_ENH_SEC
465 /****************************************************************************
466 an enhanced crypt for OSF1
467 ****************************************************************************/
468 static char *osf1_bigcrypt(char *password, char *salt1)
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++;
479 StrnCpy(salt, salt1, 2);
480 StrnCpy(result, salt1, 2);
481 result[2] = '\0';
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;
491 return (result);
493 #endif
496 /****************************************************************************
497 apply a function to upper/lower case combinations
498 of a string and return true if one of them returns true.
499 try all combinations with N uppercase letters.
500 offset is the first char to try and change (start with 0)
501 it assumes the string starts lowercased
502 ****************************************************************************/
503 static NTSTATUS string_combinations2(char *s, int offset,
504 NTSTATUS (*fn)(const char *s,
505 const void *private_data),
506 int N, const void *private_data)
508 int len = strlen(s);
509 int i;
510 NTSTATUS nt_status;
512 #ifdef PASSWORD_LENGTH
513 len = MIN(len, PASSWORD_LENGTH);
514 #endif
516 if (N <= 0 || offset >= len)
517 return (fn(s, private_data));
519 for (i = offset; i < (len - (N - 1)); i++) {
520 char c = s[i];
521 if (!islower_m(c))
522 continue;
523 s[i] = toupper_m(c);
524 nt_status = string_combinations2(s, i + 1, fn, N - 1,
525 private_data);
526 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
527 return nt_status;
529 s[i] = c;
531 return (NT_STATUS_WRONG_PASSWORD);
534 /****************************************************************************
535 apply a function to upper/lower case combinations
536 of a string and return true if one of them returns true.
537 try all combinations with up to N uppercase letters.
538 offset is the first char to try and change (start with 0)
539 it assumes the string starts lowercased
540 ****************************************************************************/
541 static NTSTATUS string_combinations(char *s,
542 NTSTATUS (*fn)(const char *s,
543 const void *private_data),
544 int N, const void *private_data)
546 int n;
547 NTSTATUS nt_status;
548 for (n = 1; n <= N; n++) {
549 nt_status = string_combinations2(s, 0, fn, n, private_data);
550 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
551 return nt_status;
554 return NT_STATUS_WRONG_PASSWORD;
558 /****************************************************************************
559 core of password checking routine
560 ****************************************************************************/
561 static NTSTATUS password_check(const char *password, const void *private_data)
563 #ifdef WITH_PAM
564 const char *rhost = (const char *)private_data;
565 return smb_pam_passcheck(get_this_user(), rhost, password);
566 #else
568 bool ret;
570 #ifdef WITH_AFS
571 if (afs_auth(get_this_user(), password))
572 return NT_STATUS_OK;
573 #endif /* WITH_AFS */
575 #ifdef WITH_DFS
576 if (dfs_auth(get_this_user(), password))
577 return NT_STATUS_OK;
578 #endif /* WITH_DFS */
580 #ifdef OSF1_ENH_SEC
582 ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
583 get_this_crypted()) == 0);
584 if (!ret) {
585 DEBUG(2,
586 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
587 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
589 if (ret) {
590 return NT_STATUS_OK;
591 } else {
592 return NT_STATUS_WRONG_PASSWORD;
595 #endif /* OSF1_ENH_SEC */
597 #ifdef ULTRIX_AUTH
598 ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
599 if (ret) {
600 return NT_STATUS_OK;
601 } else {
602 return NT_STATUS_WRONG_PASSWORD;
605 #endif /* ULTRIX_AUTH */
607 #ifdef LINUX_BIGCRYPT
608 ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
609 if (ret) {
610 return NT_STATUS_OK;
611 } else {
612 return NT_STATUS_WRONG_PASSWORD;
614 #endif /* LINUX_BIGCRYPT */
616 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
619 * Some systems have bigcrypt in the C library but might not
620 * actually use it for the password hashes (HPUX 10.20) is
621 * a noteable example. So we try bigcrypt first, followed
622 * by crypt.
625 if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
626 return NT_STATUS_OK;
627 else
628 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
629 if (ret) {
630 return NT_STATUS_OK;
631 } else {
632 return NT_STATUS_WRONG_PASSWORD;
634 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
636 #ifdef HAVE_BIGCRYPT
637 ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
638 if (ret) {
639 return NT_STATUS_OK;
640 } else {
641 return NT_STATUS_WRONG_PASSWORD;
643 #endif /* HAVE_BIGCRYPT */
645 #ifndef HAVE_CRYPT
646 DEBUG(1, ("Warning - no crypt available\n"));
647 return NT_STATUS_LOGON_FAILURE;
648 #else /* HAVE_CRYPT */
649 ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
650 if (ret) {
651 return NT_STATUS_OK;
652 } else {
653 return NT_STATUS_WRONG_PASSWORD;
655 #endif /* HAVE_CRYPT */
656 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
657 #endif /* WITH_PAM */
662 /****************************************************************************
663 CHECK if a username/password is OK
664 the function pointer fn() points to a function to call when a successful
665 match is found and is used to update the encrypted password file
666 return NT_STATUS_OK on correct match, appropriate error otherwise
667 ****************************************************************************/
669 NTSTATUS pass_check(const struct passwd *pass,
670 const char *user,
671 const char *rhost,
672 const char *password,
673 bool run_cracker)
675 char *pass2 = NULL;
676 int level = lp_passwordlevel();
678 NTSTATUS nt_status;
680 #ifdef DEBUG_PASSWORD
681 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
682 #endif
684 if (!password)
685 return NT_STATUS_LOGON_FAILURE;
687 if ((!*password) && !lp_null_passwords())
688 return NT_STATUS_LOGON_FAILURE;
690 #if defined(WITH_PAM)
693 * If we're using PAM we want to short-circuit all the
694 * checks below and dive straight into the PAM code.
697 if (set_this_user(user) == NULL) {
698 return NT_STATUS_NO_MEMORY;
701 DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
703 #else /* Not using PAM */
705 DEBUG(4, ("pass_check: Checking password for user %s\n", user));
707 if (!pass) {
708 DEBUG(3, ("Couldn't find user %s\n", user));
709 return NT_STATUS_NO_SUCH_USER;
713 /* Copy into global for the convenience of looping code */
714 /* Also the place to keep the 'password' no matter what
715 crazy struct it started in... */
716 if (set_this_crypted(pass->pw_passwd) == NULL) {
717 return NT_STATUS_NO_MEMORY;
719 if (set_this_salt(pass->pw_passwd) == NULL) {
720 return NT_STATUS_NO_MEMORY;
723 #ifdef HAVE_GETSPNAM
725 struct spwd *spass;
727 /* many shadow systems require you to be root to get
728 the password, in most cases this should already be
729 the case when this function is called, except
730 perhaps for IPC password changing requests */
732 spass = getspnam(pass->pw_name);
733 if (spass && spass->sp_pwdp) {
734 if (set_this_crypted(spass->sp_pwdp) == NULL) {
735 return NT_STATUS_NO_MEMORY;
737 if (set_this_salt(spass->sp_pwdp) == NULL) {
738 return NT_STATUS_NO_MEMORY;
742 #elif defined(IA_UINFO)
744 /* Need to get password with SVR4.2's ia_ functions
745 instead of get{sp,pw}ent functions. Required by
746 UnixWare 2.x, tested on version
747 2.1. (tangent@cyberport.com) */
748 uinfo_t uinfo;
749 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
750 ia_get_logpwd(uinfo, &(pass->pw_passwd));
752 #endif
754 #ifdef HAVE_GETPRPWNAM
756 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
757 if (pr_pw && pr_pw->ufld.fd_encrypt) {
758 if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
759 return NT_STATUS_NO_MEMORY;
763 #endif
765 #ifdef HAVE_GETPWANAM
767 struct passwd_adjunct *pwret;
768 pwret = getpwanam(s);
769 if (pwret && pwret->pwa_passwd) {
770 if (set_this_crypted(pwret->pwa_passwd) == NULL) {
771 return NT_STATUS_NO_MEMORY;
775 #endif
777 #ifdef OSF1_ENH_SEC
779 struct pr_passwd *mypasswd;
780 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
781 user));
782 mypasswd = getprpwnam(user);
783 if (mypasswd) {
784 if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
785 return NT_STATUS_NO_MEMORY;
787 if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
788 return NT_STATUS_NO_MEMORY;
790 } else {
791 DEBUG(5,
792 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
793 user));
796 #endif
798 #ifdef ULTRIX_AUTH
800 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
801 if (ap) {
802 if (set_this_crypted(ap->a_password) == NULL) {
803 endauthent();
804 return NT_STATUS_NO_MEMORY;
806 endauthent();
809 #endif
811 #if defined(HAVE_TRUNCATED_SALT)
812 /* crypt on some platforms (HPUX in particular)
813 won't work with more than 2 salt characters. */
815 char *trunc_salt = get_this_salt();
816 if (!trunc_salt || strlen(trunc_salt) < 2) {
817 return NT_STATUS_LOGON_FAILURE;
819 trunc_salt[2] = 0;
820 if (set_this_salt(trunc_salt) == NULL) {
821 return NT_STATUS_NO_MEMORY;
824 #endif
826 if (!get_this_crypted() || !*get_this_crypted()) {
827 if (!lp_null_passwords()) {
828 DEBUG(2, ("Disallowing %s with null password\n",
829 get_this_user()));
830 return NT_STATUS_LOGON_FAILURE;
832 if (!*password) {
833 DEBUG(3,
834 ("Allowing access to %s with null password\n",
835 get_this_user()));
836 return NT_STATUS_OK;
840 #endif /* defined(WITH_PAM) */
842 /* try it as it came to us */
843 nt_status = password_check(password, (const void *)rhost);
844 if NT_STATUS_IS_OK(nt_status) {
845 return (nt_status);
846 } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
847 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
848 return (nt_status);
851 if (!run_cracker) {
852 return (nt_status);
855 /* if the password was given to us with mixed case then we don't
856 * need to proceed as we know it hasn't been case modified by the
857 * client */
858 if (strhasupper(password) && strhaslower(password)) {
859 return nt_status;
862 /* make a copy of it */
863 pass2 = talloc_strdup(talloc_tos(), password);
864 if (!pass2) {
865 return NT_STATUS_NO_MEMORY;
868 /* try all lowercase if it's currently all uppercase */
869 if (strhasupper(pass2)) {
870 if (!strlower_m(pass2)) {
871 return NT_STATUS_INVALID_PARAMETER;
873 nt_status = password_check(pass2, (const void *)rhost);
874 if (NT_STATUS_IS_OK(nt_status)) {
875 return (nt_status);
879 /* give up? */
880 if (level < 1) {
881 return NT_STATUS_WRONG_PASSWORD;
884 /* last chance - all combinations of up to level chars upper! */
885 if (!strlower_m(pass2)) {
886 return NT_STATUS_INVALID_PARAMETER;
889 nt_status = string_combinations(pass2, password_check, level,
890 (const void *)rhost);
891 if (NT_STATUS_IS_OK(nt_status)) {
892 return nt_status;
895 return NT_STATUS_WRONG_PASSWORD;