/* Unix SMB/CIFS implementation. Authentication utility functions Copyright (C) Simo Sorce 2010 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "auth.h" #include "librpc/gen_ndr/krb5pac.h" #include "nsswitch/libwbclient/wbclient.h" #include "passdb.h" #include "lib/param/loadparm.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH #ifdef HAVE_KRB5 NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, const char *cli_name, const char *princ_name, bool *is_mapped, bool *mapped_to_guest, char **ntuser, char **ntdomain, char **username, struct passwd **_pw) { NTSTATUS status; const char *domain = NULL; const char *realm = NULL; char *user = NULL; char *p; char *fuser = NULL; char *unixuser = NULL; struct passwd *pw = NULL; bool may_retry = false; DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name)); p = strchr_m(princ_name, '@'); if (!p) { DEBUG(3, ("[%s] Doesn't look like a valid principal\n", princ_name)); return NT_STATUS_LOGON_FAILURE; } user = talloc_strndup(mem_ctx, princ_name, p - princ_name); if (!user) { return NT_STATUS_NO_MEMORY; } realm = p + 1; if (!strequal(realm, lp_realm())) { DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); if (!lp_allow_trusted_domains()) { return NT_STATUS_LOGON_FAILURE; } domain = realm; } else { domain = lp_workgroup(); may_retry = true; } fuser = talloc_asprintf(mem_ctx, "%s%c%s", domain, *lp_winbind_separator(), user); if (!fuser) { return NT_STATUS_NO_MEMORY; } *is_mapped = map_username(mem_ctx, fuser, &fuser); if (!fuser) { return NT_STATUS_NO_MEMORY; } *mapped_to_guest = false; pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); if (may_retry && pw == NULL && !*is_mapped) { fuser = talloc_strdup(mem_ctx, user); if (!fuser) { return NT_STATUS_NO_MEMORY; } pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); } if (pw) { if (!unixuser) { return NT_STATUS_NO_MEMORY; } /* if a real user check pam account restrictions */ /* only really performed if "obey pam restriction" is true */ /* do this before an eventual mapping to guest occurs */ status = smb_pam_accountcheck(pw->pw_name, cli_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("PAM account restrictions prevent user " "[%s] login\n", unixuser)); return status; } } if (!pw) { /* this was originally the behavior of Samba 2.2, if a user did not have a local uid but has been authenticated, then map them to a guest account */ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) { *mapped_to_guest = true; fuser = talloc_strdup(mem_ctx, lp_guest_account()); if (!fuser) { return NT_STATUS_NO_MEMORY; } pw = smb_getpwnam(mem_ctx, fuser, &unixuser, false); } /* extra sanity check that the guest account is valid */ if (!pw) { DBG_NOTICE("Username %s is invalid on this system\n", fuser); return NT_STATUS_LOGON_FAILURE; } } if (!unixuser) { return NT_STATUS_NO_MEMORY; } *username = talloc_strdup(mem_ctx, unixuser); if (!*username) { return NT_STATUS_NO_MEMORY; } *ntuser = user; *ntdomain = talloc_strdup(mem_ctx, domain); if (*ntdomain == NULL) { return NT_STATUS_NO_MEMORY; } *_pw = pw; return NT_STATUS_OK; } NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, char *ntuser, char *ntdomain, char *username, struct passwd *pw, bool mapped_to_guest, bool username_was_mapped, struct auth_session_info **session_info) { NTSTATUS status; struct auth_serversupplied_info *server_info; if (mapped_to_guest) { status = make_server_info_guest(mem_ctx, &server_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("make_server_info_guest failed: %s!\n", nt_errstr(status))); return status; } } else { /* * We didn't get a PAC, we have to make up the user * ourselves. Try to ask the pdb backend to provide * SID consistency with ntlmssp session setup */ struct samu *sampass; sampass = samu_new(talloc_tos()); if (sampass == NULL) { return NT_STATUS_NO_MEMORY; } if (pdb_getsampwnam(sampass, username)) { DEBUG(10, ("found user %s in passdb, calling " "make_server_info_sam\n", username)); status = make_server_info_sam(mem_ctx, sampass, &server_info); } else { /* * User not in passdb, make it up artificially */ DEBUG(10, ("didn't find user %s in passdb, calling " "make_server_info_pw\n", username)); status = make_server_info_pw(mem_ctx, username, pw, &server_info); } TALLOC_FREE(sampass); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n", nt_errstr(status))); return status; } /* make_server_info_pw does not set the domain. Without this * we end up with the local netbios name in substitutions for * %D. */ if (server_info->info3 != NULL) { server_info->info3->base.logon_domain.string = talloc_strdup(server_info->info3, ntdomain); } } server_info->nss_token |= username_was_mapped; status = create_local_token(mem_ctx, server_info, NULL, ntuser, session_info); talloc_free(server_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("failed to create local token: %s\n", nt_errstr(status))); return status; } return NT_STATUS_OK; } #else /* HAVE_KRB5 */ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, const char *cli_name, const char *princ_name, bool *is_mapped, bool *mapped_to_guest, char **ntuser, char **ntdomain, char **username, struct passwd **_pw) { return NT_STATUS_NOT_IMPLEMENTED; } NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx, char *ntuser, char *ntdomain, char *username, struct passwd *pw, bool mapped_to_guest, bool username_was_mapped, struct auth_session_info **session_info) { return NT_STATUS_NOT_IMPLEMENTED; } #endif /* HAVE_KRB5 */