b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose Kerberos 5 Backend Module - Manage krb5_child
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose Sumit Bose <sbose@redhat.com>
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose Copyright (C) 2010 Red Hat
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose This program is free software; you can redistribute it and/or modify
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose it under the terms of the GNU General Public License as published by
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose the Free Software Foundation; either version 3 of the License, or
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose (at your option) any later version.
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose This program is distributed in the hope that it will be useful,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose but WITHOUT ANY WARRANTY; without even the implied warranty of
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose GNU General Public License for more details.
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose You should have received a copy of the GNU General Public License
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose along with this program. If not, see <http://www.gnu.org/licenses/>.
248a24eda712d738127897264290ad1b751faf12Jakub Hrozek#endif /* SSSD_LIBEXEC_PATH */
248a24eda712d738127897264290ad1b751faf12Jakub Hrozek#endif /* KRB5_CHILD_DIR */
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek#define int64_to_time_t(val) ((time_t)((val) < TIME_T_MAX ? val : TIME_T_MAX))
64af76e2bef2565caa9738f675c108a4b3789237Simo Sorcestatic errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
64af76e2bef2565caa9738f675c108a4b3789237Simo Sorce ret = sss_authtok_get_password(tok, &data, &len);
64af76e2bef2565caa9738f675c108a4b3789237Simo Sorce SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp);
64af76e2bef2565caa9738f675c108a4b3789237Simo Sorce SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp);
2d527aab0bab0c5323b7ea09c9a8c3820f4f8736Sumit Bose safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic errno_t create_send_buffer(struct krb5child_req *kr,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Missing keytab option.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0;
48657b5de36a63b0c13ed5d53065871d59d8f10bJakub Hrozek /* Always send PAC except for local IPA users and IPA server mode */
48657b5de36a63b0c13ed5d53065871d59d8f10bJakub Hrozek send_pac = kr->upn_from_different_realm ? 1 : 0;
614057ea85c05d3a6d4b62217a41b8b5db8d5d38Sumit Bose if (kr->pd->cmd == SSS_CMD_RENEW || kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM
614057ea85c05d3a6d4b62217a41b8b5db8d5d38Sumit Bose || kr->pd->cmd == SSS_PAM_CHAUTHTOK || kr->is_offline) {
695cc8754aecb3dcc3a617d86b7d4b6470af175dSumit Bose use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
f772649cb8b624f4b4dfa5521f487ef38e3f8931Jakub Hrozek buf->size = 9*sizeof(uint32_t) + strlen(kr->upn);
f772649cb8b624f4b4dfa5521f487ef38e3f8931Jakub Hrozek buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->cmd, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
861ab44e8148208425b67c4711bc8fade10fd3edJakub Hrozek SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
fa4a9c4afcc0c62a693034e21f33356e64735687Sumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp);
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->old_ccname), &rp);
2745b0156f12df7a7eb93d57716233243658e4d9Jakub Hrozek safealign_memcpy(&buf->data[rp], kr->old_ccname,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
9acfb09f7969a69f58bd45c856b01700541853caLukas Slebodnik ret = pack_authtok(buf, &rp, kr->pd->authtok);
9acfb09f7969a69f58bd45c856b01700541853caLukas Slebodnik ret = pack_authtok(buf, &rp, kr->pd->newauthtok);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose SAFEALIGN_SET_UINT32(&buf->data[rp], username_len, &rp);
fedfb7c62b4efa89d18d0d3a7895a2a34ec4ce42Jakub Hrozek safealign_memcpy(&buf->data[rp], kr->kuserok_user, username_len, &rp);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic void krb5_child_timeout(struct tevent_context *ev,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Timeout for child [%d] reached. In case KDC is distant or network "
07270cd9739b942c63602ef57c513c6a50e6f7eePavel Reichl "is slow you may consider increasing value of krb5_auth_timeout.\n",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "kill failed [%d][%s].\n", errno, strerror(errno));
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic errno_t activate_child_timeout_handler(struct tevent_req *req,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose tv = tevent_timeval_add(&tv, timeout_seconds, 0);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose state->timeout_handler = tevent_add_timer(ev, state, tv,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Boseerrno_t set_extra_args(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx,
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose if (krb5_ctx == NULL || krb5_child_extra_args == NULL) {
d380148b0a23dd1a04d1d0767ba41d3e76fb7d23Lukas Slebodnik extra_args = talloc_zero_array(mem_ctx, const char *, 10);
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose extra_args[c] = talloc_asprintf(extra_args, "--"CHILD_OPT_REALM"=%s",
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose extra_args[c] = talloc_asprintf(extra_args, "--"CHILD_OPT_LIFETIME"=%s",
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose extra_args[c] = talloc_asprintf(extra_args, "--"CHILD_OPT_USE_FAST"=%s",
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose ret = set_extra_args(state, state->kr->krb5_ctx, &krb5_child_extra_args);
7e394400eefd0e7c5ba0c64ab3fa28bee21ef2d7Sumit Bose DEBUG(SSSDBG_OP_FAILURE, "set_extra_args failed.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "pipe failed [%d][%s].\n", errno, strerror(errno));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "pipe failed [%d][%s].\n", errno, strerror(errno));
de8815aba87d08b6b7ac5d502dcb1755787e0857Jakub Hrozek KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
de8815aba87d08b6b7ac5d502dcb1755787e0857Jakub Hrozek /* We should never get here */
de8815aba87d08b6b7ac5d502dcb1755787e0857Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec KRB5 child\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose state->io->read_from_child_fd = pipefd_from_child[0];
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose state->io->write_to_child_fd = pipefd_to_child[1];
f3d91181d4ee9da3f8bbf4ddf8782951c0ae46c1Jakub Hrozek sss_fd_nonblocking(state->io->read_from_child_fd);
f3d91181d4ee9da3f8bbf4ddf8782951c0ae46c1Jakub Hrozek sss_fd_nonblocking(state->io->write_to_child_fd);
711bba7e2f72a816774effa389ad13bcc46e7843Pavel BĆezina ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Could not set up child signal handler\n");
45e11be651dbd3855a35de4abd2922e5b9d4b963Jakub Hrozek ret = activate_child_timeout_handler(req, state->ev,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose dp_opt_get_int(state->kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "activate_child_timeout_handler failed.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose } else { /* error */
45e11be651dbd3855a35de4abd2922e5b9d4b963Jakub Hrozek "fork failed [%d][%s].\n", errno, strerror(ret));
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic void handle_child_step(struct tevent_req *subreq);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic void handle_child_done(struct tevent_req *subreq);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestruct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
06f10b2a0ebb26f2460cd445f8040e9205de7500Jakub Hrozek state->io = talloc(state, struct child_io_fds);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose talloc_set_destructor((void *) state->io, child_io_destructor);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "create_send_buffer failed.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "fork_child failed.\n");
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose subreq = write_pipe_send(state, ev, buf->data, buf->size,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose tevent_req_set_callback(subreq, handle_child_step, req);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic void handle_child_step(struct tevent_req *subreq)
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct tevent_req *req = tevent_req_callback_data(subreq,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose tevent_req_set_callback(subreq, handle_child_done, req);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bosestatic void handle_child_done(struct tevent_req *subreq)
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct tevent_req *req = tevent_req_callback_data(subreq,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Boseint handle_child_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
b87233035e26cee919dcf46adaec29ba7fdaa51eSumit Bose struct handle_child_state *state = tevent_req_data(req,
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozekparse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "message too short.\n");
92c6d2bbff680c3f4a83fbb1360eed098e7bcf2eStephen Gallagher memset(&tgtt, 0, sizeof(struct tgt_times));
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek pwd_exp_warning = KERBEROS_PWEXPIRE_WARNING_TIME;
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek /* A buffer with the following structure is expected.
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * int32_t status of the request (required)
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * message (zero or more)
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * A message consists of:
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * int32_t type of the message
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * int32_t length of the following data
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * uint8_t[len] data
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek while (p < len) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_TRACE_LIBS, "child response [%d][%d][%d].\n",
9f0bffebd070115ab47a92eadc6890a721c7b78dMichal Ćœidek DEBUG(SSSDBG_CRIT_FAILURE, "message format error [%d] > [%zu].\n",
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek /* We need to save the name of the credential cache file. To find it
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * we check if the data part of a message starts with
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek * sizeof() counts the trailing '\0' of a string. */
fe521d1ad610920ce5411589a158157d6a5f0794Alexander Bokovoy (strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0)) {
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek SAFEALIGN_COPY_INT64(&time_data, buf+p+sizeof(int64_t), NULL);
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek SAFEALIGN_COPY_INT64(&time_data, buf+p+2*sizeof(int64_t), NULL);
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek SAFEALIGN_COPY_INT64(&time_data, buf+p+3*sizeof(int64_t), NULL);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_TRACE_LIBS, "TGT times are [%ld][%ld][%ld][%ld].\n",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov tgtt.authtime, tgtt.starttime, tgtt.endtime, tgtt.renew_till);
84fbb0cad534308254a8a8ad837d1924496cfe71Michal Zidek SAFEALIGN_COPY_UINT32(&msg_subtype, buf + p, NULL);
84fbb0cad534308254a8a8ad837d1924496cfe71Michal Zidek if (msg_subtype == SSS_PAM_USER_INFO_EXPIRE_WARN) {
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek /* This is not a fatal error */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
fe521d1ad610920ce5411589a158157d6a5f0794Alexander Bokovoy if ((p < len) && (p + 2*sizeof(int32_t) > len)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "The remainder of the message is too short.\n");
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek res = talloc_zero(mem_ctx, struct krb5_child_response);
7b14a9e64fd248103149eb1cb422ee752d91ba58Jakub Hrozek res->ccname = talloc_strndup(res, ccname, ccname_len);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
d3dca30d3a6feba062d0299718d1a9fcdc8b9d17Sumit Bose res->correct_upn = talloc_strndup(res, upn, upn_len);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");