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)
171 if (account_name == NULL || remote_host == NULL) {
172 return NT_STATUS_INVALID_PARAMETER;
175 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
177 pam_error = pam_start("samba", account_name, pconv, pamh);
178 if (pam_error != PAM_SUCCESS) {
179 /* no vaild pamh here, can we reliably call pam_strerror ? */
180 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
181 return NT_STATUS_UNSUCCESSFUL;
185 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
186 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
187 if (pam_error != PAM_SUCCESS) {
190 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
191 pam_strerror(*pamh, pam_error)));
192 nt_status = pam_to_nt_status(pam_error);
194 pam_error = pam_end(*pamh, 0);
195 if (pam_error != PAM_SUCCESS) {
196 /* no vaild pamh here, can we reliably call pam_strerror ? */
197 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
199 return pam_to_nt_status(pam_error);
205 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
206 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
207 if (pam_error != PAM_SUCCESS) {
210 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
211 pam_strerror(*pamh, pam_error)));
212 nt_status = pam_to_nt_status(pam_error);
214 pam_error = pam_end(*pamh, 0);
215 if (pam_error != PAM_SUCCESS) {
216 /* no vaild pamh here, can we reliably call pam_strerror ? */
217 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
219 return pam_to_nt_status(pam_error);
224 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
229 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
234 pam_error = pam_end(pamh, 0);
235 if (pam_error != PAM_SUCCESS) {
236 /* no vaild pamh here, can we reliably call pam_strerror ? */
237 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
239 return pam_to_nt_status(pam_error);
244 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
245 return NT_STATUS_UNSUCCESSFUL;
249 * PAM Authentication Handler
251 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
256 * To enable debugging set in /etc/pam.d/samba:
257 * auth required /lib/security/pam_pwdb.so nullok shadow audit
260 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
262 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
265 DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
267 case PAM_CRED_INSUFFICIENT:
268 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
270 case PAM_AUTHINFO_UNAVAIL:
271 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
273 case PAM_USER_UNKNOWN:
274 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
277 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
280 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
283 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
286 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
290 return pam_to_nt_status(pam_error);
294 * PAM Account Handler
296 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
300 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
302 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
303 switch( pam_error ) {
304 case PAM_AUTHTOK_EXPIRED:
305 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
307 case PAM_ACCT_EXPIRED:
308 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
311 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
313 case PAM_PERM_DENIED:
314 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
316 case PAM_USER_UNKNOWN:
317 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
320 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
323 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
327 return pam_to_nt_status(pam_error);
331 * PAM Credential Setting
334 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
339 * This will allow samba to aquire a kerberos token. And, when
340 * exporting an AFS cell, be able to /write/ to this cell.
343 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
345 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
346 switch( pam_error ) {
347 case PAM_CRED_UNAVAIL:
348 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
350 case PAM_CRED_EXPIRED:
351 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
353 case PAM_USER_UNKNOWN:
354 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
357 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
360 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
363 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
367 return pam_to_nt_status(pam_error);
370 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
372 struct smb_pam_user_info *info;
373 struct pam_conv *pamconv;
377 info = talloc(ctx, struct smb_pam_user_info);
379 return NT_STATUS_NO_MEMORY;
382 info->account_name = user_info->account_name;
383 info->plaintext_password = (char *)(user_info->plaintext_password.data);
385 pamconv = talloc(ctx, struct pam_conv);
386 if (pamconv == NULL) {
387 return NT_STATUS_NO_MEMORY;
390 pamconv->conv = smb_pam_conv;
391 pamconv->appdata_ptr = (void *)info;
394 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
395 * if true set up a crack name routine.
398 nt_status = smb_pam_start(&pamh, user_info->account_name, user_info->remote_host, pamconv);
399 if (!NT_STATUS_IS_OK(nt_status)) {
404 nt_status = smb_pam_auth(pamh, user_info->account_name);
405 if (!NT_STATUS_IS_OK(nt_status)) {
410 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
412 nt_status = smb_pam_account(pamh, user_info->account_name);
413 if (!NT_STATUS_IS_OK(nt_status)) {
418 nt_status = smb_pam_setcred(pamh, user_info->account_name);
419 if (!NT_STATUS_IS_OK(nt_status)) {
431 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
438 ret = talloc(ctx, struct passwd);
439 NT_STATUS_HAVE_NO_MEMORY(ret);
441 from = getpwnam(username);
443 return NT_STATUS_NO_SUCH_USER;
446 ret->pw_name = talloc_strdup(ctx, from->pw_name);
447 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
449 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
450 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
452 ret->pw_uid = from->pw_uid;
453 ret->pw_gid = from->pw_gid;
454 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
455 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
457 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
458 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
460 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
461 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
469 /****************************************************************************
470 core of password checking routine
471 ****************************************************************************/
472 static NTSTATUS password_check(const char *username, const char *password,
473 const char *crypted, const char *salt)
478 if (afs_auth(username, password))
480 #endif /* WITH_AFS */
483 if (dfs_auth(username, password))
485 #endif /* WITH_DFS */
489 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
493 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
494 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
499 return NT_STATUS_WRONG_PASSWORD;
502 #endif /* OSF1_ENH_SEC */
505 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
509 return NT_STATUS_WRONG_PASSWORD;
512 #endif /* ULTRIX_AUTH */
514 #ifdef LINUX_BIGCRYPT
515 ret = (linux_bigcrypt(password, salt, crypted));
519 return NT_STATUS_WRONG_PASSWORD;
521 #endif /* LINUX_BIGCRYPT */
523 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
526 * Some systems have bigcrypt in the C library but might not
527 * actually use it for the password hashes (HPUX 10.20) is
528 * a noteable example. So we try bigcrypt first, followed
532 if (strcmp(bigcrypt(password, salt), crypted) == 0)
535 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
539 return NT_STATUS_WRONG_PASSWORD;
541 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
544 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
548 return NT_STATUS_WRONG_PASSWORD;
550 #endif /* HAVE_BIGCRYPT */
553 DEBUG(1, ("Warning - no crypt available\n"));
554 return NT_STATUS_LOGON_FAILURE;
555 #else /* HAVE_CRYPT */
556 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
560 return NT_STATUS_WRONG_PASSWORD;
562 #endif /* HAVE_CRYPT */
563 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
567 Does a string have any lowercase chars in it?
569 static BOOL strhaslower(const char *s)
572 if (islower(*s)) return True;
579 Does a string have any uppercase chars in it?
581 static BOOL strhasupper(const char *s)
584 if (isupper(*s)) return True;
590 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
599 int level = lp_passwordlevel();
601 username = talloc_strdup(ctx, user_info->account_name);
602 password = talloc_strdup(ctx, user_info->plaintext_password.data);
604 nt_status = talloc_getpwnam(ctx, username, &pws);
605 if (!NT_STATUS_IS_OK(nt_status)) {
609 crypted = pws->pw_passwd;
610 salt = pws->pw_passwd;
616 /* many shadow systems require you to be root to get
617 the password, in most cases this should already be
618 the case when this function is called, except
619 perhaps for IPC password changing requests */
621 spass = getspnam(pws->pw_name);
622 if (spass && spass->sp_pwdp) {
623 crypted = talloc_strdup(ctx, spass->sp_pwdp);
624 NT_STATUS_HAVE_NO_MEMORY(crypted);
625 salt = talloc_strdup(ctx, spass->sp_pwdp);
626 NT_STATUS_HAVE_NO_MEMORY(salt);
629 #elif defined(IA_UINFO)
632 /* Need to get password with SVR4.2's ia_ functions
633 instead of get{sp,pw}ent functions. Required by
634 UnixWare 2.x, tested on version
635 2.1. (tangent@cyberport.com) */
637 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
638 ia_get_logpwd(uinfo, &ia_password);
639 crypted = talloc_strdup(ctx, ia_password);
640 NT_STATUS_HAVE_NO_MEMORY(crypted);
645 #ifdef HAVE_GETPRPWNAM
647 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
648 if (pr_pw && pr_pw->ufld.fd_encrypt) {
649 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
650 NT_STATUS_HAVE_NO_MEMORY(crypted);
655 #ifdef HAVE_GETPWANAM
657 struct passwd_adjunct *pwret;
658 pwret = getpwanam(s);
659 if (pwret && pwret->pwa_passwd) {
660 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
661 NT_STATUS_HAVE_NO_MEMORY(crypted);
668 struct pr_passwd *mypasswd;
669 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
670 mypasswd = getprpwnam(username);
672 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
673 NT_STATUS_HAVE_NO_MEMORY(username);
674 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
675 NT_STATUS_HAVE_NO_MEMORY(crypted);
677 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
684 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
686 crypted = talloc_strdup(ctx, ap->a_password);
688 NT_STATUS_HAVE_NO_MEMORY(crypted);
693 #if defined(HAVE_TRUNCATED_SALT)
694 /* crypt on some platforms (HPUX in particular)
695 won't work with more than 2 salt characters. */
699 if (crypted[0] == '\0') {
700 if (!lp_null_passwords()) {
701 DEBUG(2, ("Disallowing %s with null password\n", username));
702 return NT_STATUS_LOGON_FAILURE;
704 if (password == NULL) {
705 DEBUG(3, ("Allowing access to %s with null password\n", username));
710 /* try it as it came to us */
711 nt_status = password_check(username, password, crypted, salt);
712 if NT_STATUS_IS_OK(nt_status) {
715 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
716 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
720 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
724 /* if the password was given to us with mixed case then we don't
725 * need to proceed as we know it hasn't been case modified by the
727 if (strhasupper(password) && strhaslower(password)) {
731 /* make a copy of it */
732 pwcopy = talloc_strdup(ctx, password);
734 return NT_STATUS_NO_MEMORY;
736 /* try all lowercase if it's currently all uppercase */
737 if (strhasupper(pwcopy)) {
739 nt_status = password_check(username, pwcopy, crypted, salt);
740 if NT_STATUS_IS_OK(nt_status) {
747 return NT_STATUS_WRONG_PASSWORD;
750 /* last chance - all combinations of up to level chars upper! */
754 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
758 return NT_STATUS_WRONG_PASSWORD;
763 /** Check a plaintext username/password
767 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
769 const struct auth_usersupplied_info *user_info,
770 struct auth_serversupplied_info **server_info)
772 TALLOC_CTX *check_ctx;
775 if (! user_info->account_name && ! *user_info->account_name) {
776 return NT_STATUS_INVALID_PARAMETER;
779 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
780 if (check_ctx == NULL) {
781 return NT_STATUS_NO_MEMORY;
784 nt_status = check_unix_password(check_ctx, user_info);
785 if ( ! NT_STATUS_IS_OK(nt_status)) {
786 talloc_free(check_ctx);
790 nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
791 if ( ! NT_STATUS_IS_OK(nt_status)) {
792 talloc_free(check_ctx);
796 talloc_free(check_ctx);
800 static const struct auth_operations unix_ops = {
802 .get_challenge = auth_get_challenge_not_implemented,
803 .check_password = authunix_check_password
806 NTSTATUS auth_unix_init(void)
810 ret = auth_register(&unix_ops);
811 if (!NT_STATUS_IS_OK(ret)) {
812 DEBUG(0,("Failed to register unix auth backend!\n"));