krb5_child.c revision d2ea839a907ba6ee1fe44027d67b11b02593fc99
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht Kerberos 5 Backend Module -- tgt_req and changepw child
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht Sumit Bose <sbose@redhat.com>
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht Copyright (C) 2009-2010 Red Hat
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht This program is free software; you can redistribute it and/or modify
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht it under the terms of the GNU General Public License as published by
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht the Free Software Foundation; either version 3 of the License, or
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht (at your option) any later version.
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht This program is distributed in the hope that it will be useful,
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht but WITHOUT ANY WARRANTY; without even the implied warranty of
94968509d2764786208bd34b59a93c7cbe3aa6dbSimon Ulbricht MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht GNU General Public License for more details.
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht You should have received a copy of the GNU General Public License
4bf72807172000becf65e11bd225efc1dfd99713Simon Ulbricht along with this program. If not, see <http://www.gnu.org/licenses/>.
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht#define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw"
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht#define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbrichtstatic krb5_error_code set_lifetime_options(krb5_get_init_creds_opt *options)
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME);
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht DEBUG(SSSDBG_CONF_SETTINGS, "Cannot read [%s] from environment.\n",
846ef0914b29a4806ca0444c116fd3cf267c4fb7Christian Maeder /* Unset option flag to make sure defaults from krb5.conf are used. */
e90b8ee3fac5c932d83af2061579c6b57d528885Christian Maeder options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE);
fa957341e01730705317221b5aeef232974dbedfSimon Ulbricht kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
fa957341e01730705317221b5aeef232974dbedfSimon Ulbricht "krb5_string_to_deltat failed for [%s].\n",
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht DEBUG(SSSDBG_CONF_SETTINGS, "%s is set to [%s]\n",
8600e22385bce13c5d1048f7b955f9394a5d94d6Simon Ulbricht krb5_get_init_creds_opt_set_renew_life(options, lifetime);
5b93337fb97e848522fcc277e384f694595bc42cSimon Ulbricht DEBUG(SSSDBG_CONF_SETTINGS, "Cannot read [%s] from environment.\n",
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht /* Unset option flag to make sure defaults from krb5.conf are used. */
fa957341e01730705317221b5aeef232974dbedfSimon Ulbricht options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_TKT_LIFE);
403c7e517cea70c01c7dd15695867fe4f8820ab4Simon Ulbricht kerr = krb5_string_to_deltat(lifetime_str, &lifetime);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht "krb5_string_to_deltat failed for [%s].\n",
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht "%s is set to [%s]\n", SSSD_KRB5_LIFETIME, lifetime_str);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbrichtstatic void set_canonicalize_option(krb5_get_init_creds_opt *opts)
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht DEBUG(SSSDBG_CONF_SETTINGS, "%s is set to [%s]\n",
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set");
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize);
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbrichtstatic void set_changepw_options(krb5_get_init_creds_opt *options)
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht sss_krb5_get_init_creds_opt_set_canonicalize(options, 0);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht krb5_get_init_creds_opt_set_forwardable(options, 0);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht krb5_get_init_creds_opt_set_proxiable(options, 0);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht krb5_get_init_creds_opt_set_renew_life(options, 0);
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht krb5_get_init_creds_opt_set_tkt_life(options, 5*60);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbrichtstatic void revert_changepw_options(krb5_get_init_creds_opt *options)
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht /* Currently we do not set forwardable and proxiable explicitly, the flags
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht * must be removed so that libkrb5 can take the defaults from krb5.conf */
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_FORWARDABLE);
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_PROXIABLE);
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n"));
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbrichtstatic errno_t sss_send_pac(krb5_authdata **pac_authdata)
4d1df661384f74cd15d2ceba8a9a3c4760e9ddfbSimon Ulbricht ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht if (ret != NSS_STATUS_SUCCESS || errnop != 0) {
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht DEBUG(SSSDBG_OP_FAILURE, "sss_pac_make_request failed [%d][%d].\n",
5917663ca76c8f8b60b767f7fb959f1d1609576bSimon Ulbrichtstatic void sss_krb5_expire_callback_func(krb5_context context, void *data,
96a17035df49356b70d7ac14bd9f4d52a5f0308dSimon Ulbricht struct krb5_req *kr = talloc_get_type(data, struct krb5_req);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht DEBUG(SSSDBG_CRIT_FAILURE, "Time to expire out of range.\n");
55be4caff6a01e4c32ec47ee27fe00b67dfd3db5Simon Ulbricht DEBUG(SSSDBG_TRACE_INTERNAL, "exp_time: [%ld]\n", exp_time);
55be4caff6a01e4c32ec47ee27fe00b67dfd3db5Simon Ulbricht DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
5b93337fb97e848522fcc277e384f694595bc42cSimon Ulbricht ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),
55be4caff6a01e4c32ec47ee27fe00b67dfd3db5Simon Ulbricht DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
55be4caff6a01e4c32ec47ee27fe00b67dfd3db5Simon Ulbricht#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_RESPONDER
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * TODO: These features generally would requires a significant refactoring
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * of SSSD and MIT krb5 doesn't support them anyway. They are listed here
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * simply as a reminder of things that might become future feature potential.
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * 1. tokeninfo selection
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * 2. challenge
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * 3. discreet token/pin prompting
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * 4. interactive otp format correction
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbrichttypedef int (*checker)(int c);
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbrichtstatic inline checker pick_checker(int format)
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbrichtstatic krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx,
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_NEXTOTP) {
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht /* This is a non-sensical value. */
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN) {
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht /* ASSUMPTION: authtok has one of the following formats:
fcc4b0f2dadf063ebb8022737cb6e40fb9c4baa8Simon Ulbricht * 1. TokenValue
9458e270eb4d18c8e76fdaa569023931ca7ca8dfSimon Ulbricht * 2. PIN+TokenValue
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht talloc_set_destructor(token, token_pin_destructor);
4d1df661384f74cd15d2ceba8a9a3c4760e9ddfbSimon Ulbricht if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_PIN) {
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht /* If the server desires a separate pin, we will split it.
5917663ca76c8f8b60b767f7fb959f1d1609576bSimon Ulbricht * ASSUMPTION: Format of authtok is PIN+TokenValue. */
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht if (ti->flags & KRB5_RESPONDER_OTP_FLAGS_SEPARATE_PIN) {
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht /* Copy the PIN from the front of the value. */
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht pin = talloc_strndup(NULL, pwd, len - ti->length);
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht talloc_set_destructor(pin, token_pin_destructor);
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht /* Remove the PIN from the front of the token value. */
e4d1479434761dc3eb8d17b6c75de4eb24866f0bSimon Ulbricht memmove(token, token + len - ti->length, ti->length + 1);
67c57fe89afed0947d5ff8fc8b04c4ace0b9595eSimon Ulbricht talloc_set_destructor(pin, token_pin_destructor);
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht /* If check is set, we need to verify the contents of the token. */
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht for (i = 0; check != NULL && token[i] != '\0'; i++) {
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbrichtstatic krb5_error_code answer_otp(krb5_context ctx,
fe6a19b07759bc4190e88dda76a211d86bf32062Simon Ulbricht ret = krb5_responder_otp_get_challenge(ctx, rctx, &chl);
fa957341e01730705317221b5aeef232974dbedfSimon Ulbricht /* Either an error, or nothing to do. */
8fa27254f463e2c958a10dc513450b992f80137bSimon Ulbricht if (chl->tokeninfo == NULL || chl->tokeninfo[0] == NULL) {
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht /* No tokeninfos? Absurd! */
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht /* Validate our assumptions about the contents of authtok. */
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht ret = sss_authtok_get_password(kr->pd->authtok, &pwd, &len);
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht /* Find the first supported tokeninfo which matches our authtoken. */
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht for (i = 0; chl->tokeninfo[i] != NULL; i++) {
7577ca4229962db6f297853d160c2e0214bd2034Simon Ulbricht ret = tokeninfo_matches(kr, chl->tokeninfo[i], pwd, len, &token, &pin);
c3b1c9fa0aa53167405eb9a004137fb5e327fd4fSimon Ulbricht "No tokeninfos found which match our credentials.\n");
846ef0914b29a4806ca0444c116fd3cf267c4fb7Christian Maeder if (chl->tokeninfo[i]->flags & KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN) {
9458e270eb4d18c8e76fdaa569023931ca7ca8dfSimon Ulbricht /* Don't let SSSD cache the OTP authtok since it is single-use. */
goto done;
done:
return ret;
void *data,
return EINVAL;
int ret;
if (num_prompts != 0) {
return KRB5_LIBOS_CANTREADPWD;
return EOK;
return EOK;
return ENOMEM;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
done:
if (kerr != 0) {
return kerr;
int ret;
int fd;
return EOK;
return ret;
return EOK;
const char *type;
#ifdef HAVE_KRB5_CC_COLLECTION
bool switch_to_cc = false;
if (kerr) {
return ERR_INTERNAL;
#ifdef HAVE_KRB5_CC_COLLECTION
switch_to_cc = true;
#ifdef HAVE_KRB5_CC_COLLECTION
if (switch_to_cc) {
done:
if (kcc) {
return kerr;
size_t p = 0;
if (!buf) {
return ENOMEM;
*_len = p;
return EOK;
int ret;
return ERR_INTERNAL;
return ENOMEM;
return ret;
int ret;
return ret;
errno = 0;
return ret;
return EOK;
return EOK;
int ret;
unsigned int upn_len = 0;
goto done;
if (kerr != 0) {
goto done;
goto done;
done:
return ret;
bool realm_entry_found = false;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
goto done;
if (kerr != 0) {
realm_entry_found = true;
if (!realm_entry_found) {
if (kerr != 0) {
goto done;
goto done;
if (kerr != 0) {
goto done;
if (kerr == 0) {
goto done;
if (kerr != 0) {
kerr = 0;
goto done;
if (kerr != 0) {
kerr = 0;
done:
return kerr;
char *ccname)
&options);
if (kerr != 0) {
return kerr;
if (kerr != 0) {
goto done;
kerr = 0;
done:
return kerr;
const char *password)
const char *realm_name;
int realm_length;
char *cc_name;
kr);
if (kerr != 0) {
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
goto done;
if (kerr != 0) {
kerr = 0;
done:
return kerr;
if (kerr != 0) {
switch (kerr) {
return ERR_OK;
case KRB5_LIBOS_CANTREADPWD:
return ERR_NO_CREDS;
case KRB5KRB_AP_ERR_SKEW:
case KRB5_KDC_UNREACH:
case KRB5_REALM_CANT_RESOLVE:
return ERR_NETWORK_IO;
return ERR_ACCOUNT_EXPIRED;
case KRB5KDC_ERR_KEY_EXP:
return ERR_CREDS_EXPIRED;
return ERR_AUTH_FAILED;
case KRB5_PROG_ETYPE_NOSUPP:
case KRB5_PREAUTH_FAILED:
return ERR_CREDS_INVALID;
return ERR_INTERNAL;
int ret;
const char *realm_name;
int realm_length;
return ERR_NO_CREDS;
if (!prelim) {
if (kerr != 0) {
msg);
return kerr;
if (prelim) {
return EOK;
return ERR_NO_CREDS;
return ERR_NETWORK_IO;
if (kerr != 0) {
return ERR_CHPASS_FAILED;
if (kerr == 0) {
int ret;
switch (ret) {
case EOK:
case EACCES:
return ERR_INVALID_CRED_TYPE;
return ERR_NO_CREDS;
if (kerr == 0) {
goto done;
if (kerr != 0) {
if (kerr == 0) {
done:
return ret;
if (kerr != 0) {
if (access_allowed) {
return EOK;
return ERR_AUTH_DENIED;
const char *ccname;
int ret;
return ERR_INVALID_CRED_TYPE;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
goto done;
if (kerr != 0) {
done:
if (kerr == 0) {
if (kerr != 0) {
return EINVAL;
switch (auth_token_type) {
case SSS_AUTHTOK_TYPE_EMPTY:
case SSS_AUTHTOK_TYPE_CCFILE:
return EINVAL;
*p += auth_token_length;
return ret;
size_t p = 0;
return ENOMEM;
p += len;
p += len;
p += len;
if (ret) {
return ret;
if (ret) {
return ret;
p += len;
return EOK;
return EOK;
if (krberr != 0) {
goto done;
if (krberr != 0) {
krberr = 0;
goto done;
krberr = 0;
done:
return krberr;
const char *primary,
const char *realm,
const char *keytab_name,
char **fast_ccname)
char *ccname;
char *server_name;
return ENOMEM;
goto done;
if (kerr) {
goto done;
if (kerr != 0) {
goto done;
goto done;
if (kerr != 0) {
goto done;
if (kerr == 0) {
goto done;
if (kerr != 0) {
goto done;
kerr = 0;
done:
if (kerr == 0) {
return kerr;
errno = 0;
return ret;
return ret;
char *fast_principal_realm;
char *fast_principal;
char *tmp_str;
if (tmp_str) {
if (kerr) {
return kerr;
&tmp_str);
if (kerr) {
return kerr;
if (!fast_principal) {
return KRB5KRB_ERR_GENERIC;
if (!fast_principal_realm) {
return ENOMEM;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (demand) {
if (kerr != 0) {
return kerr;
return EOK;
char *use_fast_str;
int parse_flags;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return EIO;
* missing in krb5.conf or to allow SSSD to work with multiple unconnected
if (kerr != 0) {
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
return ENOMEM;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (kerr != 0) {
return kerr;
if (!offline) {
return EINVAL;
return kerr;
int opt;
switch(opt) {
if (!debug_prg_name) {
goto done;
goto done;
goto done;
case SSS_PAM_AUTHENTICATE:
if (offline) {
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_ACCT_MGMT:
case SSS_CMD_RENEW:
if (offline) {
goto done;
goto done;
done:
exit(0);