krb5_auth.c revision 7c5cd2e7711621af9163a41393e88896a91ac33b
/*
SSSD
Kerberos 5 Backend Module
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2009-2010 Red Hat
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 <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <pwd.h>
#include <security/pam_modules.h>
#include "util/find_uid.h"
#include "util/auth_utils.h"
#include "util/child_common.h"
#include "providers/krb5/krb5_auth.h"
#include "providers/krb5/krb5_utils.h"
#include "providers/krb5/krb5_ccache.h"
static errno_t
{
*active = false;
*valid = false;
switch (ret) {
case ERR_NOT_FOUND:
case ENOENT:
"Saved ccache %s doesn't exist.\n", old_ccache);
return ENOENT;
case EINVAL:
/* cache found but no tgt or expired */
case EOK:
*valid = true;
break;
default:
"Cannot check if saved ccache %s is valid\n",
return ret;
}
return ret;
}
return EOK;
}
struct sss_domain_info *domain,
const char *name,
const char *ccname,
int mod_op)
{
struct sysdb_attrs *attrs;
int ret;
bool in_transaction = false;
return EINVAL;
}
return EINVAL;
}
if (!tmpctx) {
return ENOMEM;
}
if (!attrs) {
goto done;
}
goto done;
}
goto done;
}
in_transaction = true;
goto done;
}
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
}
}
return ret;
}
struct sss_domain_info *domain,
const char *name,
const char *ccname)
{
}
struct sss_domain_info *domain,
const char *name,
const char *ccname)
{
}
{
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
struct krb5_ctx);
break;
case SSS_PAM_ACCT_MGMT:
struct krb5_ctx);
break;
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
struct krb5_ctx);
break;
default:
return NULL;
}
}
static int krb5_cleanup(void *ptr)
{
return EOK;
}
{
return ENOMEM;
}
kr->is_offline = false;
kr->active_ccache = true;
kr->run_as_user = true;
return EOK;
}
struct sss_domain_info *domain,
struct confdb_ctx *cdb,
int *pam_status, int *dp_err)
{
return;
}
return;
}
/* This error is not fatal */
"add_user_to_delayed_online_authentication failed.\n");
}
*dp_err = DP_ERR_OFFLINE;
}
{
const char *ccname_template;
if (!kr->is_offline) {
}
/* The ccache file should be (re)created if one of the following conditions
* is true:
* - it doesn't exist (kr->ccname == NULL)
* - the backend is online and the current ccache file is not used, i.e
* the related user is currently not logged in and it is not a renewal
* request
* (!kr->is_offline && !kr->active_ccache && kr->pd->cmd != SSS_CMD_RENEW)
* - the backend is offline and the current cache file not used and
* it does not contain a valid tgt
* (kr->is_offline && !kr->active_ccache && !kr->valid_tgt)
*/
true,
return ENOMEM;
}
return ret;
}
}
return EOK;
}
{
case SSS_CMD_RENEW:
/* The authtok is set to the credential cache
* during renewal. We don't want to save this
* as the cached password.
*/
break;
case SSS_PAM_AUTHENTICATE:
case SSS_PAM_CHAUTHTOK_PRELIM:
break;
case SSS_PAM_CHAUTHTOK:
break;
default:
}
/* password caching failures are not fatal errors */
return;
}
"password not available, offline auth may not work.\n");
/* password caching failures are not fatal errors */
}
return;
}
if (ret) {
"Failed to cache password, offline auth may not work."
/* password caching failures are not fatal errors */
}
}
/* krb5_auth request */
struct krb5_auth_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
struct krb5child_req *kr;
bool search_kpasswd;
int pam_status;
int dp_err;
};
struct tevent_context *ev,
{
const char **attrs;
struct krb5_auth_state *state;
struct ldb_result *res;
const char *ccache_file = NULL;
const char *realm;
struct tevent_req *req;
struct tevent_req *subreq;
int authtok_type;
int ret;
return NULL;
}
goto done;
}
case SSS_PAM_AUTHENTICATE:
case SSS_PAM_CHAUTHTOK:
if (authtok_type != SSS_AUTHTOK_TYPE_PASSWORD) {
/* handle empty password gracefully */
if (authtok_type == SSS_AUTHTOK_TYPE_EMPTY) {
"Illegal zero-length authtok for user [%s]\n",
goto done;
}
"Wrong authtok type for user [%s]. " \
goto done;
}
break;
case SSS_PAM_CHAUTHTOK_PRELIM:
"Password reset by root is not supported.\n");
goto done;
}
break;
case SSS_CMD_RENEW:
if (authtok_type != SSS_AUTHTOK_TYPE_CCFILE) {
"Wrong authtok type for user [%s]. " \
goto done;
}
break;
default:
goto done;
}
if (be_is_offline(be_ctx) &&
"Password changes and ticket renewal are not possible "
"while offline.\n");
goto done;
}
goto done;
}
goto done;
}
&res);
if (ret) {
goto done;
}
goto done;
}
case 0:
goto done;
break;
case 1:
goto done;
}
if (ret != 0) {
goto done;
}
NULL);
}
goto done;
}
goto done;
}
NULL);
if (ccache_file != NULL) {
&kr->active_ccache,
"Ignoring ccache attribute [%s], because it doesn't"
"exist.\n", ccache_file);
ccache_file = NULL;
"check_if_ccache_file_is_used failed.\n");
ccache_file = NULL;
}
} else {
kr->active_ccache = false;
}
"Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
if (ccache_file != NULL) {
goto done;
}
} else {
}
break;
default:
goto done;
break;
}
state->search_kpasswd = false;
if (!subreq) {
goto done;
}
return req;
done:
} else {
}
return req;
}
{
char *msg;
int ret;
if (!state->search_kpasswd) {
} else {
}
if (state->search_kpasswd) {
/* all kpasswd servers have been tried and none was found good,
* but the kdc seems ok. Password changes are not possible but
* authentication is. We return an PAM error here, but do not
* mark the backend offline. */
goto done;
}
} else {
/* all servers have been tried and none
* was found good, setting offline,
* but we still have to call the child to setup
* the ccache file if we are performing auth */
kr->is_offline = true;
"No KDC suitable for password change is available\n");
goto done;
}
} else {
state->search_kpasswd = true;
goto done;
}
return;
}
}
}
if (ret) {
goto done;
}
if (kr->is_offline) {
"ccache file is already in use.\n");
} else {
}
}
} else {
}
goto done;
}
}
/* We need to keep the root privileges to read the keytab file if
* validation or FAST is enabled, otherwise we can drop them and run
* krb5_child with user privileges.
* If we are offline we want to create an empty ccache file. In this
* case we can drop the privileges, too. */
(!kr->is_offline)) {
kr->run_as_user = false;
} else {
kr->run_as_user = true;
}
goto done;
}
return;
done:
} else {
}
}
{
int ret;
struct krb5_child_response *res;
struct fo_server *search_srv;
char *renew_interval_str;
bool use_enterprise_principal;
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
state->search_kpasswd = false;
break;
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
state->search_kpasswd = true;
break;
} else {
state->search_kpasswd = false;
break;
}
default:
goto done;
}
search_srv == NULL ? true : false);
goto done;
}
return;
goto done;
}
/* EOK */
&res);
if (ret) {
goto done;
}
goto done;
}
}
/* Check if the cases of our upn are correct and update it if needed.
* Fail if the upn differs by more than just the case for non-enterprise
* principals. */
use_enterprise_principal == true) {
goto done;
}
"check_if_cached_upn_needs_update failed.\n");
goto done;
}
} else {
"returned UPN [%s] differ by more " \
"than just the case.\n",
goto done;
}
}
/* If the child request failed, but did not return an offline error code,
* return with the status */
switch (res->msg_status) {
case ERR_OK:
/* If the child request was successful and we run the first pass of the
* change password request just return success. */
goto done;
}
break;
case ERR_NETWORK_IO:
/* if using a dedicated kpasswd server for a chpass operation... */
/* ..try to resolve next kpasswd server */
state->search_kpasswd = true;
goto done;
}
return;
/* failed to use the KDC... */
/* ..try to resolve next KDC */
state->search_kpasswd = false;
goto done;
}
return;
}
break;
case ERR_CREDS_EXPIRED:
/* If the password is expired we can safely remove the ccache from the
* cache and disk if it is not actively used anymore. This will allow
* to create a new random ccache if sshd with privilege separation is
* used. */
"Failed to remove old ccache file [%s], "
}
}
}
}
goto done;
case ERR_CREDS_INVALID:
goto done;
case ERR_ACCOUNT_EXPIRED:
goto done;
case ERR_NO_CREDS:
goto done;
case ERR_AUTH_FAILED:
goto done;
case ERR_CHPASS_FAILED:
goto done;
default:
goto done;
}
/* found a dedicated kpasswd server for a chpass operation */
/* found a KDC */
}
/* Now only a successful authentication or password change is left.
*
* We expect that one of the messages in the received buffer contains
* the name of the credential cache file. */
goto done;
}
if (ret) {
"Password change succeeded but currently "
"post-chpass kinit is not implemented\n");
(const uint8_t *) &user_info_type);
/* Not fatal */
}
} else {
goto done;
}
}
if (kr->old_ccname) {
"Failed to remove old ccache file [%s], "
}
}
if (ret) {
goto done;
}
if (renew_interval_str != NULL) {
"Reading krb5_renew_interval failed.\n");
renew_interval_delta = 0;
}
}
"automatic renewal not possible.\n");
}
}
if (kr->is_offline) {
} else {
"Backend is marked offline, retry later!\n");
}
goto done;
}
}
"pam_add_response failed: %d (%s).\n",
goto done;
}
}
done:
} else {
}
}
{
return EOK;
}
{
struct tevent_req *req;
int dp_err = DP_ERR_FATAL;
int ret;
goto done;
}
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
"Request successfully added to wait queue "
return;
} else {
"Failed to add request to wait queue of user [%s], "
}
goto done;
}
break;
case SSS_PAM_ACCT_MGMT:
goto done;
}
break;
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
goto done;
break;
default:
goto done;
}
return;
done:
}
{
int ret;
int pam_status;
int dp_err;
if (ret) {
} else {
}
} else {
}
}
{
int ret;
bool access_allowed;
goto done;
}
done:
}