• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/auth/ntlm/
1/*
2   Unix SMB/CIFS implementation.
3   Password and authentication handling
4   Copyright (C) Andrew Bartlett		2001
5   Copyright (C) Jeremy Allison			2001
6   Copyright (C) Simo Sorce			2005
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "auth/auth.h"
24#include "auth/ntlm/auth_proto.h"
25#include "system/passwd.h" /* needed by some systems for struct passwd */
26#include "lib/socket/socket.h"
27#include "auth/ntlm/pam_errors.h"
28#include "param/param.h"
29
30/* TODO: look at how to best fill in parms retrieveing a struct passwd info
31 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
32 */
33static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
34					  const char *netbios_name,
35					  const struct auth_usersupplied_info *user_info,
36					  struct passwd *pwd,
37					  struct auth_serversupplied_info **_server_info)
38{
39	struct auth_serversupplied_info *server_info;
40	NTSTATUS status;
41
42	/* This is a real, real hack */
43	if (pwd->pw_uid == 0) {
44		status = auth_system_server_info(mem_ctx, netbios_name, &server_info);
45		if (!NT_STATUS_IS_OK(status)) {
46			return status;
47		}
48
49		server_info->account_name = talloc_steal(server_info, pwd->pw_name);
50		NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
51
52		server_info->domain_name = talloc_strdup(server_info, "unix");
53		NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
54	} else {
55		server_info = talloc(mem_ctx, struct auth_serversupplied_info);
56		NT_STATUS_HAVE_NO_MEMORY(server_info);
57
58		server_info->authenticated = true;
59
60		server_info->account_name = talloc_steal(server_info, pwd->pw_name);
61		NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
62
63		server_info->domain_name = talloc_strdup(server_info, "unix");
64		NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
65
66		/* This isn't in any way correct.. */
67		server_info->account_sid = NULL;
68		server_info->primary_group_sid = NULL;
69		server_info->n_domain_groups = 0;
70		server_info->domain_groups = NULL;
71	}
72	server_info->user_session_key = data_blob(NULL,0);
73	server_info->lm_session_key = data_blob(NULL,0);
74
75	server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
76	NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
77	server_info->logon_script = talloc_strdup(server_info, "");
78	NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
79	server_info->profile_path = talloc_strdup(server_info, "");
80	NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
81	server_info->home_directory = talloc_strdup(server_info, "");
82	NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
83	server_info->home_drive = talloc_strdup(server_info, "");
84	NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
85
86	server_info->last_logon = 0;
87	server_info->last_logoff = 0;
88	server_info->acct_expiry = 0;
89	server_info->last_password_change = 0;
90	server_info->allow_password_change = 0;
91	server_info->force_password_change = 0;
92	server_info->logon_count = 0;
93	server_info->bad_password_count = 0;
94	server_info->acct_flags = 0;
95
96	*_server_info = server_info;
97
98	return NT_STATUS_OK;
99}
100
101static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
102{
103        struct passwd *ret;
104	struct passwd *from;
105
106	*pws = NULL;
107
108	ret = talloc(ctx, struct passwd);
109	NT_STATUS_HAVE_NO_MEMORY(ret);
110
111	from = getpwnam(username);
112	if (!from) {
113		return NT_STATUS_NO_SUCH_USER;
114	}
115
116        ret->pw_name = talloc_strdup(ctx, from->pw_name);
117	NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
118
119        ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
120	NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
121
122        ret->pw_uid = from->pw_uid;
123        ret->pw_gid = from->pw_gid;
124        ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
125	NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
126
127        ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
128	NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
129
130        ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
131	NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
132
133	*pws = ret;
134
135	return NT_STATUS_OK;
136}
137
138
139#ifdef HAVE_SECURITY_PAM_APPL_H
140#include <security/pam_appl.h>
141
142struct smb_pam_user_info {
143	const char *account_name;
144	const char *plaintext_password;
145};
146
147#define COPY_STRING(s) (s) ? strdup(s) : NULL
148
149/*
150 * Check user password
151 * Currently it uses PAM only and fails on systems without PAM
152 * Samba3 code located in pass_check.c is to ugly to be used directly it will
153 * need major rework that's why pass_check.c is still there.
154*/
155
156static int smb_pam_conv(int num_msg, const struct pam_message **msg,
157			 struct pam_response **reply, void *appdata_ptr)
158{
159	struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
160	int num;
161
162	if (num_msg <= 0) {
163		*reply = NULL;
164		return PAM_CONV_ERR;
165	}
166
167	/*
168	 * Apparantly HPUX has a buggy PAM that doesn't support the
169	 * data pointer. Fail if this is the case. JRA.
170	 */
171
172	if (info == NULL) {
173		*reply = NULL;
174		return PAM_CONV_ERR;
175	}
176
177	/*
178	 * PAM frees memory in reply messages by itself
179	 * so use malloc instead of talloc here.
180	 */
181	*reply = malloc_array_p(struct pam_response, num_msg);
182	if (*reply == NULL) {
183		return PAM_CONV_ERR;
184	}
185
186	for (num = 0; num < num_msg; num++) {
187		switch  (msg[num]->msg_style) {
188			case PAM_PROMPT_ECHO_ON:
189				(*reply)[num].resp_retcode = PAM_SUCCESS;
190				(*reply)[num].resp = COPY_STRING(info->account_name);
191				break;
192
193			case PAM_PROMPT_ECHO_OFF:
194				(*reply)[num].resp_retcode = PAM_SUCCESS;
195				(*reply)[num].resp = COPY_STRING(info->plaintext_password);
196				break;
197
198			case PAM_TEXT_INFO:
199				(*reply)[num].resp_retcode = PAM_SUCCESS;
200				(*reply)[num].resp = NULL;
201				DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
202				break;
203
204			case PAM_ERROR_MSG:
205				(*reply)[num].resp_retcode = PAM_SUCCESS;
206				(*reply)[num].resp = NULL;
207				DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
208				break;
209
210			default:
211				while (num > 0) {
212					SAFE_FREE((*reply)[num-1].resp);
213					num--;
214				}
215				SAFE_FREE(*reply);
216				*reply = NULL;
217				DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
218				return PAM_CONV_ERR;
219		}
220	}
221
222	return PAM_SUCCESS;
223}
224
225/*
226 * Start PAM authentication for specified account
227 */
228
229static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
230{
231	int pam_error;
232
233	if (account_name == NULL || remote_host == NULL) {
234		return NT_STATUS_INVALID_PARAMETER;
235	}
236
237	DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
238
239	pam_error = pam_start("samba", account_name, pconv, pamh);
240	if (pam_error != PAM_SUCCESS) {
241		/* no valid pamh here, can we reliably call pam_strerror ? */
242		DEBUG(4,("smb_pam_start: pam_start failed!\n"));
243		return NT_STATUS_UNSUCCESSFUL;
244	}
245
246#ifdef PAM_RHOST
247	DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
248	pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
249	if (pam_error != PAM_SUCCESS) {
250		NTSTATUS nt_status;
251
252		DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
253			 pam_strerror(*pamh, pam_error)));
254		nt_status = pam_to_nt_status(pam_error);
255
256		pam_error = pam_end(*pamh, 0);
257		if (pam_error != PAM_SUCCESS) {
258			/* no vaild pamh here, can we reliably call pam_strerror ? */
259			DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
260				 pam_error));
261			return pam_to_nt_status(pam_error);
262		}
263		return nt_status;
264	}
265#endif
266#ifdef PAM_TTY
267	DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
268	pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
269	if (pam_error != PAM_SUCCESS) {
270		NTSTATUS nt_status;
271
272		DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
273			 pam_strerror(*pamh, pam_error)));
274		nt_status = pam_to_nt_status(pam_error);
275
276		pam_error = pam_end(*pamh, 0);
277		if (pam_error != PAM_SUCCESS) {
278			/* no vaild pamh here, can we reliably call pam_strerror ? */
279			DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
280				 pam_error));
281			return pam_to_nt_status(pam_error);
282		}
283		return nt_status;
284	}
285#endif
286	DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
287
288	return NT_STATUS_OK;
289}
290
291static NTSTATUS smb_pam_end(pam_handle_t *pamh)
292{
293	int pam_error;
294
295	if (pamh != NULL) {
296		pam_error = pam_end(pamh, 0);
297		if (pam_error != PAM_SUCCESS) {
298			/* no vaild pamh here, can we reliably call pam_strerror ? */
299			DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
300				 pam_error));
301			return pam_to_nt_status(pam_error);
302		}
303		return NT_STATUS_OK;
304	}
305
306	DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
307	return NT_STATUS_UNSUCCESSFUL;
308}
309
310/*
311 * PAM Authentication Handler
312 */
313static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user)
314{
315	int pam_error;
316
317	/*
318	 * To enable debugging set in /etc/pam.d/samba:
319	 *	auth required /lib/security/pam_pwdb.so nullok shadow audit
320	 */
321
322	DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
323
324	pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
325	switch( pam_error ){
326		case PAM_AUTH_ERR:
327			DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
328			break;
329		case PAM_CRED_INSUFFICIENT:
330			DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
331			break;
332		case PAM_AUTHINFO_UNAVAIL:
333			DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
334			break;
335		case PAM_USER_UNKNOWN:
336			DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
337			break;
338		case PAM_MAXTRIES:
339			DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
340			break;
341		case PAM_ABORT:
342			DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
343			break;
344		case PAM_SUCCESS:
345			DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
346			break;
347		default:
348			DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
349			break;
350	}
351
352	return pam_to_nt_status(pam_error);
353}
354
355/*
356 * PAM Account Handler
357 */
358static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
359{
360	int pam_error;
361
362	DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
363
364	pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
365	switch( pam_error ) {
366		case PAM_AUTHTOK_EXPIRED:
367			DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
368			break;
369		case PAM_ACCT_EXPIRED:
370			DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
371			break;
372		case PAM_AUTH_ERR:
373			DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
374			break;
375		case PAM_PERM_DENIED:
376			DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
377			break;
378		case PAM_USER_UNKNOWN:
379			DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
380			break;
381		case PAM_SUCCESS:
382			DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
383			break;
384		default:
385			DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
386			break;
387	}
388
389	return pam_to_nt_status(pam_error);
390}
391
392/*
393 * PAM Credential Setting
394 */
395
396static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
397{
398	int pam_error;
399
400	/*
401	 * This will allow samba to aquire a kerberos token. And, when
402	 * exporting an AFS cell, be able to /write/ to this cell.
403	 */
404
405	DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
406
407	pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
408	switch( pam_error ) {
409		case PAM_CRED_UNAVAIL:
410			DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
411			break;
412		case PAM_CRED_EXPIRED:
413			DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
414			break;
415		case PAM_USER_UNKNOWN:
416			DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
417			break;
418		case PAM_CRED_ERR:
419			DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
420			break;
421		case PAM_SUCCESS:
422			DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
423			break;
424		default:
425			DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
426			break;
427	}
428
429	return pam_to_nt_status(pam_error);
430}
431
432static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
433				    const struct auth_usersupplied_info *user_info, struct passwd **pws)
434{
435	struct smb_pam_user_info *info;
436	struct pam_conv *pamconv;
437	pam_handle_t *pamh;
438	NTSTATUS nt_status;
439
440	info = talloc(ctx, struct smb_pam_user_info);
441	if (info == NULL) {
442		return NT_STATUS_NO_MEMORY;
443	}
444
445	info->account_name = user_info->mapped.account_name;
446	info->plaintext_password = user_info->password.plaintext;
447
448	pamconv = talloc(ctx, struct pam_conv);
449	if (pamconv == NULL) {
450		return NT_STATUS_NO_MEMORY;
451	}
452
453	pamconv->conv = smb_pam_conv;
454	pamconv->appdata_ptr = (void *)info;
455
456	/* TODO:
457	 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
458	 * if true set up a crack name routine.
459	 */
460
461	nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
462	if (!NT_STATUS_IS_OK(nt_status)) {
463		return nt_status;
464	}
465
466	nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name);
467	if (!NT_STATUS_IS_OK(nt_status)) {
468		smb_pam_end(pamh);
469		return nt_status;
470	}
471
472	if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
473
474		nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
475		if (!NT_STATUS_IS_OK(nt_status)) {
476			smb_pam_end(pamh);
477			return nt_status;
478		}
479
480		nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
481		if (!NT_STATUS_IS_OK(nt_status)) {
482			smb_pam_end(pamh);
483			return nt_status;
484		}
485	}
486
487	smb_pam_end(pamh);
488
489	nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
490	if (!NT_STATUS_IS_OK(nt_status)) {
491		return nt_status;
492	}
493
494	return NT_STATUS_OK;
495}
496
497#else
498
499/****************************************************************************
500core of password checking routine
501****************************************************************************/
502static NTSTATUS password_check(const char *username, const char *password,
503					const char *crypted, const char *salt)
504{
505	bool ret;
506
507#ifdef WITH_AFS
508	if (afs_auth(username, password))
509		return NT_STATUS_OK;
510#endif /* WITH_AFS */
511
512#ifdef WITH_DFS
513	if (dfs_auth(username, password))
514		return NT_STATUS_OK;
515#endif /* WITH_DFS */
516
517#ifdef OSF1_ENH_SEC
518
519	ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
520
521	if (!ret) {
522		DEBUG(2,
523		      ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
524		ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
525	}
526	if (ret) {
527		return NT_STATUS_OK;
528	} else {
529		return NT_STATUS_WRONG_PASSWORD;
530	}
531
532#endif /* OSF1_ENH_SEC */
533
534#ifdef ULTRIX_AUTH
535	ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
536	if (ret) {
537		return NT_STATUS_OK;
538        } else {
539		return NT_STATUS_WRONG_PASSWORD;
540	}
541
542#endif /* ULTRIX_AUTH */
543
544#ifdef LINUX_BIGCRYPT
545	ret = (linux_bigcrypt(password, salt, crypted));
546        if (ret) {
547		return NT_STATUS_OK;
548	} else {
549		return NT_STATUS_WRONG_PASSWORD;
550	}
551#endif /* LINUX_BIGCRYPT */
552
553#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
554
555	/*
556	 * Some systems have bigcrypt in the C library but might not
557	 * actually use it for the password hashes (HPUX 10.20) is
558	 * a noteable example. So we try bigcrypt first, followed
559	 * by crypt.
560	 */
561
562	if (strcmp(bigcrypt(password, salt), crypted) == 0)
563		return NT_STATUS_OK;
564	else
565		ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
566	if (ret) {
567		return NT_STATUS_OK;
568	} else {
569		return NT_STATUS_WRONG_PASSWORD;
570	}
571#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
572
573#ifdef HAVE_BIGCRYPT
574	ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
575        if (ret) {
576		return NT_STATUS_OK;
577	} else {
578		return NT_STATUS_WRONG_PASSWORD;
579	}
580#endif /* HAVE_BIGCRYPT */
581
582#ifndef HAVE_CRYPT
583	DEBUG(1, ("Warning - no crypt available\n"));
584	return NT_STATUS_LOGON_FAILURE;
585#else /* HAVE_CRYPT */
586	ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
587        if (ret) {
588		return NT_STATUS_OK;
589	} else {
590		return NT_STATUS_WRONG_PASSWORD;
591	}
592#endif /* HAVE_CRYPT */
593#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
594}
595
596static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
597				    const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
598{
599	char *username;
600	char *password;
601	char *pwcopy;
602	char *salt;
603	char *crypted;
604	struct passwd *pws;
605	NTSTATUS nt_status;
606	int level = lp_passwordlevel(lp_ctx);
607
608	*ret_passwd = NULL;
609
610	username = talloc_strdup(ctx, user_info->mapped.account_name);
611	password = talloc_strdup(ctx, user_info->password.plaintext);
612
613	nt_status = talloc_getpwnam(ctx, username, &pws);
614	if (!NT_STATUS_IS_OK(nt_status)) {
615		return nt_status;
616	}
617
618	crypted = pws->pw_passwd;
619	salt = pws->pw_passwd;
620
621#ifdef HAVE_GETSPNAM
622	{
623		struct spwd *spass;
624
625		/* many shadow systems require you to be root to get
626		   the password, in most cases this should already be
627		   the case when this function is called, except
628		   perhaps for IPC password changing requests */
629
630		spass = getspnam(pws->pw_name);
631		if (spass && spass->sp_pwdp) {
632			crypted = talloc_strdup(ctx, spass->sp_pwdp);
633			NT_STATUS_HAVE_NO_MEMORY(crypted);
634			salt = talloc_strdup(ctx, spass->sp_pwdp);
635			NT_STATUS_HAVE_NO_MEMORY(salt);
636		}
637	}
638#elif defined(IA_UINFO)
639	{
640		char *ia_password;
641		/* Need to get password with SVR4.2's ia_ functions
642		   instead of get{sp,pw}ent functions. Required by
643		   UnixWare 2.x, tested on version
644		   2.1. (tangent@cyberport.com) */
645		uinfo_t uinfo;
646		if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
647			ia_get_logpwd(uinfo, &ia_password);
648			crypted = talloc_strdup(ctx, ia_password);
649			NT_STATUS_HAVE_NO_MEMORY(crypted);
650		}
651	}
652#endif
653
654#ifdef HAVE_GETPRPWNAM
655	{
656		struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
657		if (pr_pw && pr_pw->ufld.fd_encrypt) {
658			crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
659			NT_STATUS_HAVE_NO_MEMORY(crypted);
660		}
661	}
662#endif
663
664#ifdef HAVE_GETPWANAM
665	{
666		struct passwd_adjunct *pwret;
667		pwret = getpwanam(s);
668		if (pwret && pwret->pwa_passwd) {
669			crypted = talloc_strdup(ctx, pwret->pwa_passwd);
670			NT_STATUS_HAVE_NO_MEMORY(crypted);
671		}
672	}
673#endif
674
675#ifdef OSF1_ENH_SEC
676	{
677		struct pr_passwd *mypasswd;
678		DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
679		mypasswd = getprpwnam(username);
680		if (mypasswd) {
681			username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
682			NT_STATUS_HAVE_NO_MEMORY(username);
683			crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
684			NT_STATUS_HAVE_NO_MEMORY(crypted);
685		} else {
686			DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
687		}
688	}
689#endif
690
691#ifdef ULTRIX_AUTH
692	{
693		AUTHORIZATION *ap = getauthuid(pws->pw_uid);
694		if (ap) {
695			crypted = talloc_strdup(ctx, ap->a_password);
696			endauthent();
697			NT_STATUS_HAVE_NO_MEMORY(crypted);
698		}
699	}
700#endif
701
702#if defined(HAVE_TRUNCATED_SALT)
703	/* crypt on some platforms (HPUX in particular)
704	   won't work with more than 2 salt characters. */
705	salt[2] = 0;
706#endif
707
708	if (crypted[0] == '\0') {
709		if (!lp_null_passwords(lp_ctx)) {
710			DEBUG(2, ("Disallowing %s with null password\n", username));
711			return NT_STATUS_LOGON_FAILURE;
712		}
713		if (password == NULL) {
714			DEBUG(3, ("Allowing access to %s with null password\n", username));
715			*ret_passwd = pws;
716			return NT_STATUS_OK;
717		}
718	}
719
720	/* try it as it came to us */
721	nt_status = password_check(username, password, crypted, salt);
722        if (NT_STATUS_IS_OK(nt_status)) {
723		*ret_passwd = pws;
724		return nt_status;
725	}
726	else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
727		/* No point continuing if its not the password thats to blame (ie PAM disabled). */
728		return nt_status;
729	}
730
731	if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
732		return nt_status;
733	}
734
735	/* if the password was given to us with mixed case then we don't
736	 * need to proceed as we know it hasn't been case modified by the
737	 * client */
738	if (strhasupper(password) && strhaslower(password)) {
739		return nt_status;
740	}
741
742	/* make a copy of it */
743	pwcopy = talloc_strdup(ctx, password);
744	if (!pwcopy)
745		return NT_STATUS_NO_MEMORY;
746
747	/* try all lowercase if it's currently all uppercase */
748	if (strhasupper(pwcopy)) {
749		strlower(pwcopy);
750		nt_status = password_check(username, pwcopy, crypted, salt);
751		if NT_STATUS_IS_OK(nt_status) {
752			*ret_passwd = pws;
753			return nt_status;
754		}
755	}
756
757	/* give up? */
758	if (level < 1) {
759		return NT_STATUS_WRONG_PASSWORD;
760	}
761
762	/* last chance - all combinations of up to level chars upper! */
763	strlower(pwcopy);
764
765#if 0
766        if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
767		*ret_passwd = pws;
768		return nt_status;
769	}
770#endif
771	return NT_STATUS_WRONG_PASSWORD;
772}
773
774#endif
775
776/** Check a plaintext username/password
777 *
778 **/
779
780static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
781				    TALLOC_CTX *mem_ctx,
782				    const struct auth_usersupplied_info *user_info)
783{
784	if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
785		return NT_STATUS_NOT_IMPLEMENTED;
786	}
787
788	return NT_STATUS_OK;
789}
790
791static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
792					TALLOC_CTX *mem_ctx,
793					const struct auth_usersupplied_info *user_info,
794					struct auth_serversupplied_info **server_info)
795{
796	TALLOC_CTX *check_ctx;
797	NTSTATUS nt_status;
798	struct passwd *pwd;
799
800	if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
801		return NT_STATUS_INVALID_PARAMETER;
802	}
803
804	check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
805	if (check_ctx == NULL) {
806		return NT_STATUS_NO_MEMORY;
807	}
808
809	nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
810	if (!NT_STATUS_IS_OK(nt_status)) {
811		talloc_free(check_ctx);
812		return nt_status;
813	}
814
815	nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx),
816					      user_info, pwd, server_info);
817	if (!NT_STATUS_IS_OK(nt_status)) {
818		talloc_free(check_ctx);
819		return nt_status;
820	}
821
822	talloc_free(check_ctx);
823	return NT_STATUS_OK;
824}
825
826static const struct auth_operations unix_ops = {
827	.name		= "unix",
828	.get_challenge	= auth_get_challenge_not_implemented,
829	.want_check	= authunix_want_check,
830	.check_password	= authunix_check_password
831};
832
833_PUBLIC_ NTSTATUS auth_unix_init(void)
834{
835	NTSTATUS ret;
836
837	ret = auth_register(&unix_ops);
838	if (!NT_STATUS_IS_OK(ret)) {
839		DEBUG(0,("Failed to register unix auth backend!\n"));
840		return ret;
841	}
842
843	return ret;
844}
845