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"
26 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
27 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
29 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
30 const struct auth_usersupplied_info *user_info,
31 struct auth_serversupplied_info **_server_info)
33 struct auth_serversupplied_info *server_info;
35 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
36 NT_STATUS_HAVE_NO_MEMORY(server_info);
38 server_info->authenticated = True;
40 server_info->account_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, user_info->mapped.account_name));
41 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
43 server_info->domain_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, "unix"));
44 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
47 /* is this correct? */
48 server_info->account_sid = NULL;
49 server_info->primary_group_sid = NULL;
50 server_info->n_domain_groups = 0;
51 server_info->domain_groups = NULL;
52 server_info->user_session_key = data_blob(NULL,0);
53 server_info->lm_session_key = data_blob(NULL,0);
55 server_info->full_name = talloc_strdup(server_info, "");
56 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
57 server_info->logon_script = talloc_strdup(server_info, "");
58 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
59 server_info->profile_path = talloc_strdup(server_info, "");
60 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
61 server_info->home_directory = talloc_strdup(server_info, "");
62 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
63 server_info->home_drive = talloc_strdup(server_info, "");
64 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
66 server_info->last_logon = 0;
67 server_info->last_logoff = 0;
68 server_info->acct_expiry = 0;
69 server_info->last_password_change = 0;
70 server_info->allow_password_change = 0;
71 server_info->force_password_change = 0;
72 server_info->logon_count = 0;
73 server_info->bad_password_count = 0;
74 server_info->acct_flags = 0;
76 *_server_info = server_info;
81 #ifdef HAVE_SECURITY_PAM_APPL_H
82 #include <security/pam_appl.h>
84 struct smb_pam_user_info {
85 const char *account_name;
86 const char *plaintext_password;
89 #define COPY_STRING(s) (s) ? strdup(s) : NULL
93 * Currently it uses PAM only and fails on systems without PAM
94 * Samba3 code located in pass_check.c is to ugly to be used directly it will
95 * need major rework that's why pass_check.c is still there.
98 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
99 struct pam_response **reply, void *appdata_ptr)
101 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
110 * Apparantly HPUX has a buggy PAM that doesn't support the
111 * data pointer. Fail if this is the case. JRA.
120 * PAM frees memory in reply messages by itself
121 * so use malloc instead of talloc here.
123 *reply = malloc_array_p(struct pam_response, num_msg);
124 if (*reply == NULL) {
128 for (num = 0; num < num_msg; num++) {
129 switch (msg[num]->msg_style) {
130 case PAM_PROMPT_ECHO_ON:
131 (*reply)[num].resp_retcode = PAM_SUCCESS;
132 (*reply)[num].resp = COPY_STRING(info->account_name);
135 case PAM_PROMPT_ECHO_OFF:
136 (*reply)[num].resp_retcode = PAM_SUCCESS;
137 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
141 (*reply)[num].resp_retcode = PAM_SUCCESS;
142 (*reply)[num].resp = NULL;
143 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
146 (*reply)[num].resp_retcode = PAM_SUCCESS;
147 (*reply)[num].resp = NULL;
148 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
154 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
163 * Start PAM authentication for specified account
166 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
170 if (account_name == NULL || remote_host == NULL) {
171 return NT_STATUS_INVALID_PARAMETER;
174 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
176 pam_error = pam_start("samba", account_name, pconv, pamh);
177 if (pam_error != PAM_SUCCESS) {
178 /* no vaild pamh here, can we reliably call pam_strerror ? */
179 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
180 return NT_STATUS_UNSUCCESSFUL;
184 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
185 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
186 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) {
209 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
210 pam_strerror(*pamh, pam_error)));
211 nt_status = pam_to_nt_status(pam_error);
213 pam_error = pam_end(*pamh, 0);
214 if (pam_error != PAM_SUCCESS) {
215 /* no vaild pamh here, can we reliably call pam_strerror ? */
216 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
218 return pam_to_nt_status(pam_error);
223 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
228 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
233 pam_error = pam_end(pamh, 0);
234 if (pam_error != PAM_SUCCESS) {
235 /* no vaild pamh here, can we reliably call pam_strerror ? */
236 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
238 return pam_to_nt_status(pam_error);
243 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
244 return NT_STATUS_UNSUCCESSFUL;
248 * PAM Authentication Handler
250 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
255 * To enable debugging set in /etc/pam.d/samba:
256 * auth required /lib/security/pam_pwdb.so nullok shadow audit
259 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
261 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
264 DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
266 case PAM_CRED_INSUFFICIENT:
267 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
269 case PAM_AUTHINFO_UNAVAIL:
270 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
272 case PAM_USER_UNKNOWN:
273 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
276 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
279 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
282 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
285 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
289 return pam_to_nt_status(pam_error);
293 * PAM Account Handler
295 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
299 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
301 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
302 switch( pam_error ) {
303 case PAM_AUTHTOK_EXPIRED:
304 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
306 case PAM_ACCT_EXPIRED:
307 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
310 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
312 case PAM_PERM_DENIED:
313 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
315 case PAM_USER_UNKNOWN:
316 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
319 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
322 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
326 return pam_to_nt_status(pam_error);
330 * PAM Credential Setting
333 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
338 * This will allow samba to aquire a kerberos token. And, when
339 * exporting an AFS cell, be able to /write/ to this cell.
342 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
344 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
345 switch( pam_error ) {
346 case PAM_CRED_UNAVAIL:
347 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
349 case PAM_CRED_EXPIRED:
350 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
352 case PAM_USER_UNKNOWN:
353 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
356 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
359 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
362 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
366 return pam_to_nt_status(pam_error);
369 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
371 struct smb_pam_user_info *info;
372 struct pam_conv *pamconv;
376 info = talloc(ctx, struct smb_pam_user_info);
378 return NT_STATUS_NO_MEMORY;
381 info->account_name = user_info->mapped.account_name;
382 info->plaintext_password = user_info->password.plaintext;
384 pamconv = talloc(ctx, struct pam_conv);
385 if (pamconv == NULL) {
386 return NT_STATUS_NO_MEMORY;
389 pamconv->conv = smb_pam_conv;
390 pamconv->appdata_ptr = (void *)info;
393 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
394 * if true set up a crack name routine.
397 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host, pamconv);
398 if (!NT_STATUS_IS_OK(nt_status)) {
403 nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
404 if (!NT_STATUS_IS_OK(nt_status)) {
409 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
411 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
412 if (!NT_STATUS_IS_OK(nt_status)) {
417 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
418 if (!NT_STATUS_IS_OK(nt_status)) {
430 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
437 ret = talloc(ctx, struct passwd);
438 NT_STATUS_HAVE_NO_MEMORY(ret);
440 from = getpwnam(username);
442 return NT_STATUS_NO_SUCH_USER;
445 ret->pw_name = talloc_strdup(ctx, from->pw_name);
446 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
448 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
449 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
451 ret->pw_uid = from->pw_uid;
452 ret->pw_gid = from->pw_gid;
453 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
454 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
456 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
457 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
459 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
460 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
468 /****************************************************************************
469 core of password checking routine
470 ****************************************************************************/
471 static NTSTATUS password_check(const char *username, const char *password,
472 const char *crypted, const char *salt)
477 if (afs_auth(username, password))
479 #endif /* WITH_AFS */
482 if (dfs_auth(username, password))
484 #endif /* WITH_DFS */
488 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
492 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
493 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
498 return NT_STATUS_WRONG_PASSWORD;
501 #endif /* OSF1_ENH_SEC */
504 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
508 return NT_STATUS_WRONG_PASSWORD;
511 #endif /* ULTRIX_AUTH */
513 #ifdef LINUX_BIGCRYPT
514 ret = (linux_bigcrypt(password, salt, crypted));
518 return NT_STATUS_WRONG_PASSWORD;
520 #endif /* LINUX_BIGCRYPT */
522 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
525 * Some systems have bigcrypt in the C library but might not
526 * actually use it for the password hashes (HPUX 10.20) is
527 * a noteable example. So we try bigcrypt first, followed
531 if (strcmp(bigcrypt(password, salt), crypted) == 0)
534 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
538 return NT_STATUS_WRONG_PASSWORD;
540 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
543 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
547 return NT_STATUS_WRONG_PASSWORD;
549 #endif /* HAVE_BIGCRYPT */
552 DEBUG(1, ("Warning - no crypt available\n"));
553 return NT_STATUS_LOGON_FAILURE;
554 #else /* HAVE_CRYPT */
555 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
559 return NT_STATUS_WRONG_PASSWORD;
561 #endif /* HAVE_CRYPT */
562 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
565 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
574 int level = lp_passwordlevel();
576 username = talloc_strdup(ctx, user_info->mapped.account_name);
577 password = talloc_strdup(ctx, user_info->password.plaintext);
579 nt_status = talloc_getpwnam(ctx, username, &pws);
580 if (!NT_STATUS_IS_OK(nt_status)) {
584 crypted = pws->pw_passwd;
585 salt = pws->pw_passwd;
591 /* many shadow systems require you to be root to get
592 the password, in most cases this should already be
593 the case when this function is called, except
594 perhaps for IPC password changing requests */
596 spass = getspnam(pws->pw_name);
597 if (spass && spass->sp_pwdp) {
598 crypted = talloc_strdup(ctx, spass->sp_pwdp);
599 NT_STATUS_HAVE_NO_MEMORY(crypted);
600 salt = talloc_strdup(ctx, spass->sp_pwdp);
601 NT_STATUS_HAVE_NO_MEMORY(salt);
604 #elif defined(IA_UINFO)
607 /* Need to get password with SVR4.2's ia_ functions
608 instead of get{sp,pw}ent functions. Required by
609 UnixWare 2.x, tested on version
610 2.1. (tangent@cyberport.com) */
612 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
613 ia_get_logpwd(uinfo, &ia_password);
614 crypted = talloc_strdup(ctx, ia_password);
615 NT_STATUS_HAVE_NO_MEMORY(crypted);
620 #ifdef HAVE_GETPRPWNAM
622 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
623 if (pr_pw && pr_pw->ufld.fd_encrypt) {
624 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
625 NT_STATUS_HAVE_NO_MEMORY(crypted);
630 #ifdef HAVE_GETPWANAM
632 struct passwd_adjunct *pwret;
633 pwret = getpwanam(s);
634 if (pwret && pwret->pwa_passwd) {
635 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
636 NT_STATUS_HAVE_NO_MEMORY(crypted);
643 struct pr_passwd *mypasswd;
644 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
645 mypasswd = getprpwnam(username);
647 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
648 NT_STATUS_HAVE_NO_MEMORY(username);
649 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
650 NT_STATUS_HAVE_NO_MEMORY(crypted);
652 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
659 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
661 crypted = talloc_strdup(ctx, ap->a_password);
663 NT_STATUS_HAVE_NO_MEMORY(crypted);
668 #if defined(HAVE_TRUNCATED_SALT)
669 /* crypt on some platforms (HPUX in particular)
670 won't work with more than 2 salt characters. */
674 if (crypted[0] == '\0') {
675 if (!lp_null_passwords()) {
676 DEBUG(2, ("Disallowing %s with null password\n", username));
677 return NT_STATUS_LOGON_FAILURE;
679 if (password == NULL) {
680 DEBUG(3, ("Allowing access to %s with null password\n", username));
685 /* try it as it came to us */
686 nt_status = password_check(username, password, crypted, salt);
687 if NT_STATUS_IS_OK(nt_status) {
690 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
691 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
695 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
699 /* if the password was given to us with mixed case then we don't
700 * need to proceed as we know it hasn't been case modified by the
702 if (strhasupper(password) && strhaslower(password)) {
706 /* make a copy of it */
707 pwcopy = talloc_strdup(ctx, password);
709 return NT_STATUS_NO_MEMORY;
711 /* try all lowercase if it's currently all uppercase */
712 if (strhasupper(pwcopy)) {
714 nt_status = password_check(username, pwcopy, crypted, salt);
715 if NT_STATUS_IS_OK(nt_status) {
722 return NT_STATUS_WRONG_PASSWORD;
725 /* last chance - all combinations of up to level chars upper! */
729 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
733 return NT_STATUS_WRONG_PASSWORD;
738 /** Check a plaintext username/password
742 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
744 const struct auth_usersupplied_info *user_info,
745 struct auth_serversupplied_info **server_info)
747 TALLOC_CTX *check_ctx;
750 if (! user_info->mapped.account_name || ! *user_info->mapped.account_name) {
752 return NT_STATUS_NOT_IMPLEMENTED;
755 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
756 return NT_STATUS_INVALID_PARAMETER;
759 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
760 if (check_ctx == NULL) {
761 return NT_STATUS_NO_MEMORY;
764 nt_status = check_unix_password(check_ctx, user_info);
765 if ( ! NT_STATUS_IS_OK(nt_status)) {
766 talloc_free(check_ctx);
770 nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
771 if ( ! NT_STATUS_IS_OK(nt_status)) {
772 talloc_free(check_ctx);
776 talloc_free(check_ctx);
780 static const struct auth_operations unix_ops = {
782 .get_challenge = auth_get_challenge_not_implemented,
783 .check_password = authunix_check_password
786 NTSTATUS auth_unix_init(void)
790 ret = auth_register(&unix_ops);
791 if (!NT_STATUS_IS_OK(ret)) {
792 DEBUG(0,("Failed to register unix auth backend!\n"));