1/*
2   Unix SMB/CIFS implementation.
3   Password checking
4   Copyright (C) Andrew Tridgell 1992-1998
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/* this module is for checking a username/password against a system
21   password database. The SMB encrypted password support is elsewhere */
22
23#include "includes.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_AUTH
27
28/* these are kept here to keep the string_combinations function simple */
29static char *ths_user;
30
31static const char *get_this_user(void)
32{
33	if (!ths_user) {
34		return "";
35	}
36	return ths_user;
37}
38
39#if defined(WITH_PAM) || defined(OSF1_ENH_SEC)
40static const char *set_this_user(const char *newuser)
41{
42	char *orig_user = ths_user;
43	ths_user = SMB_STRDUP(newuser);
44	SAFE_FREE(orig_user);
45	return ths_user;
46}
47#endif
48
49#if !defined(WITH_PAM)
50static char *ths_salt;
51/* This must be writable. */
52static char *get_this_salt(void)
53{
54	return ths_salt;
55}
56
57/* We may be setting a modified version of the same
58 * string, so don't free before use. */
59
60static const char *set_this_salt(const char *newsalt)
61{
62	char *orig_salt = ths_salt;
63	ths_salt = SMB_STRDUP(newsalt);
64	SAFE_FREE(orig_salt);
65	return ths_salt;
66}
67
68static char *ths_crypted;
69static const char *get_this_crypted(void)
70{
71	if (!ths_crypted) {
72		return "";
73	}
74	return ths_crypted;
75}
76
77static const char *set_this_crypted(const char *newcrypted)
78{
79	char *orig_crypted = ths_crypted;
80	ths_crypted = SMB_STRDUP(newcrypted);
81	SAFE_FREE(orig_crypted);
82	return ths_crypted;
83}
84#endif
85
86#ifdef WITH_AFS
87
88#include <afs/stds.h>
89#include <afs/kautils.h>
90
91/*******************************************************************
92check on AFS authentication
93********************************************************************/
94static bool afs_auth(char *user, char *password)
95{
96	long password_expires = 0;
97	char *reason;
98
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)
109	{
110		return (True);
111	}
112	DEBUG(1,
113	      ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
114	return (False);
115}
116#endif
117
118
119#ifdef WITH_DFS
120
121#include <dce/dce_error.h>
122#include <dce/sec_login.h>
123
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 :
128
129  - Server credentials may expire
130  - Client credential cache files have wrong owner
131  - purge_context() function is called with invalid argument
132
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******************************************************************/
136
137sec_login_handle_t my_dce_sec_context;
138int dcelogin_atmost_once = 0;
139
140/*******************************************************************
141check on a DCE/DFS authentication
142********************************************************************/
143static bool dfs_auth(char *user, char *password)
144{
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;
156
157	if (dcelogin_atmost_once)
158		return (False);
159
160#ifdef HAVE_CRYPT
161	/*
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!
165	 */
166
167	if (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()))
168	{
169		return (False);
170	}
171#endif
172
173	sec_login_get_current_context(&my_dce_sec_context, &err);
174	if (err != error_status_ok)
175	{
176		dce_error_inq_text(err, dce_errstr, &err2);
177		DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
178
179		return (False);
180	}
181
182	sec_login_certify_identity(my_dce_sec_context, &err);
183	if (err != error_status_ok)
184	{
185		dce_error_inq_text(err, dce_errstr, &err2);
186		DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
187
188		return (False);
189	}
190
191	sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
192	if (err != error_status_ok)
193	{
194		dce_error_inq_text(err, dce_errstr, &err2);
195		DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
196
197		return (False);
198	}
199
200	time(&current_time);
201
202	if (expire_time < (current_time + 60))
203	{
204		struct passwd *pw;
205		sec_passwd_rec_t *key;
206
207		sec_login_get_pwent(my_dce_sec_context,
208				    (sec_login_passwd_t *) & pw, &err);
209		if (err != error_status_ok)
210		{
211			dce_error_inq_text(err, dce_errstr, &err2);
212			DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
213
214			return (False);
215		}
216
217		sec_login_refresh_identity(my_dce_sec_context, &err);
218		if (err != error_status_ok)
219		{
220			dce_error_inq_text(err, dce_errstr, &err2);
221			DEBUG(0, ("DCE can't refresh identity. %s\n",
222				  dce_errstr));
223
224			return (False);
225		}
226
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)
232		{
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));
236
237			return (False);
238		}
239
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)
244		{
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));
249		}
250
251		sec_key_mgmt_free_key(key, &err);
252		if (err != error_status_ok)
253		{
254			dce_error_inq_text(err, dce_errstr, &err2);
255			DEBUG(0, ("DCE can't free key.\n", dce_errstr));
256		}
257	}
258
259	if (sec_login_setup_identity((unsigned char *)user,
260				     sec_login_no_flags,
261				     &my_dce_sec_context, &err) == 0)
262	{
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);
267	}
268
269	sec_login_get_pwent(my_dce_sec_context,
270			    (sec_login_passwd_t *) & pw, &err);
271	if (err != error_status_ok)
272	{
273		dce_error_inq_text(err, dce_errstr, &err2);
274		DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
275
276		return (False);
277	}
278
279	sec_login_purge_context(&my_dce_sec_context, &err);
280	if (err != error_status_ok)
281	{
282		dce_error_inq_text(err, dce_errstr, &err2);
283		DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
284
285		return (False);
286	}
287
288	/*
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.
295	 */
296
297	egid = getegid();
298
299	set_effective_gid(pw->pw_gid);
300	set_effective_uid(pw->pw_uid);
301
302	if (sec_login_setup_identity((unsigned char *)user,
303				     sec_login_no_flags,
304				     &my_dce_sec_context, &err) == 0)
305	{
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;
310	}
311
312	sec_login_get_pwent(my_dce_sec_context,
313			    (sec_login_passwd_t *) & pw, &err);
314	if (err != error_status_ok)
315	{
316		dce_error_inq_text(err, dce_errstr, &err2);
317		DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
318		goto err;
319	}
320
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;
325
326	sec_login_validate_identity(my_dce_sec_context,
327				    &passwd_rec, &password_reset,
328				    &auth_src, &err);
329	if (err != error_status_ok)
330	{
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;
336	}
337
338	sec_login_certify_identity(my_dce_sec_context, &err);
339	if (err != error_status_ok)
340	{
341		dce_error_inq_text(err, dce_errstr, &err2);
342		DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
343		goto err;
344	}
345
346	if (auth_src != sec_login_auth_src_network)
347	{
348		DEBUG(0, ("DCE context has no network credentials.\n"));
349	}
350
351	sec_login_set_context(my_dce_sec_context, &err);
352	if (err != error_status_ok)
353	{
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));
358
359		sec_login_purge_context(&my_dce_sec_context, &err);
360		goto err;
361	}
362
363	sec_login_get_pwent(my_dce_sec_context,
364			    (sec_login_passwd_t *) & pw, &err);
365	if (err != error_status_ok)
366	{
367		dce_error_inq_text(err, dce_errstr, &err2);
368		DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
369		goto err;
370	}
371
372	DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
373		  user, sys_getpid()));
374
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));
383
384	sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
385	if (err != error_status_ok)
386	{
387		dce_error_inq_text(err, dce_errstr, &err2);
388		DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
389		goto err;
390	}
391
392	set_effective_uid(0);
393	set_effective_gid(0);
394
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));
400		}
401	}
402
403	dcelogin_atmost_once = 1;
404	return (True);
405
406      err:
407
408	/* Go back to root, JRA. */
409	set_effective_uid(0);
410	set_effective_gid(egid);
411	return (False);
412}
413
414void dfs_unlogin(void)
415{
416	error_status_t err;
417	int err2;
418	unsigned char dce_errstr[dce_c_error_string_len];
419
420	sec_login_purge_context(&my_dce_sec_context, &err);
421	if (err != error_status_ok)
422	{
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));
427	}
428}
429#endif
430
431#ifdef LINUX_BIGCRYPT
432/****************************************************************************
433an enhanced crypt for Linux to handle password longer than 8 characters
434****************************************************************************/
435static int linux_bigcrypt(char *password, char *salt1, char *crypted)
436{
437#define LINUX_PASSWORD_SEG_CHARS 8
438	char salt[3];
439	int i;
440
441	StrnCpy(salt, salt1, 2);
442	crypted += 2;
443
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);
450	}
451
452	return (1);
453}
454#endif
455
456#ifdef OSF1_ENH_SEC
457/****************************************************************************
458an enhanced crypt for OSF1
459****************************************************************************/
460static char *osf1_bigcrypt(char *password, char *salt1)
461{
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++;
470
471	StrnCpy(salt, salt1, 2);
472	StrnCpy(result, salt1, 2);
473	result[2] = '\0';
474
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;
481	}
482
483	return (result);
484}
485#endif
486
487
488/****************************************************************************
489apply a function to upper/lower case combinations
490of a string and return true if one of them returns true.
491try all combinations with N uppercase letters.
492offset is the first char to try and change (start with 0)
493it assumes the string starts lowercased
494****************************************************************************/
495static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (const char *),
496				 int N)
497{
498	int len = strlen(s);
499	int i;
500	NTSTATUS nt_status;
501
502#ifdef PASSWORD_LENGTH
503	len = MIN(len, PASSWORD_LENGTH);
504#endif
505
506	if (N <= 0 || offset >= len)
507		return (fn(s));
508
509	for (i = offset; i < (len - (N - 1)); i++) {
510		char c = s[i];
511		if (!islower_ascii(c))
512			continue;
513		s[i] = toupper_ascii(c);
514		if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
515			return (nt_status);
516		}
517		s[i] = c;
518	}
519	return (NT_STATUS_WRONG_PASSWORD);
520}
521
522/****************************************************************************
523apply a function to upper/lower case combinations
524of a string and return true if one of them returns true.
525try all combinations with up to N uppercase letters.
526offset is the first char to try and change (start with 0)
527it assumes the string starts lowercased
528****************************************************************************/
529static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (const char *), int N)
530{
531	int n;
532	NTSTATUS nt_status;
533	for (n = 1; n <= N; n++)
534		if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
535			return nt_status;
536	return NT_STATUS_WRONG_PASSWORD;
537}
538
539
540/****************************************************************************
541core of password checking routine
542****************************************************************************/
543static NTSTATUS password_check(const char *password)
544{
545#ifdef WITH_PAM
546	return smb_pam_passcheck(get_this_user(), password);
547#else
548
549	bool ret;
550
551#ifdef WITH_AFS
552	if (afs_auth(get_this_user(), password))
553		return NT_STATUS_OK;
554#endif /* WITH_AFS */
555
556#ifdef WITH_DFS
557	if (dfs_auth(get_this_user(), password))
558		return NT_STATUS_OK;
559#endif /* WITH_DFS */
560
561#ifdef OSF1_ENH_SEC
562
563	ret = (strcmp(osf1_bigcrypt(password, get_this_salt()),
564		      get_this_crypted()) == 0);
565	if (!ret) {
566		DEBUG(2,
567		      ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
568		ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
569	}
570	if (ret) {
571		return NT_STATUS_OK;
572	} else {
573		return NT_STATUS_WRONG_PASSWORD;
574	}
575
576#endif /* OSF1_ENH_SEC */
577
578#ifdef ULTRIX_AUTH
579	ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
580	if (ret) {
581		return NT_STATUS_OK;
582        } else {
583		return NT_STATUS_WRONG_PASSWORD;
584	}
585
586#endif /* ULTRIX_AUTH */
587
588#ifdef LINUX_BIGCRYPT
589	ret = (linux_bigcrypt(password, get_this_salt(), get_this_crypted()));
590        if (ret) {
591		return NT_STATUS_OK;
592	} else {
593		return NT_STATUS_WRONG_PASSWORD;
594	}
595#endif /* LINUX_BIGCRYPT */
596
597#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
598
599	/*
600	 * Some systems have bigcrypt in the C library but might not
601	 * actually use it for the password hashes (HPUX 10.20) is
602	 * a noteable example. So we try bigcrypt first, followed
603	 * by crypt.
604	 */
605
606	if (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0)
607		return NT_STATUS_OK;
608	else
609		ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
610	if (ret) {
611		return NT_STATUS_OK;
612	} else {
613		return NT_STATUS_WRONG_PASSWORD;
614	}
615#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
616
617#ifdef HAVE_BIGCRYPT
618	ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
619        if (ret) {
620		return NT_STATUS_OK;
621	} else {
622		return NT_STATUS_WRONG_PASSWORD;
623	}
624#endif /* HAVE_BIGCRYPT */
625
626#ifndef HAVE_CRYPT
627	DEBUG(1, ("Warning - no crypt available\n"));
628	return NT_STATUS_LOGON_FAILURE;
629#else /* HAVE_CRYPT */
630	ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
631        if (ret) {
632		return NT_STATUS_OK;
633	} else {
634		return NT_STATUS_WRONG_PASSWORD;
635	}
636#endif /* HAVE_CRYPT */
637#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
638#endif /* WITH_PAM */
639}
640
641
642
643/****************************************************************************
644CHECK if a username/password is OK
645the function pointer fn() points to a function to call when a successful
646match is found and is used to update the encrypted password file
647return NT_STATUS_OK on correct match, appropriate error otherwise
648****************************************************************************/
649
650NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password,
651		    int pwlen, bool (*fn) (const char *, const char *), bool run_cracker)
652{
653	char *pass2 = NULL;
654	int level = lp_passwordlevel();
655
656	NTSTATUS nt_status;
657
658#ifdef DEBUG_PASSWORD
659	DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
660#endif
661
662	if (!password)
663		return NT_STATUS_LOGON_FAILURE;
664
665	if (((!*password) || (!pwlen)) && !lp_null_passwords())
666		return NT_STATUS_LOGON_FAILURE;
667
668#if defined(WITH_PAM)
669
670	/*
671	 * If we're using PAM we want to short-circuit all the
672	 * checks below and dive straight into the PAM code.
673	 */
674
675	if (set_this_user(user) == NULL) {
676		return NT_STATUS_NO_MEMORY;
677	}
678
679	DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
680
681#else /* Not using PAM */
682
683	DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
684
685	if (!pass) {
686		DEBUG(3, ("Couldn't find user %s\n", user));
687		return NT_STATUS_NO_SUCH_USER;
688	}
689
690
691	/* Copy into global for the convenience of looping code */
692	/* Also the place to keep the 'password' no matter what
693	   crazy struct it started in... */
694	if (set_this_crypted(pass->pw_passwd) == NULL) {
695		return NT_STATUS_NO_MEMORY;
696	}
697	if (set_this_salt(pass->pw_passwd) == NULL) {
698		return NT_STATUS_NO_MEMORY;
699	}
700
701#ifdef HAVE_GETSPNAM
702	{
703		struct spwd *spass;
704
705		/* many shadow systems require you to be root to get
706		   the password, in most cases this should already be
707		   the case when this function is called, except
708		   perhaps for IPC password changing requests */
709
710		spass = getspnam(pass->pw_name);
711		if (spass && spass->sp_pwdp) {
712			if (set_this_crypted(spass->sp_pwdp) == NULL) {
713				return NT_STATUS_NO_MEMORY;
714			}
715			if (set_this_salt(spass->sp_pwdp) == NULL) {
716				return NT_STATUS_NO_MEMORY;
717			}
718		}
719	}
720#elif defined(IA_UINFO)
721	{
722		/* Need to get password with SVR4.2's ia_ functions
723		   instead of get{sp,pw}ent functions. Required by
724		   UnixWare 2.x, tested on version
725		   2.1. (tangent@cyberport.com) */
726		uinfo_t uinfo;
727		if (ia_openinfo(pass->pw_name, &uinfo) != -1)
728			ia_get_logpwd(uinfo, &(pass->pw_passwd));
729	}
730#endif
731
732#ifdef HAVE_GETPRPWNAM
733	{
734		struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
735		if (pr_pw && pr_pw->ufld.fd_encrypt) {
736			if (set_this_crypted(pr_pw->ufld.fd_encrypt) == NULL) {
737				return NT_STATUS_NO_MEMORY;
738			}
739		}
740	}
741#endif
742
743#ifdef HAVE_GETPWANAM
744	{
745		struct passwd_adjunct *pwret;
746		pwret = getpwanam(s);
747		if (pwret && pwret->pwa_passwd) {
748			if (set_this_crypted(pwret->pwa_passwd) == NULL) {
749				return NT_STATUS_NO_MEMORY;
750			}
751		}
752	}
753#endif
754
755#ifdef OSF1_ENH_SEC
756	{
757		struct pr_passwd *mypasswd;
758		DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
759			  user));
760		mypasswd = getprpwnam(user);
761		if (mypasswd) {
762			if (set_this_user(mypasswd->ufld.fd_name) == NULL) {
763				return NT_STATUS_NO_MEMORY;
764			}
765			if (set_this_crypted(mypasswd->ufld.fd_encrypt) == NULL) {
766				return NT_STATUS_NO_MEMORY;
767			}
768		} else {
769			DEBUG(5,
770			      ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
771			       user));
772		}
773	}
774#endif
775
776#ifdef ULTRIX_AUTH
777	{
778		AUTHORIZATION *ap = getauthuid(pass->pw_uid);
779		if (ap) {
780			if (set_this_crypted(ap->a_password) == NULL) {
781				endauthent();
782				return NT_STATUS_NO_MEMORY;
783			}
784			endauthent();
785		}
786	}
787#endif
788
789#if defined(HAVE_TRUNCATED_SALT)
790	/* crypt on some platforms (HPUX in particular)
791	   won't work with more than 2 salt characters. */
792	{
793		char *trunc_salt = get_this_salt();
794		if (!trunc_salt || strlen(trunc_salt) < 2) {
795			return NT_STATUS_LOGON_FAILURE;
796		}
797		trunc_salt[2] = 0;
798		if (set_this_salt(trunc_salt) == NULL) {
799			return NT_STATUS_NO_MEMORY;
800		}
801	}
802#endif
803
804	if (!get_this_crypted() || !*get_this_crypted()) {
805		if (!lp_null_passwords()) {
806			DEBUG(2, ("Disallowing %s with null password\n",
807				  get_this_user()));
808			return NT_STATUS_LOGON_FAILURE;
809		}
810		if (!*password) {
811			DEBUG(3,
812			      ("Allowing access to %s with null password\n",
813			       get_this_user()));
814			return NT_STATUS_OK;
815		}
816	}
817
818#endif /* defined(WITH_PAM) */
819
820	/* try it as it came to us */
821	nt_status = password_check(password);
822        if NT_STATUS_IS_OK(nt_status) {
823                if (fn) {
824                        fn(user, password);
825		}
826		return (nt_status);
827	} else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
828                /* No point continuing if its not the password thats to blame (ie PAM disabled). */
829                return (nt_status);
830        }
831
832	if (!run_cracker) {
833		return (nt_status);
834	}
835
836	/* if the password was given to us with mixed case then we don't
837	 * need to proceed as we know it hasn't been case modified by the
838	 * client */
839	if (strhasupper(password) && strhaslower(password)) {
840		return nt_status;
841	}
842
843	/* make a copy of it */
844	pass2 = talloc_strdup(talloc_tos(), password);
845	if (!pass2) {
846		return NT_STATUS_NO_MEMORY;
847	}
848
849	/* try all lowercase if it's currently all uppercase */
850	if (strhasupper(pass2)) {
851		strlower_m(pass2);
852		if NT_STATUS_IS_OK(nt_status = password_check(pass2)) {
853		        if (fn)
854				fn(user, pass2);
855			return (nt_status);
856		}
857	}
858
859	/* give up? */
860	if (level < 1) {
861		return NT_STATUS_WRONG_PASSWORD;
862	}
863
864	/* last chance - all combinations of up to level chars upper! */
865	strlower_m(pass2);
866
867        if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) {
868                if (fn)
869			fn(user, pass2);
870		return nt_status;
871	}
872
873	return NT_STATUS_WRONG_PASSWORD;
874}
875