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"
27 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
28 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
30 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
31 const struct auth_usersupplied_info *user_info,
32 struct auth_serversupplied_info **_server_info)
34 struct auth_serversupplied_info *server_info;
36 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
37 NT_STATUS_HAVE_NO_MEMORY(server_info);
39 server_info->authenticated = True;
41 server_info->account_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, user_info->account_name));
42 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
44 server_info->domain_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, "unix"));
45 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
48 /* is this correct? */
49 server_info->account_sid = NULL;
50 server_info->primary_group_sid = NULL;
51 server_info->n_domain_groups = 0;
52 server_info->domain_groups = NULL;
53 server_info->user_session_key = data_blob(NULL,0);
54 server_info->lm_session_key = data_blob(NULL,0);
56 server_info->full_name = talloc_strdup(server_info, "");
57 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
58 server_info->logon_script = talloc_strdup(server_info, "");
59 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
60 server_info->profile_path = talloc_strdup(server_info, "");
61 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
62 server_info->home_directory = talloc_strdup(server_info, "");
63 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
64 server_info->home_drive = talloc_strdup(server_info, "");
65 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
67 server_info->last_logon = 0;
68 server_info->last_logoff = 0;
69 server_info->acct_expiry = 0;
70 server_info->last_password_change = 0;
71 server_info->allow_password_change = 0;
72 server_info->force_password_change = 0;
73 server_info->logon_count = 0;
74 server_info->bad_password_count = 0;
75 server_info->acct_flags = 0;
77 *_server_info = server_info;
82 #ifdef HAVE_SECURITY_PAM_APPL_H
83 #include <security/pam_appl.h>
85 struct smb_pam_user_info {
86 const char *account_name;
87 const char *plaintext_password;
90 #define COPY_STRING(s) (s) ? strdup(s) : NULL
94 * Currently it uses PAM only and fails on systems without PAM
95 * Samba3 code located in pass_check.c is to ugly to be used directly it will
96 * need major rework that's why pass_check.c is still there.
99 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
100 struct pam_response **reply, void *appdata_ptr)
102 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
111 * Apparantly HPUX has a buggy PAM that doesn't support the
112 * data pointer. Fail if this is the case. JRA.
121 * PAM frees memory in reply messages by itself
122 * so use malloc instead of talloc here.
124 *reply = malloc_array_p(struct pam_response, num_msg);
125 if (*reply == NULL) {
129 for (num = 0; num < num_msg; num++) {
130 switch (msg[num]->msg_style) {
131 case PAM_PROMPT_ECHO_ON:
132 (*reply)[num].resp_retcode = PAM_SUCCESS;
133 (*reply)[num].resp = COPY_STRING(info->account_name);
136 case PAM_PROMPT_ECHO_OFF:
137 (*reply)[num].resp_retcode = PAM_SUCCESS;
138 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
142 (*reply)[num].resp_retcode = PAM_SUCCESS;
143 (*reply)[num].resp = NULL;
144 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
147 (*reply)[num].resp_retcode = PAM_SUCCESS;
148 (*reply)[num].resp = NULL;
149 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
155 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
164 * Start PAM authentication for specified account
167 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) {
189 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
190 pam_strerror(*pamh, pam_error)));
191 nt_status = pam_to_nt_status(pam_error);
193 pam_error = pam_end(*pamh, 0);
194 if (pam_error != PAM_SUCCESS) {
195 /* no vaild pamh here, can we reliably call pam_strerror ? */
196 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
198 return pam_to_nt_status(pam_error);
204 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
205 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
206 if (pam_error != PAM_SUCCESS) {
207 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
208 pam_strerror(*pamh, pam_error)));
209 nt_status = pam_to_nt_status(pam_error);
211 pam_error = pam_end(*pamh, 0);
212 if (pam_error != PAM_SUCCESS) {
213 /* no vaild pamh here, can we reliably call pam_strerror ? */
214 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
216 return pam_to_nt_status(pam_error);
221 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
226 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
231 pam_error = pam_end(pamh, 0);
232 if (pam_error != PAM_SUCCESS) {
233 /* no vaild pamh here, can we reliably call pam_strerror ? */
234 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
236 return pam_to_nt_status(pam_error);
241 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
242 return NT_STATUS_UNSUCCESSFUL;
246 * PAM Authentication Handler
248 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
253 * To enable debugging set in /etc/pam.d/samba:
254 * auth required /lib/security/pam_pwdb.so nullok shadow audit
257 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
259 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
262 DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
264 case PAM_CRED_INSUFFICIENT:
265 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
267 case PAM_AUTHINFO_UNAVAIL:
268 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
270 case PAM_USER_UNKNOWN:
271 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
274 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
277 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
280 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
283 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
287 return pam_to_nt_status(pam_error);
291 * PAM Account Handler
293 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
297 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
299 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
300 switch( pam_error ) {
301 case PAM_AUTHTOK_EXPIRED:
302 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
304 case PAM_ACCT_EXPIRED:
305 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
308 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
310 case PAM_PERM_DENIED:
311 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
313 case PAM_USER_UNKNOWN:
314 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
317 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
320 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
324 return pam_to_nt_status(pam_error);
328 * PAM Credential Setting
331 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
336 * This will allow samba to aquire a kerberos token. And, when
337 * exporting an AFS cell, be able to /write/ to this cell.
340 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
342 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
343 switch( pam_error ) {
344 case PAM_CRED_UNAVAIL:
345 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
347 case PAM_CRED_EXPIRED:
348 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
350 case PAM_USER_UNKNOWN:
351 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
354 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
357 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
360 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
364 return pam_to_nt_status(pam_error);
367 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
369 struct smb_pam_user_info *info;
370 struct pam_conv *pamconv;
374 info = talloc(ctx, struct smb_pam_user_info);
376 return NT_STATUS_NO_MEMORY;
379 info->account_name = user_info->account_name;
380 info->plaintext_password = (char *)(user_info->plaintext_password.data);
382 pamconv = talloc(ctx, struct pam_conv);
383 if (pamconv == NULL) {
384 return NT_STATUS_NO_MEMORY;
387 pamconv->conv = smb_pam_conv;
388 pamconv->appdata_ptr = (void *)info;
391 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
392 * if true set up a crack name routine.
395 nt_status = smb_pam_start(&pamh, user_info->account_name, user_info->remote_host, pamconv);
396 if (!NT_STATUS_IS_OK(nt_status)) {
401 nt_status = smb_pam_auth(pamh, user_info->account_name);
402 if (!NT_STATUS_IS_OK(nt_status)) {
407 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
409 nt_status = smb_pam_account(pamh, user_info->account_name);
410 if (!NT_STATUS_IS_OK(nt_status)) {
415 nt_status = smb_pam_setcred(pamh, user_info->account_name);
416 if (!NT_STATUS_IS_OK(nt_status)) {
428 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
435 ret = talloc(ctx, struct passwd);
436 NT_STATUS_HAVE_NO_MEMORY(ret);
438 from = getpwnam(username);
440 return NT_STATUS_NO_SUCH_USER;
443 ret->pw_name = talloc_strdup(ctx, from->pw_name);
444 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
446 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
447 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
449 ret->pw_uid = from->pw_uid;
450 ret->pw_gid = from->pw_gid;
451 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
452 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
454 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
455 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
457 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
458 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
466 /****************************************************************************
467 core of password checking routine
468 ****************************************************************************/
469 static NTSTATUS password_check(const char *username, const char *password,
470 const char *crypted, const char *salt)
475 if (afs_auth(username, password))
477 #endif /* WITH_AFS */
480 if (dfs_auth(username, password))
482 #endif /* WITH_DFS */
486 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
490 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
491 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
496 return NT_STATUS_WRONG_PASSWORD;
499 #endif /* OSF1_ENH_SEC */
502 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
506 return NT_STATUS_WRONG_PASSWORD;
509 #endif /* ULTRIX_AUTH */
511 #ifdef LINUX_BIGCRYPT
512 ret = (linux_bigcrypt(password, salt, crypted));
516 return NT_STATUS_WRONG_PASSWORD;
518 #endif /* LINUX_BIGCRYPT */
520 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
523 * Some systems have bigcrypt in the C library but might not
524 * actually use it for the password hashes (HPUX 10.20) is
525 * a noteable example. So we try bigcrypt first, followed
529 if (strcmp(bigcrypt(password, salt), crypted) == 0)
532 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
536 return NT_STATUS_WRONG_PASSWORD;
538 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
541 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
545 return NT_STATUS_WRONG_PASSWORD;
547 #endif /* HAVE_BIGCRYPT */
550 DEBUG(1, ("Warning - no crypt available\n"));
551 return NT_STATUS_LOGON_FAILURE;
552 #else /* HAVE_CRYPT */
553 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
557 return NT_STATUS_WRONG_PASSWORD;
559 #endif /* HAVE_CRYPT */
560 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
564 Does a string have any lowercase chars in it?
566 static BOOL strhaslower(const char *s)
569 if (islower(*s)) return True;
576 Does a string have any uppercase chars in it?
578 static BOOL strhasupper(const char *s)
581 if (isupper(*s)) return True;
587 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
596 int level = lp_passwordlevel();
598 username = talloc_strdup(ctx, user_info->account_name);
599 password = talloc_strdup(ctx, user_info->plaintext_password.data);
601 nt_status = talloc_getpwnam(ctx, username, &pws);
602 if (!NT_STATUS_IS_OK(nt_status)) {
606 crypted = pws->pw_passwd;
607 salt = pws->pw_passwd;
613 /* many shadow systems require you to be root to get
614 the password, in most cases this should already be
615 the case when this function is called, except
616 perhaps for IPC password changing requests */
618 spass = getspnam(pws->pw_name);
619 if (spass && spass->sp_pwdp) {
620 crypted = talloc_strdup(ctx, spass->sp_pwdp);
621 NT_STATUS_HAVE_NO_MEMORY(crypted);
622 salt = talloc_strdup(ctx, spass->sp_pwdp);
623 NT_STATUS_HAVE_NO_MEMORY(salt);
626 #elif defined(IA_UINFO)
629 /* Need to get password with SVR4.2's ia_ functions
630 instead of get{sp,pw}ent functions. Required by
631 UnixWare 2.x, tested on version
632 2.1. (tangent@cyberport.com) */
634 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
635 ia_get_logpwd(uinfo, &ia_password);
636 crypted = talloc_strdup(ctx, ia_password);
637 NT_STATUS_HAVE_NO_MEMORY(crypted);
642 #ifdef HAVE_GETPRPWNAM
644 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
645 if (pr_pw && pr_pw->ufld.fd_encrypt) {
646 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
647 NT_STATUS_HAVE_NO_MEMORY(crypted);
652 #ifdef HAVE_GETPWANAM
654 struct passwd_adjunct *pwret;
655 pwret = getpwanam(s);
656 if (pwret && pwret->pwa_passwd) {
657 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
658 NT_STATUS_HAVE_NO_MEMORY(crypted);
665 struct pr_passwd *mypasswd;
666 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
667 mypasswd = getprpwnam(username);
669 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
670 NT_STATUS_HAVE_NO_MEMORY(username);
671 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
672 NT_STATUS_HAVE_NO_MEMORY(crypted);
674 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
681 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
683 crypted = talloc_strdup(ctx, ap->a_password);
685 NT_STATUS_HAVE_NO_MEMORY(crypted);
690 #if defined(HAVE_TRUNCATED_SALT)
691 /* crypt on some platforms (HPUX in particular)
692 won't work with more than 2 salt characters. */
696 if (crypted[0] == '\0') {
697 if (!lp_null_passwords()) {
698 DEBUG(2, ("Disallowing %s with null password\n", username));
699 return NT_STATUS_LOGON_FAILURE;
701 if (password == NULL) {
702 DEBUG(3, ("Allowing access to %s with null password\n", username));
707 /* try it as it came to us */
708 nt_status = password_check(username, password, crypted, salt);
709 if NT_STATUS_IS_OK(nt_status) {
712 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
713 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
717 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
721 /* if the password was given to us with mixed case then we don't
722 * need to proceed as we know it hasn't been case modified by the
724 if (strhasupper(password) && strhaslower(password)) {
728 /* make a copy of it */
729 pwcopy = talloc_strdup(ctx, password);
731 return NT_STATUS_NO_MEMORY;
733 /* try all lowercase if it's currently all uppercase */
734 if (strhasupper(pwcopy)) {
736 nt_status = password_check(username, pwcopy, crypted, salt);
737 if NT_STATUS_IS_OK(nt_status) {
744 return NT_STATUS_WRONG_PASSWORD;
747 /* last chance - all combinations of up to level chars upper! */
751 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
755 return NT_STATUS_WRONG_PASSWORD;
760 /** Check a plaintext username/password
764 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
766 const struct auth_usersupplied_info *user_info,
767 struct auth_serversupplied_info **server_info)
769 TALLOC_CTX *check_ctx;
772 if (! user_info->account_name && ! *user_info->account_name) {
773 return NT_STATUS_INVALID_PARAMETER;
776 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
777 if (check_ctx == NULL) {
778 return NT_STATUS_NO_MEMORY;
781 nt_status = check_unix_password(check_ctx, user_info);
782 if ( ! NT_STATUS_IS_OK(nt_status)) {
783 talloc_free(check_ctx);
787 nt_status = authunix_make_server_info(check_ctx, user_info, server_info);
788 if ( ! NT_STATUS_IS_OK(nt_status)) {
789 talloc_free(check_ctx);
793 talloc_free(check_ctx);
797 static const struct auth_operations unix_ops = {
799 .get_challenge = auth_get_challenge_not_implemented,
800 .check_password = authunix_check_password
803 NTSTATUS auth_unix_init(void)
807 ret = auth_register(&unix_ops);
808 if (!NT_STATUS_IS_OK(ret)) {
809 DEBUG(0,("Failed to register unix auth backend!\n"));