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