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
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.
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.
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.
24 #include "auth/auth.h"
25 #include "system/passwd.h"
26 #include "system/iconv.h"
28 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
29 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
31 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
32 const struct auth_usersupplied_info *user_info,
33 struct auth_serversupplied_info **_server_info)
35 struct auth_serversupplied_info *server_info;
37 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
38 NT_STATUS_HAVE_NO_MEMORY(server_info);
40 server_info->authenticated = True;
42 server_info->account_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, user_info->mapped.account_name));
43 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
45 server_info->domain_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, "unix"));
46 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
49 /* is this correct? */
50 server_info->account_sid = NULL;
51 server_info->primary_group_sid = NULL;
52 server_info->n_domain_groups = 0;
53 server_info->domain_groups = NULL;
54 server_info->user_session_key = data_blob(NULL,0);
55 server_info->lm_session_key = data_blob(NULL,0);
57 server_info->full_name = talloc_strdup(server_info, "");
58 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
59 server_info->logon_script = talloc_strdup(server_info, "");
60 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
61 server_info->profile_path = talloc_strdup(server_info, "");
62 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
63 server_info->home_directory = talloc_strdup(server_info, "");
64 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
65 server_info->home_drive = talloc_strdup(server_info, "");
66 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
68 server_info->last_logon = 0;
69 server_info->last_logoff = 0;
70 server_info->acct_expiry = 0;
71 server_info->last_password_change = 0;
72 server_info->allow_password_change = 0;
73 server_info->force_password_change = 0;
74 server_info->logon_count = 0;
75 server_info->bad_password_count = 0;
76 server_info->acct_flags = 0;
78 *_server_info = server_info;
83 #ifdef HAVE_SECURITY_PAM_APPL_H
84 #include <security/pam_appl.h>
86 struct smb_pam_user_info {
87 const char *account_name;
88 const char *plaintext_password;
91 #define COPY_STRING(s) (s) ? strdup(s) : NULL
95 * Currently it uses PAM only and fails on systems without PAM
96 * Samba3 code located in pass_check.c is to ugly to be used directly it will
97 * need major rework that's why pass_check.c is still there.
100 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
101 struct pam_response **reply, void *appdata_ptr)
103 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
112 * Apparantly HPUX has a buggy PAM that doesn't support the
113 * data pointer. Fail if this is the case. JRA.
122 * PAM frees memory in reply messages by itself
123 * so use malloc instead of talloc here.
125 *reply = malloc_array_p(struct pam_response, num_msg);
126 if (*reply == NULL) {
130 for (num = 0; num < num_msg; num++) {
131 switch (msg[num]->msg_style) {
132 case PAM_PROMPT_ECHO_ON:
133 (*reply)[num].resp_retcode = PAM_SUCCESS;
134 (*reply)[num].resp = COPY_STRING(info->account_name);
137 case PAM_PROMPT_ECHO_OFF:
138 (*reply)[num].resp_retcode = PAM_SUCCESS;
139 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
143 (*reply)[num].resp_retcode = PAM_SUCCESS;
144 (*reply)[num].resp = NULL;
145 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
148 (*reply)[num].resp_retcode = PAM_SUCCESS;
149 (*reply)[num].resp = NULL;
150 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
156 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
165 * Start PAM authentication for specified account
168 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
172 if (account_name == NULL || remote_host == NULL) {
173 return NT_STATUS_INVALID_PARAMETER;
176 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
178 pam_error = pam_start("samba", account_name, pconv, pamh);
179 if (pam_error != PAM_SUCCESS) {
180 /* no vaild pamh here, can we reliably call pam_strerror ? */
181 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
182 return NT_STATUS_UNSUCCESSFUL;
186 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
187 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
188 if (pam_error != PAM_SUCCESS) {
191 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
192 pam_strerror(*pamh, pam_error)));
193 nt_status = pam_to_nt_status(pam_error);
195 pam_error = pam_end(*pamh, 0);
196 if (pam_error != PAM_SUCCESS) {
197 /* no vaild pamh here, can we reliably call pam_strerror ? */
198 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
200 return pam_to_nt_status(pam_error);
206 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
207 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
208 if (pam_error != PAM_SUCCESS) {
211 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
212 pam_strerror(*pamh, pam_error)));
213 nt_status = pam_to_nt_status(pam_error);
215 pam_error = pam_end(*pamh, 0);
216 if (pam_error != PAM_SUCCESS) {
217 /* no vaild pamh here, can we reliably call pam_strerror ? */
218 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
220 return pam_to_nt_status(pam_error);
225 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
230 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
235 pam_error = pam_end(pamh, 0);
236 if (pam_error != PAM_SUCCESS) {
237 /* no vaild pamh here, can we reliably call pam_strerror ? */
238 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
240 return pam_to_nt_status(pam_error);
245 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
246 return NT_STATUS_UNSUCCESSFUL;
250 * PAM Authentication Handler
252 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
257 * To enable debugging set in /etc/pam.d/samba:
258 * auth required /lib/security/pam_pwdb.so nullok shadow audit
261 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
263 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
266 DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
268 case PAM_CRED_INSUFFICIENT:
269 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
271 case PAM_AUTHINFO_UNAVAIL:
272 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
274 case PAM_USER_UNKNOWN:
275 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
278 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
281 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
284 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
287 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
291 return pam_to_nt_status(pam_error);
295 * PAM Account Handler
297 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
301 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
303 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
304 switch( pam_error ) {
305 case PAM_AUTHTOK_EXPIRED:
306 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
308 case PAM_ACCT_EXPIRED:
309 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
312 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
314 case PAM_PERM_DENIED:
315 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
317 case PAM_USER_UNKNOWN:
318 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
321 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
324 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
328 return pam_to_nt_status(pam_error);
332 * PAM Credential Setting
335 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
340 * This will allow samba to aquire a kerberos token. And, when
341 * exporting an AFS cell, be able to /write/ to this cell.
344 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
346 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
347 switch( pam_error ) {
348 case PAM_CRED_UNAVAIL:
349 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
351 case PAM_CRED_EXPIRED:
352 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
354 case PAM_USER_UNKNOWN:
355 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
358 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
361 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
364 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
368 return pam_to_nt_status(pam_error);
371 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
373 struct smb_pam_user_info *info;
374 struct pam_conv *pamconv;
378 info = talloc(ctx, struct smb_pam_user_info);
380 return NT_STATUS_NO_MEMORY;
383 info->account_name = user_info->mapped.account_name;
384 info->plaintext_password = user_info->password.plaintext;
386 pamconv = talloc(ctx, struct pam_conv);
387 if (pamconv == NULL) {
388 return NT_STATUS_NO_MEMORY;
391 pamconv->conv = smb_pam_conv;
392 pamconv->appdata_ptr = (void *)info;
395 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
396 * if true set up a crack name routine.
399 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host, pamconv);
400 if (!NT_STATUS_IS_OK(nt_status)) {
405 nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
406 if (!NT_STATUS_IS_OK(nt_status)) {
411 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
413 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
414 if (!NT_STATUS_IS_OK(nt_status)) {
419 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
420 if (!NT_STATUS_IS_OK(nt_status)) {
432 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
439 ret = talloc(ctx, struct passwd);
440 NT_STATUS_HAVE_NO_MEMORY(ret);
442 from = getpwnam(username);
444 return NT_STATUS_NO_SUCH_USER;
447 ret->pw_name = talloc_strdup(ctx, from->pw_name);
448 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
450 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
451 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
453 ret->pw_uid = from->pw_uid;
454 ret->pw_gid = from->pw_gid;
455 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
456 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
458 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
459 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
461 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
462 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
470 /****************************************************************************
471 core of password checking routine
472 ****************************************************************************/
473 static NTSTATUS password_check(const char *username, const char *password,
474 const char *crypted, const char *salt)
479 if (afs_auth(username, password))
481 #endif /* WITH_AFS */
484 if (dfs_auth(username, password))
486 #endif /* WITH_DFS */
490 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
494 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
495 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
500 return NT_STATUS_WRONG_PASSWORD;
503 #endif /* OSF1_ENH_SEC */
506 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
510 return NT_STATUS_WRONG_PASSWORD;
513 #endif /* ULTRIX_AUTH */
515 #ifdef LINUX_BIGCRYPT
516 ret = (linux_bigcrypt(password, salt, crypted));
520 return NT_STATUS_WRONG_PASSWORD;
522 #endif /* LINUX_BIGCRYPT */
524 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
527 * Some systems have bigcrypt in the C library but might not
528 * actually use it for the password hashes (HPUX 10.20) is
529 * a noteable example. So we try bigcrypt first, followed
533 if (strcmp(bigcrypt(password, salt), crypted) == 0)
536 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
540 return NT_STATUS_WRONG_PASSWORD;
542 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
545 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
549 return NT_STATUS_WRONG_PASSWORD;
551 #endif /* HAVE_BIGCRYPT */
554 DEBUG(1, ("Warning - no crypt available\n"));
555 return NT_STATUS_LOGON_FAILURE;
556 #else /* HAVE_CRYPT */
557 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
561 return NT_STATUS_WRONG_PASSWORD;
563 #endif /* HAVE_CRYPT */
564 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
567 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
576 int level = lp_passwordlevel();
578 username = talloc_strdup(ctx, user_info->mapped.account_name);
579 password = talloc_strdup(ctx, user_info->password.plaintext);
581 nt_status = talloc_getpwnam(ctx, username, &pws);
582 if (!NT_STATUS_IS_OK(nt_status)) {
586 crypted = pws->pw_passwd;
587 salt = pws->pw_passwd;
593 /* many shadow systems require you to be root to get
594 the password, in most cases this should already be
595 the case when this function is called, except
596 perhaps for IPC password changing requests */
598 spass = getspnam(pws->pw_name);
599 if (spass && spass->sp_pwdp) {
600 crypted = talloc_strdup(ctx, spass->sp_pwdp);
601 NT_STATUS_HAVE_NO_MEMORY(crypted);
602 salt = talloc_strdup(ctx, spass->sp_pwdp);
603 NT_STATUS_HAVE_NO_MEMORY(salt);
606 #elif defined(IA_UINFO)
609 /* Need to get password with SVR4.2's ia_ functions
610 instead of get{sp,pw}ent functions. Required by
611 UnixWare 2.x, tested on version
612 2.1. (tangent@cyberport.com) */
614 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
615 ia_get_logpwd(uinfo, &ia_password);
616 crypted = talloc_strdup(ctx, ia_password);
617 NT_STATUS_HAVE_NO_MEMORY(crypted);
622 #ifdef HAVE_GETPRPWNAM
624 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
625 if (pr_pw && pr_pw->ufld.fd_encrypt) {
626 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
627 NT_STATUS_HAVE_NO_MEMORY(crypted);
632 #ifdef HAVE_GETPWANAM
634 struct passwd_adjunct *pwret;
635 pwret = getpwanam(s);
636 if (pwret && pwret->pwa_passwd) {
637 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
638 NT_STATUS_HAVE_NO_MEMORY(crypted);
645 struct pr_passwd *mypasswd;
646 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
647 mypasswd = getprpwnam(username);
649 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
650 NT_STATUS_HAVE_NO_MEMORY(username);
651 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
652 NT_STATUS_HAVE_NO_MEMORY(crypted);
654 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
661 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
663 crypted = talloc_strdup(ctx, ap->a_password);
665 NT_STATUS_HAVE_NO_MEMORY(crypted);
670 #if defined(HAVE_TRUNCATED_SALT)
671 /* crypt on some platforms (HPUX in particular)
672 won't work with more than 2 salt characters. */
676 if (crypted[0] == '\0') {
677 if (!lp_null_passwords()) {
678 DEBUG(2, ("Disallowing %s with null password\n", username));
679 return NT_STATUS_LOGON_FAILURE;
681 if (password == NULL) {
682 DEBUG(3, ("Allowing access to %s with null password\n", username));
687 /* try it as it came to us */
688 nt_status = password_check(username, password, crypted, salt);
689 if NT_STATUS_IS_OK(nt_status) {
692 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
693 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
697 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
701 /* if the password was given to us with mixed case then we don't
702 * need to proceed as we know it hasn't been case modified by the
704 if (strhasupper(password) && strhaslower(password)) {
708 /* make a copy of it */
709 pwcopy = talloc_strdup(ctx, password);
711 return NT_STATUS_NO_MEMORY;
713 /* try all lowercase if it's currently all uppercase */
714 if (strhasupper(pwcopy)) {
716 nt_status = password_check(username, pwcopy, crypted, salt);
717 if NT_STATUS_IS_OK(nt_status) {
724 return NT_STATUS_WRONG_PASSWORD;
727 /* last chance - all combinations of up to level chars upper! */
731 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
735 return NT_STATUS_WRONG_PASSWORD;
740 /** Check a plaintext username/password
744 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
746 const struct auth_usersupplied_info *user_info,
747 struct auth_serversupplied_info **server_info)
749 TALLOC_CTX *check_ctx;
752 if (! user_info->mapped.account_name || ! *user_info->mapped.account_name) {
754 return NT_STATUS_NOT_IMPLEMENTED;
757 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
758 return NT_STATUS_INVALID_PARAMETER;
761 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
762 if (check_ctx == NULL) {
763 return NT_STATUS_NO_MEMORY;
766 nt_status = check_unix_password(check_ctx, user_info);
767 if ( ! NT_STATUS_IS_OK(nt_status)) {
768 talloc_free(check_ctx);
772 nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
773 if ( ! NT_STATUS_IS_OK(nt_status)) {
774 talloc_free(check_ctx);
778 talloc_free(check_ctx);
782 static const struct auth_operations unix_ops = {
784 .get_challenge = auth_get_challenge_not_implemented,
785 .check_password = authunix_check_password
788 NTSTATUS auth_unix_init(void)
792 ret = auth_register(&unix_ops);
793 if (!NT_STATUS_IS_OK(ret)) {
794 DEBUG(0,("Failed to register unix auth backend!\n"));