source: trunk-3.0/source/auth/pass_check.c@ 101

Last change on this file since 101 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 20.4 KB
Line 
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/* this module is for checking a username/password against a system
22 password database. The SMB encrypted password support is elsewhere */
23
24#include "includes.h"
25
26#undef DBGC_CLASS
27#define DBGC_CLASS DBGC_AUTH
28
29/* these are kept here to keep the string_combinations function simple */
30static fstring this_user;
31#if !defined(WITH_PAM)
32static fstring this_salt;
33static fstring this_crypted;
34#endif
35
36#ifdef WITH_AFS
37
38#include <afs/stds.h>
39#include <afs/kautils.h>
40
41/*******************************************************************
42check on AFS authentication
43********************************************************************/
44static BOOL afs_auth(char *user, char *password)
45{
46 long password_expires = 0;
47 char *reason;
48
49 /* For versions of AFS prior to 3.3, this routine has few arguments, */
50 /* but since I can't find the old documentation... :-) */
51 setpag();
52 if (ka_UserAuthenticateGeneral
53 (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0, /* instance */
54 (char *)0, /* cell */
55 password, 0, /* lifetime, default */
56 &password_expires, /*days 'til it expires */
57 0, /* spare 2 */
58 &reason) == 0)
59 {
60 return (True);
61 }
62 DEBUG(1,
63 ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
64 return (False);
65}
66#endif
67
68
69#ifdef WITH_DFS
70
71#include <dce/dce_error.h>
72#include <dce/sec_login.h>
73
74/*****************************************************************
75 This new version of the DFS_AUTH code was donated by Karsten Muuss
76 <muuss@or.uni-bonn.de>. It fixes the following problems with the
77 old code :
78
79 - Server credentials may expire
80 - Client credential cache files have wrong owner
81 - purge_context() function is called with invalid argument
82
83 This new code was modified to ensure that on exit the uid/gid is
84 still root, and the original directory is restored. JRA.
85******************************************************************/
86
87sec_login_handle_t my_dce_sec_context;
88int dcelogin_atmost_once = 0;
89
90/*******************************************************************
91check on a DCE/DFS authentication
92********************************************************************/
93static BOOL dfs_auth(char *user, char *password)
94{
95 struct tm *t;
96 error_status_t err;
97 int err2;
98 int prterr;
99 signed32 expire_time, current_time;
100 boolean32 password_reset;
101 struct passwd *pw;
102 sec_passwd_rec_t passwd_rec;
103 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
104 unsigned char dce_errstr[dce_c_error_string_len];
105 gid_t egid;
106
107 if (dcelogin_atmost_once)
108 return (False);
109
110#ifdef HAVE_CRYPT
111 /*
112 * We only go for a DCE login context if the given password
113 * matches that stored in the local password file..
114 * Assumes local passwd file is kept in sync w/ DCE RGY!
115 */
116
117 if (strcmp((char *)crypt(password, this_salt), this_crypted))
118 {
119 return (False);
120 }
121#endif
122
123 sec_login_get_current_context(&my_dce_sec_context, &err);
124 if (err != error_status_ok)
125 {
126 dce_error_inq_text(err, dce_errstr, &err2);
127 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
128
129 return (False);
130 }
131
132 sec_login_certify_identity(my_dce_sec_context, &err);
133 if (err != error_status_ok)
134 {
135 dce_error_inq_text(err, dce_errstr, &err2);
136 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
137
138 return (False);
139 }
140
141 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
142 if (err != error_status_ok)
143 {
144 dce_error_inq_text(err, dce_errstr, &err2);
145 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
146
147 return (False);
148 }
149
150 time(&current_time);
151
152 if (expire_time < (current_time + 60))
153 {
154 struct passwd *pw;
155 sec_passwd_rec_t *key;
156
157 sec_login_get_pwent(my_dce_sec_context,
158 (sec_login_passwd_t *) & pw, &err);
159 if (err != error_status_ok)
160 {
161 dce_error_inq_text(err, dce_errstr, &err2);
162 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
163
164 return (False);
165 }
166
167 sec_login_refresh_identity(my_dce_sec_context, &err);
168 if (err != error_status_ok)
169 {
170 dce_error_inq_text(err, dce_errstr, &err2);
171 DEBUG(0, ("DCE can't refresh identity. %s\n",
172 dce_errstr));
173
174 return (False);
175 }
176
177 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
178 (unsigned char *)pw->pw_name,
179 sec_c_key_version_none,
180 (void **)&key, &err);
181 if (err != error_status_ok)
182 {
183 dce_error_inq_text(err, dce_errstr, &err2);
184 DEBUG(0, ("DCE can't get key for %s. %s\n",
185 pw->pw_name, dce_errstr));
186
187 return (False);
188 }
189
190 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
191 &password_reset, &auth_src,
192 &err);
193 if (err != error_status_ok)
194 {
195 dce_error_inq_text(err, dce_errstr, &err2);
196 DEBUG(0,
197 ("DCE can't validate and certify identity for %s. %s\n",
198 pw->pw_name, dce_errstr));
199 }
200
201 sec_key_mgmt_free_key(key, &err);
202 if (err != error_status_ok)
203 {
204 dce_error_inq_text(err, dce_errstr, &err2);
205 DEBUG(0, ("DCE can't free key.\n", dce_errstr));
206 }
207 }
208
209 if (sec_login_setup_identity((unsigned char *)user,
210 sec_login_no_flags,
211 &my_dce_sec_context, &err) == 0)
212 {
213 dce_error_inq_text(err, dce_errstr, &err2);
214 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
215 user, dce_errstr));
216 return (False);
217 }
218
219 sec_login_get_pwent(my_dce_sec_context,
220 (sec_login_passwd_t *) & pw, &err);
221 if (err != error_status_ok)
222 {
223 dce_error_inq_text(err, dce_errstr, &err2);
224 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
225
226 return (False);
227 }
228
229 sec_login_purge_context(&my_dce_sec_context, &err);
230 if (err != error_status_ok)
231 {
232 dce_error_inq_text(err, dce_errstr, &err2);
233 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
234
235 return (False);
236 }
237
238 /*
239 * NB. I'd like to change these to call something like change_to_user()
240 * instead but currently we don't have a connection
241 * context to become the correct user. This is already
242 * fairly platform specific code however, so I think
243 * this should be ok. I have added code to go
244 * back to being root on error though. JRA.
245 */
246
247 egid = getegid();
248
249 set_effective_gid(pw->pw_gid);
250 set_effective_uid(pw->pw_uid);
251
252 if (sec_login_setup_identity((unsigned char *)user,
253 sec_login_no_flags,
254 &my_dce_sec_context, &err) == 0)
255 {
256 dce_error_inq_text(err, dce_errstr, &err2);
257 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
258 user, dce_errstr));
259 goto err;
260 }
261
262 sec_login_get_pwent(my_dce_sec_context,
263 (sec_login_passwd_t *) & pw, &err);
264 if (err != error_status_ok)
265 {
266 dce_error_inq_text(err, dce_errstr, &err2);
267 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
268 goto err;
269 }
270
271 passwd_rec.version_number = sec_passwd_c_version_none;
272 passwd_rec.pepper = NULL;
273 passwd_rec.key.key_type = sec_passwd_plain;
274 passwd_rec.key.tagged_union.plain = (idl_char *) password;
275
276 sec_login_validate_identity(my_dce_sec_context,
277 &passwd_rec, &password_reset,
278 &auth_src, &err);
279 if (err != error_status_ok)
280 {
281 dce_error_inq_text(err, dce_errstr, &err2);
282 DEBUG(0,
283 ("DCE Identity Validation failed for principal %s: %s\n",
284 user, dce_errstr));
285 goto err;
286 }
287
288 sec_login_certify_identity(my_dce_sec_context, &err);
289 if (err != error_status_ok)
290 {
291 dce_error_inq_text(err, dce_errstr, &err2);
292 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
293 goto err;
294 }
295
296 if (auth_src != sec_login_auth_src_network)
297 {
298 DEBUG(0, ("DCE context has no network credentials.\n"));
299 }
300
301 sec_login_set_context(my_dce_sec_context, &err);
302 if (err != error_status_ok)
303 {
304 dce_error_inq_text(err, dce_errstr, &err2);
305 DEBUG(0,
306 ("DCE login failed for principal %s, cant set context: %s\n",
307 user, dce_errstr));
308
309 sec_login_purge_context(&my_dce_sec_context, &err);
310 goto err;
311 }
312
313 sec_login_get_pwent(my_dce_sec_context,
314 (sec_login_passwd_t *) & pw, &err);
315 if (err != error_status_ok)
316 {
317 dce_error_inq_text(err, dce_errstr, &err2);
318 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
319 goto err;
320 }
321
322 DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
323 user, sys_getpid()));
324
325 DEBUG(3, ("DCE principal: %s\n"
326 " uid: %d\n"
327 " gid: %d\n",
328 pw->pw_name, pw->pw_uid, pw->pw_gid));
329 DEBUG(3, (" info: %s\n"
330 " dir: %s\n"
331 " shell: %s\n",
332 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
333
334 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
335 if (err != error_status_ok)
336 {
337 dce_error_inq_text(err, dce_errstr, &err2);
338 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
339 goto err;
340 }
341
342 set_effective_uid(0);
343 set_effective_gid(0);
344
345 t = localtime(&expire_time);
346 if (t) {
347 const char *asct = asctime(t);
348 if (asct) {
349 DEBUG(0,("DCE context expires: %s", asct));
350 }
351 }
352
353 dcelogin_atmost_once = 1;
354 return (True);
355
356 err:
357
358 /* Go back to root, JRA. */
359 set_effective_uid(0);
360 set_effective_gid(egid);
361 return (False);
362}
363
364void dfs_unlogin(void)
365{
366 error_status_t err;
367 int err2;
368 unsigned char dce_errstr[dce_c_error_string_len];
369
370 sec_login_purge_context(&my_dce_sec_context, &err);
371 if (err != error_status_ok)
372 {
373 dce_error_inq_text(err, dce_errstr, &err2);
374 DEBUG(0,
375 ("DCE purge login context failed for server instance %d: %s\n",
376 sys_getpid(), dce_errstr));
377 }
378}
379#endif
380
381#ifdef LINUX_BIGCRYPT
382/****************************************************************************
383an enhanced crypt for Linux to handle password longer than 8 characters
384****************************************************************************/
385static int linux_bigcrypt(char *password, char *salt1, char *crypted)
386{
387#define LINUX_PASSWORD_SEG_CHARS 8
388 char salt[3];
389 int i;
390
391 StrnCpy(salt, salt1, 2);
392 crypted += 2;
393
394 for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
395 char *p = crypt(password, salt) + 2;
396 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
397 return (0);
398 password += LINUX_PASSWORD_SEG_CHARS;
399 crypted += strlen(p);
400 }
401
402 return (1);
403}
404#endif
405
406#ifdef OSF1_ENH_SEC
407/****************************************************************************
408an enhanced crypt for OSF1
409****************************************************************************/
410static char *osf1_bigcrypt(char *password, char *salt1)
411{
412 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
413 char *p1;
414 char *p2 = password;
415 char salt[3];
416 int i;
417 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
418 if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
419 parts++;
420
421 StrnCpy(salt, salt1, 2);
422 StrnCpy(result, salt1, 2);
423 result[2] = '\0';
424
425 for (i = 0; i < parts; i++) {
426 p1 = crypt(p2, salt);
427 strncat(result, p1 + 2,
428 AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
429 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
430 p2 += AUTH_CLEARTEXT_SEG_CHARS;
431 }
432
433 return (result);
434}
435#endif
436
437
438/****************************************************************************
439apply a function to upper/lower case combinations
440of a string and return true if one of them returns true.
441try all combinations with N uppercase letters.
442offset is the first char to try and change (start with 0)
443it assumes the string starts lowercased
444****************************************************************************/
445static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (const char *),
446 int N)
447{
448 int len = strlen(s);
449 int i;
450 NTSTATUS nt_status;
451
452#ifdef PASSWORD_LENGTH
453 len = MIN(len, PASSWORD_LENGTH);
454#endif
455
456 if (N <= 0 || offset >= len)
457 return (fn(s));
458
459 for (i = offset; i < (len - (N - 1)); i++) {
460 char c = s[i];
461 if (!islower_ascii(c))
462 continue;
463 s[i] = toupper_ascii(c);
464 if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
465 return (nt_status);
466 }
467 s[i] = c;
468 }
469 return (NT_STATUS_WRONG_PASSWORD);
470}
471
472/****************************************************************************
473apply a function to upper/lower case combinations
474of a string and return true if one of them returns true.
475try all combinations with up to N uppercase letters.
476offset is the first char to try and change (start with 0)
477it assumes the string starts lowercased
478****************************************************************************/
479static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (const char *), int N)
480{
481 int n;
482 NTSTATUS nt_status;
483 for (n = 1; n <= N; n++)
484 if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
485 return nt_status;
486 return NT_STATUS_WRONG_PASSWORD;
487}
488
489
490/****************************************************************************
491core of password checking routine
492****************************************************************************/
493static NTSTATUS password_check(const char *password)
494{
495#ifdef WITH_PAM
496 return smb_pam_passcheck(this_user, password);
497#else
498
499 BOOL ret;
500
501#ifdef WITH_AFS
502 if (afs_auth(this_user, password))
503 return NT_STATUS_OK;
504#endif /* WITH_AFS */
505
506#ifdef WITH_DFS
507 if (dfs_auth(this_user, password))
508 return NT_STATUS_OK;
509#endif /* WITH_DFS */
510
511#ifdef OSF1_ENH_SEC
512
513 ret = (strcmp(osf1_bigcrypt(password, this_salt),
514 this_crypted) == 0);
515 if (!ret) {
516 DEBUG(2,
517 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
518 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
519 }
520 if (ret) {
521 return NT_STATUS_OK;
522 } else {
523 return NT_STATUS_WRONG_PASSWORD;
524 }
525
526#endif /* OSF1_ENH_SEC */
527
528#ifdef ULTRIX_AUTH
529 ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
530 if (ret) {
531 return NT_STATUS_OK;
532 } else {
533 return NT_STATUS_WRONG_PASSWORD;
534 }
535
536#endif /* ULTRIX_AUTH */
537
538#ifdef LINUX_BIGCRYPT
539 ret = (linux_bigcrypt(password, this_salt, this_crypted));
540 if (ret) {
541 return NT_STATUS_OK;
542 } else {
543 return NT_STATUS_WRONG_PASSWORD;
544 }
545#endif /* LINUX_BIGCRYPT */
546
547#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
548
549 /*
550 * Some systems have bigcrypt in the C library but might not
551 * actually use it for the password hashes (HPUX 10.20) is
552 * a noteable example. So we try bigcrypt first, followed
553 * by crypt.
554 */
555
556 if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
557 return NT_STATUS_OK;
558 else
559 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
560 if (ret) {
561 return NT_STATUS_OK;
562 } else {
563 return NT_STATUS_WRONG_PASSWORD;
564 }
565#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
566
567#ifdef HAVE_BIGCRYPT
568 ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
569 if (ret) {
570 return NT_STATUS_OK;
571 } else {
572 return NT_STATUS_WRONG_PASSWORD;
573 }
574#endif /* HAVE_BIGCRYPT */
575
576#ifndef HAVE_CRYPT
577 DEBUG(1, ("Warning - no crypt available\n"));
578 return NT_STATUS_LOGON_FAILURE;
579#else /* HAVE_CRYPT */
580 ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
581 if (ret) {
582 return NT_STATUS_OK;
583 } else {
584 return NT_STATUS_WRONG_PASSWORD;
585 }
586#endif /* HAVE_CRYPT */
587#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
588#endif /* WITH_PAM */
589}
590
591
592
593/****************************************************************************
594CHECK if a username/password is OK
595the function pointer fn() points to a function to call when a successful
596match is found and is used to update the encrypted password file
597return NT_STATUS_OK on correct match, appropriate error otherwise
598****************************************************************************/
599
600NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password,
601 int pwlen, BOOL (*fn) (const char *, const char *), BOOL run_cracker)
602{
603 pstring pass2;
604 int level = lp_passwordlevel();
605
606 NTSTATUS nt_status;
607
608#ifdef DEBUG_PASSWORD
609 DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
610#endif
611
612 if (!password)
613 return NT_STATUS_LOGON_FAILURE;
614
615 if (((!*password) || (!pwlen)) && !lp_null_passwords())
616 return NT_STATUS_LOGON_FAILURE;
617
618#if defined(WITH_PAM)
619
620 /*
621 * If we're using PAM we want to short-circuit all the
622 * checks below and dive straight into the PAM code.
623 */
624
625 fstrcpy(this_user, user);
626
627 DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
628
629#else /* Not using PAM */
630
631 DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
632
633 if (!pass) {
634 DEBUG(3, ("Couldn't find user %s\n", user));
635 return NT_STATUS_NO_SUCH_USER;
636 }
637
638
639 /* Copy into global for the convenience of looping code */
640 /* Also the place to keep the 'password' no matter what
641 crazy struct it started in... */
642 fstrcpy(this_crypted, pass->pw_passwd);
643 fstrcpy(this_salt, pass->pw_passwd);
644
645#ifdef HAVE_GETSPNAM
646 {
647 struct spwd *spass;
648
649 /* many shadow systems require you to be root to get
650 the password, in most cases this should already be
651 the case when this function is called, except
652 perhaps for IPC password changing requests */
653
654 spass = getspnam(pass->pw_name);
655 if (spass && spass->sp_pwdp) {
656 fstrcpy(this_crypted, spass->sp_pwdp);
657 fstrcpy(this_salt, spass->sp_pwdp);
658 }
659 }
660#elif defined(IA_UINFO)
661 {
662 /* Need to get password with SVR4.2's ia_ functions
663 instead of get{sp,pw}ent functions. Required by
664 UnixWare 2.x, tested on version
665 2.1. (tangent@cyberport.com) */
666 uinfo_t uinfo;
667 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
668 ia_get_logpwd(uinfo, &(pass->pw_passwd));
669 }
670#endif
671
672#ifdef HAVE_GETPRPWNAM
673 {
674 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
675 if (pr_pw && pr_pw->ufld.fd_encrypt)
676 fstrcpy(this_crypted, pr_pw->ufld.fd_encrypt);
677 }
678#endif
679
680#ifdef HAVE_GETPWANAM
681 {
682 struct passwd_adjunct *pwret;
683 pwret = getpwanam(s);
684 if (pwret && pwret->pwa_passwd)
685 fstrcpy(this_crypted, pwret->pwa_passwd);
686 }
687#endif
688
689#ifdef OSF1_ENH_SEC
690 {
691 struct pr_passwd *mypasswd;
692 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
693 user));
694 mypasswd = getprpwnam(user);
695 if (mypasswd) {
696 fstrcpy(this_user, mypasswd->ufld.fd_name);
697 fstrcpy(this_crypted, mypasswd->ufld.fd_encrypt);
698 } else {
699 DEBUG(5,
700 ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
701 user));
702 }
703 }
704#endif
705
706#ifdef ULTRIX_AUTH
707 {
708 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
709 if (ap) {
710 fstrcpy(this_crypted, ap->a_password);
711 endauthent();
712 }
713 }
714#endif
715
716#if defined(HAVE_TRUNCATED_SALT)
717 /* crypt on some platforms (HPUX in particular)
718 won't work with more than 2 salt characters. */
719 this_salt[2] = 0;
720#endif
721
722 if (!*this_crypted) {
723 if (!lp_null_passwords()) {
724 DEBUG(2, ("Disallowing %s with null password\n",
725 this_user));
726 return NT_STATUS_LOGON_FAILURE;
727 }
728 if (!*password) {
729 DEBUG(3,
730 ("Allowing access to %s with null password\n",
731 this_user));
732 return NT_STATUS_OK;
733 }
734 }
735
736#endif /* defined(WITH_PAM) */
737
738 /* try it as it came to us */
739 nt_status = password_check(password);
740 if NT_STATUS_IS_OK(nt_status) {
741 if (fn) {
742 fn(user, password);
743 }
744 return (nt_status);
745 } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
746 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
747 return (nt_status);
748 }
749
750 if (!run_cracker) {
751 return (nt_status);
752 }
753
754 /* if the password was given to us with mixed case then we don't
755 * need to proceed as we know it hasn't been case modified by the
756 * client */
757 if (strhasupper(password) && strhaslower(password)) {
758 return nt_status;
759 }
760
761 /* make a copy of it */
762 pstrcpy(pass2, password);
763
764 /* try all lowercase if it's currently all uppercase */
765 if (strhasupper(pass2)) {
766 strlower_m(pass2);
767 if NT_STATUS_IS_OK(nt_status = password_check(pass2)) {
768 if (fn)
769 fn(user, pass2);
770 return (nt_status);
771 }
772 }
773
774 /* give up? */
775 if (level < 1) {
776 return NT_STATUS_WRONG_PASSWORD;
777 }
778
779 /* last chance - all combinations of up to level chars upper! */
780 strlower_m(pass2);
781
782 if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) {
783 if (fn)
784 fn(user, pass2);
785 return nt_status;
786 }
787
788 return NT_STATUS_WRONG_PASSWORD;
789}
Note: See TracBrowser for help on using the repository browser.