diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2014-11-28 13:04:42 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2014-12-03 11:02:44 +0100 |
commit | 543d1652e0185abadd5d8b45c718a3db96cd2828 (patch) | |
tree | bb17cc89e2e8d8ddc36b6049cf89922aeca61b99 | |
parent | b4f87b42b18888c396e44e7359f7aafb092221bf (diff) | |
download | sssd-543d1652e0185abadd5d8b45c718a3db96cd2828.tar.gz sssd-543d1652e0185abadd5d8b45c718a3db96cd2828.tar.xz sssd-543d1652e0185abadd5d8b45c718a3db96cd2828.zip |
KRB5: Create the fast ccache in a child process
Related:
https://fedorahosted.org/sssd/ticket/2503
In order to avoid calling Kerberos library calls as root, the krb5_child
forks itself and recreates the FAST ccache as the SSSD user.
Reviewed-by: Sumit Bose <sbose@redhat.com>
-rw-r--r-- | src/providers/krb5/krb5_child.c | 118 | ||||
-rw-r--r-- | src/providers/krb5/krb5_child_handler.c | 10 |
2 files changed, 100 insertions, 28 deletions
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index cd78874db..e16620891 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -74,6 +74,9 @@ struct krb5_req { bool old_cc_valid; bool old_cc_active; enum k5c_fast_opt fast_val; + + uid_t fast_uid; + gid_t fast_gid; }; static krb5_context krb5_error_ctx; @@ -1009,17 +1012,6 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n"); } - if (kr->validate || kr->fast_ccname != NULL) { - /* We drop root privileges which were needed to read the keytab file - * for the validation of the credentials or for FAST here to run the - * ccache I/O operations with user privileges. */ - kerr = become_user(kr->uid, kr->gid); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); - return kerr; - } - } - /* If kr->ccname is cache collection (DIR:/...), we want to work * directly with file ccache (DIR::/...), but cache collection * should be returned back to back end. @@ -1440,17 +1432,6 @@ static errno_t renew_tgt_child(struct krb5_req *kr) DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n"); } - if (kr->validate || kr->fast_ccname != NULL) { - /* We drop root privileges which were needed to read the keytab file - * for the validation of the credentials or for FAST here to run the - * ccache I/O operations with user privileges. */ - kerr = become_user(kr->uid, kr->gid); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); - goto done; - } - } - kerr = krb5_cc_initialize(kr->ctx, ccache, kr->princ); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); @@ -1724,6 +1705,8 @@ done: static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, krb5_context ctx, + uid_t fast_uid, + gid_t fast_gid, const char *primary, const char *realm, const char *keytab_name, @@ -1737,6 +1720,8 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, krb5_keytab keytab = NULL; krb5_principal client_princ = NULL; krb5_principal server_princ = NULL; + pid_t fchild_pid; + int status; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { @@ -1794,10 +1779,79 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, } } - kerr = get_and_save_tgt_with_keytab(ctx, client_princ, keytab, ccname); - if (kerr != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "get_and_save_tgt_with_keytab failed.\n"); - goto done; + /* Need to recreate the FAST ccache */ + fchild_pid = fork(); + switch (fchild_pid) { + case -1: + DEBUG(SSSDBG_CRIT_FAILURE, "fork failed\n"); + kerr = EIO; + goto done; + case 0: + /* Child */ + debug_prg_name = talloc_asprintf(NULL, "[sssd[krb5_child[%d]]]", getpid()); + if (debug_prg_name == NULL) { + debug_prg_name = "[sssd[krb5_child]]"; + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); + /* Try to carry on */ + } + + kerr = become_user(fast_uid, fast_gid); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr); + exit(1); + } + DEBUG(SSSDBG_TRACE_INTERNAL, + "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid()); + + kerr = get_and_save_tgt_with_keytab(ctx, client_princ, + keytab, ccname); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, + "get_and_save_tgt_with_keytab failed: %d\n", kerr); + exit(2); + } + exit(0); + default: + /* Parent */ + do { + errno = 0; + kerr = waitpid(fchild_pid, &status, 0); + } while (kerr == -1 && errno == EINTR); + + if (kerr > 0) { + kerr = EIO; + if (WIFEXITED(status)) { + kerr = WEXITSTATUS(status); + /* Don't blindly fail if the child fails, but check + * the ccache again */ + if (kerr != 0) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Creating FAST ccache failed, krb5_child will " + "likely fail!\n"); + } + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + "krb5_child subprocess %d terminated unexpectedly\n", + fchild_pid); + } + } else { + DEBUG(SSSDBG_FUNC_DATA, + "Failed to wait for children %d\n", fchild_pid); + kerr = EIO; + } + } + + /* Check the ccache times again. Should be updated ... */ + memset(&tgtt, 0, sizeof(tgtt)); + kerr = get_tgt_times(ctx, ccname, server_princ, client_princ, &tgtt); + if (kerr == 0) { + if (tgtt.endtime > time(NULL)) { + DEBUG(SSSDBG_FUNC_DATA, "FAST TGT was successfully recreated!\n"); + goto done; + } else { + kerr = ERR_CREDS_EXPIRED; + goto done; + } } kerr = 0; @@ -1889,7 +1943,8 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand) fast_principal = NULL; } - kerr = check_fast_ccache(kr, kr->ctx, fast_principal, fast_principal_realm, + kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid, + fast_principal, fast_principal_realm, kr->keytab, &kr->fast_ccname); if (kerr != 0) { DEBUG(SSSDBG_CRIT_FAILURE, "check_fast_ccache failed.\n"); @@ -2253,6 +2308,8 @@ int main(int argc, const char *argv[]) int debug_fd = -1; errno_t ret; krb5_error_code kerr; + uid_t fast_uid; + gid_t fast_gid; struct poptOption long_options[] = { POPT_AUTOHELP @@ -2267,6 +2324,10 @@ int main(int argc, const char *argv[]) {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, _("Send the debug output to stderr directly."), NULL }, + {"fast-ccache-uid", 0, POPT_ARG_INT, &fast_uid, 0, + _("The user to create FAST ccache as"), NULL}, + {"fast-ccache-gid", 0, POPT_ARG_INT, &fast_gid, 0, + _("The group to create FAST ccache as"), NULL}, POPT_TABLEEND }; @@ -2313,6 +2374,9 @@ int main(int argc, const char *argv[]) } talloc_steal(kr, debug_prg_name); + kr->fast_uid = fast_uid; + kr->fast_gid = fast_gid; + ret = k5c_recv_data(kr, STDIN_FILENO, &offline); if (ret != EOK) { goto done; diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 9bb61f654..1454d220f 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -278,6 +278,14 @@ static errno_t fork_child(struct tevent_req *req) errno_t err; struct handle_child_state *state = tevent_req_data(req, struct handle_child_state); + const char *k5c_extra_args[3]; + + k5c_extra_args[0] = talloc_asprintf(state, "--fast-ccache-uid=%"SPRIuid, getuid()); + k5c_extra_args[1] = talloc_asprintf(state, "--fast-ccache-gid=%"SPRIgid, getgid()); + k5c_extra_args[2] = NULL; + if (k5c_extra_args[0] == NULL || k5c_extra_args[1] == NULL) { + return ENOMEM; + } ret = pipe(pipefd_from_child); if (ret == -1) { @@ -300,7 +308,7 @@ static errno_t fork_child(struct tevent_req *req) err = exec_child(state, pipefd_to_child, pipefd_from_child, KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd, - NULL); + k5c_extra_args); if (err != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n", err, strerror(err)); |