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" /* needed by some systems for struct passwd */
26 #include "lib/socket/socket.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,
34 struct auth_serversupplied_info **_server_info)
36 struct auth_serversupplied_info *server_info;
39 /* This is a real, real hack */
40 if (pwd->pw_uid == 0) {
41 status = auth_system_server_info(mem_ctx, &server_info);
42 if (!NT_STATUS_IS_OK(status)) {
46 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
47 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
49 server_info->domain_name = talloc_strdup(server_info, "unix");
50 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
52 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
53 NT_STATUS_HAVE_NO_MEMORY(server_info);
55 server_info->authenticated = True;
57 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
58 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
60 server_info->domain_name = talloc_strdup(server_info, "unix");
61 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
63 /* This isn't in any way correct.. */
64 server_info->account_sid = NULL;
65 server_info->primary_group_sid = NULL;
66 server_info->n_domain_groups = 0;
67 server_info->domain_groups = NULL;
69 server_info->user_session_key = data_blob(NULL,0);
70 server_info->lm_session_key = data_blob(NULL,0);
72 server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
73 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
74 server_info->logon_script = talloc_strdup(server_info, "");
75 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
76 server_info->profile_path = talloc_strdup(server_info, "");
77 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
78 server_info->home_directory = talloc_strdup(server_info, "");
79 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
80 server_info->home_drive = talloc_strdup(server_info, "");
81 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
83 server_info->last_logon = 0;
84 server_info->last_logoff = 0;
85 server_info->acct_expiry = 0;
86 server_info->last_password_change = 0;
87 server_info->allow_password_change = 0;
88 server_info->force_password_change = 0;
89 server_info->logon_count = 0;
90 server_info->bad_password_count = 0;
91 server_info->acct_flags = 0;
93 *_server_info = server_info;
98 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
105 ret = talloc(ctx, struct passwd);
106 NT_STATUS_HAVE_NO_MEMORY(ret);
108 from = getpwnam(username);
110 return NT_STATUS_NO_SUCH_USER;
113 ret->pw_name = talloc_strdup(ctx, from->pw_name);
114 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
116 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
117 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
119 ret->pw_uid = from->pw_uid;
120 ret->pw_gid = from->pw_gid;
121 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
122 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
124 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
125 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
127 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
128 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
136 #ifdef HAVE_SECURITY_PAM_APPL_H
137 #include <security/pam_appl.h>
139 struct smb_pam_user_info {
140 const char *account_name;
141 const char *plaintext_password;
144 #define COPY_STRING(s) (s) ? strdup(s) : NULL
147 * Check user password
148 * Currently it uses PAM only and fails on systems without PAM
149 * Samba3 code located in pass_check.c is to ugly to be used directly it will
150 * need major rework that's why pass_check.c is still there.
153 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
154 struct pam_response **reply, void *appdata_ptr)
156 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
165 * Apparantly HPUX has a buggy PAM that doesn't support the
166 * data pointer. Fail if this is the case. JRA.
175 * PAM frees memory in reply messages by itself
176 * so use malloc instead of talloc here.
178 *reply = malloc_array_p(struct pam_response, num_msg);
179 if (*reply == NULL) {
183 for (num = 0; num < num_msg; num++) {
184 switch (msg[num]->msg_style) {
185 case PAM_PROMPT_ECHO_ON:
186 (*reply)[num].resp_retcode = PAM_SUCCESS;
187 (*reply)[num].resp = COPY_STRING(info->account_name);
190 case PAM_PROMPT_ECHO_OFF:
191 (*reply)[num].resp_retcode = PAM_SUCCESS;
192 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
196 (*reply)[num].resp_retcode = PAM_SUCCESS;
197 (*reply)[num].resp = NULL;
198 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
201 (*reply)[num].resp_retcode = PAM_SUCCESS;
202 (*reply)[num].resp = NULL;
203 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
209 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
218 * Start PAM authentication for specified account
221 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
225 if (account_name == NULL || remote_host == NULL) {
226 return NT_STATUS_INVALID_PARAMETER;
229 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
231 pam_error = pam_start("samba", account_name, pconv, pamh);
232 if (pam_error != PAM_SUCCESS) {
233 /* no vaild pamh here, can we reliably call pam_strerror ? */
234 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
235 return NT_STATUS_UNSUCCESSFUL;
239 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
240 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
241 if (pam_error != PAM_SUCCESS) {
244 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
245 pam_strerror(*pamh, pam_error)));
246 nt_status = pam_to_nt_status(pam_error);
248 pam_error = pam_end(*pamh, 0);
249 if (pam_error != PAM_SUCCESS) {
250 /* no vaild pamh here, can we reliably call pam_strerror ? */
251 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
253 return pam_to_nt_status(pam_error);
259 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
260 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
261 if (pam_error != PAM_SUCCESS) {
264 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
265 pam_strerror(*pamh, pam_error)));
266 nt_status = pam_to_nt_status(pam_error);
268 pam_error = pam_end(*pamh, 0);
269 if (pam_error != PAM_SUCCESS) {
270 /* no vaild pamh here, can we reliably call pam_strerror ? */
271 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
273 return pam_to_nt_status(pam_error);
278 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
283 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
288 pam_error = pam_end(pamh, 0);
289 if (pam_error != PAM_SUCCESS) {
290 /* no vaild pamh here, can we reliably call pam_strerror ? */
291 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
293 return pam_to_nt_status(pam_error);
298 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
299 return NT_STATUS_UNSUCCESSFUL;
303 * PAM Authentication Handler
305 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
310 * To enable debugging set in /etc/pam.d/samba:
311 * auth required /lib/security/pam_pwdb.so nullok shadow audit
314 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
316 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
319 DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
321 case PAM_CRED_INSUFFICIENT:
322 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
324 case PAM_AUTHINFO_UNAVAIL:
325 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
327 case PAM_USER_UNKNOWN:
328 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
331 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
334 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
337 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
340 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
344 return pam_to_nt_status(pam_error);
348 * PAM Account Handler
350 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
354 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
356 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
357 switch( pam_error ) {
358 case PAM_AUTHTOK_EXPIRED:
359 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
361 case PAM_ACCT_EXPIRED:
362 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
365 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
367 case PAM_PERM_DENIED:
368 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
370 case PAM_USER_UNKNOWN:
371 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
374 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
377 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
381 return pam_to_nt_status(pam_error);
385 * PAM Credential Setting
388 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
393 * This will allow samba to aquire a kerberos token. And, when
394 * exporting an AFS cell, be able to /write/ to this cell.
397 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
399 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
400 switch( pam_error ) {
401 case PAM_CRED_UNAVAIL:
402 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
404 case PAM_CRED_EXPIRED:
405 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
407 case PAM_USER_UNKNOWN:
408 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
411 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
414 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
417 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
421 return pam_to_nt_status(pam_error);
424 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info, struct passwd **pws)
426 struct smb_pam_user_info *info;
427 struct pam_conv *pamconv;
431 info = talloc(ctx, struct smb_pam_user_info);
433 return NT_STATUS_NO_MEMORY;
436 info->account_name = user_info->mapped.account_name;
437 info->plaintext_password = user_info->password.plaintext;
439 pamconv = talloc(ctx, struct pam_conv);
440 if (pamconv == NULL) {
441 return NT_STATUS_NO_MEMORY;
444 pamconv->conv = smb_pam_conv;
445 pamconv->appdata_ptr = (void *)info;
448 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
449 * if true set up a crack name routine.
452 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
453 if (!NT_STATUS_IS_OK(nt_status)) {
457 nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
458 if (!NT_STATUS_IS_OK(nt_status)) {
463 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
465 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
466 if (!NT_STATUS_IS_OK(nt_status)) {
471 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
472 if (!NT_STATUS_IS_OK(nt_status)) {
480 nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
481 if (!NT_STATUS_IS_OK(nt_status)) {
490 /****************************************************************************
491 core of password checking routine
492 ****************************************************************************/
493 static NTSTATUS password_check(const char *username, const char *password,
494 const char *crypted, const char *salt)
499 if (afs_auth(username, password))
501 #endif /* WITH_AFS */
504 if (dfs_auth(username, password))
506 #endif /* WITH_DFS */
510 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
514 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
515 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
520 return NT_STATUS_WRONG_PASSWORD;
523 #endif /* OSF1_ENH_SEC */
526 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
530 return NT_STATUS_WRONG_PASSWORD;
533 #endif /* ULTRIX_AUTH */
535 #ifdef LINUX_BIGCRYPT
536 ret = (linux_bigcrypt(password, salt, crypted));
540 return NT_STATUS_WRONG_PASSWORD;
542 #endif /* LINUX_BIGCRYPT */
544 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
547 * Some systems have bigcrypt in the C library but might not
548 * actually use it for the password hashes (HPUX 10.20) is
549 * a noteable example. So we try bigcrypt first, followed
553 if (strcmp(bigcrypt(password, salt), crypted) == 0)
556 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
560 return NT_STATUS_WRONG_PASSWORD;
562 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
565 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
569 return NT_STATUS_WRONG_PASSWORD;
571 #endif /* HAVE_BIGCRYPT */
574 DEBUG(1, ("Warning - no crypt available\n"));
575 return NT_STATUS_LOGON_FAILURE;
576 #else /* HAVE_CRYPT */
577 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
581 return NT_STATUS_WRONG_PASSWORD;
583 #endif /* HAVE_CRYPT */
584 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
587 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
596 int level = lp_passwordlevel();
600 username = talloc_strdup(ctx, user_info->mapped.account_name);
601 password = talloc_strdup(ctx, user_info->password.plaintext);
603 nt_status = talloc_getpwnam(ctx, username, &pws);
604 if (!NT_STATUS_IS_OK(nt_status)) {
608 crypted = pws->pw_passwd;
609 salt = pws->pw_passwd;
615 /* many shadow systems require you to be root to get
616 the password, in most cases this should already be
617 the case when this function is called, except
618 perhaps for IPC password changing requests */
620 spass = getspnam(pws->pw_name);
621 if (spass && spass->sp_pwdp) {
622 crypted = talloc_strdup(ctx, spass->sp_pwdp);
623 NT_STATUS_HAVE_NO_MEMORY(crypted);
624 salt = talloc_strdup(ctx, spass->sp_pwdp);
625 NT_STATUS_HAVE_NO_MEMORY(salt);
628 #elif defined(IA_UINFO)
631 /* Need to get password with SVR4.2's ia_ functions
632 instead of get{sp,pw}ent functions. Required by
633 UnixWare 2.x, tested on version
634 2.1. (tangent@cyberport.com) */
636 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
637 ia_get_logpwd(uinfo, &ia_password);
638 crypted = talloc_strdup(ctx, ia_password);
639 NT_STATUS_HAVE_NO_MEMORY(crypted);
644 #ifdef HAVE_GETPRPWNAM
646 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
647 if (pr_pw && pr_pw->ufld.fd_encrypt) {
648 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
649 NT_STATUS_HAVE_NO_MEMORY(crypted);
654 #ifdef HAVE_GETPWANAM
656 struct passwd_adjunct *pwret;
657 pwret = getpwanam(s);
658 if (pwret && pwret->pwa_passwd) {
659 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
660 NT_STATUS_HAVE_NO_MEMORY(crypted);
667 struct pr_passwd *mypasswd;
668 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
669 mypasswd = getprpwnam(username);
671 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
672 NT_STATUS_HAVE_NO_MEMORY(username);
673 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
674 NT_STATUS_HAVE_NO_MEMORY(crypted);
676 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
683 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
685 crypted = talloc_strdup(ctx, ap->a_password);
687 NT_STATUS_HAVE_NO_MEMORY(crypted);
692 #if defined(HAVE_TRUNCATED_SALT)
693 /* crypt on some platforms (HPUX in particular)
694 won't work with more than 2 salt characters. */
698 if (crypted[0] == '\0') {
699 if (!lp_null_passwords()) {
700 DEBUG(2, ("Disallowing %s with null password\n", username));
701 return NT_STATUS_LOGON_FAILURE;
703 if (password == NULL) {
704 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)) {
716 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
717 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
721 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
725 /* if the password was given to us with mixed case then we don't
726 * need to proceed as we know it hasn't been case modified by the
728 if (strhasupper(password) && strhaslower(password)) {
732 /* make a copy of it */
733 pwcopy = talloc_strdup(ctx, password);
735 return NT_STATUS_NO_MEMORY;
737 /* try all lowercase if it's currently all uppercase */
738 if (strhasupper(pwcopy)) {
740 nt_status = password_check(username, pwcopy, crypted, salt);
741 if NT_STATUS_IS_OK(nt_status) {
749 return NT_STATUS_WRONG_PASSWORD;
752 /* last chance - all combinations of up to level chars upper! */
756 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
761 return NT_STATUS_WRONG_PASSWORD;
766 /** Check a plaintext username/password
770 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
772 const struct auth_usersupplied_info *user_info,
773 struct auth_serversupplied_info **server_info)
775 TALLOC_CTX *check_ctx;
779 if (! user_info->mapped.account_name || ! *user_info->mapped.account_name) {
781 return NT_STATUS_NOT_IMPLEMENTED;
784 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
785 return NT_STATUS_INVALID_PARAMETER;
788 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
789 if (check_ctx == NULL) {
790 return NT_STATUS_NO_MEMORY;
793 nt_status = check_unix_password(check_ctx, user_info, &pwd);
794 if ( ! NT_STATUS_IS_OK(nt_status)) {
795 talloc_free(check_ctx);
799 nt_status = authunix_make_server_info(mem_ctx, user_info, pwd, server_info);
800 if ( ! NT_STATUS_IS_OK(nt_status)) {
801 talloc_free(check_ctx);
805 talloc_free(check_ctx);
809 static const struct auth_operations unix_ops = {
811 .get_challenge = auth_get_challenge_not_implemented,
812 .check_password = authunix_check_password
815 NTSTATUS auth_unix_init(void)
819 ret = auth_register(&unix_ops);
820 if (!NT_STATUS_IS_OK(ret)) {
821 DEBUG(0,("Failed to register unix auth backend!\n"));