krb5_auth.c revision 02e38eae1b9cb5df2036a707dafd86f6047c17de
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski Kerberos 5 Backend Module
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Sumit Bose <sbose@redhat.com>
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder Copyright (C) 2009-2010 Red Hat
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder This program is free software; you can redistribute it and/or modify
f3a94a197960e548ecd6520bb768cb0d547457bbChristian Maeder it under the terms of the GNU General Public License as published by
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder the Free Software Foundation; either version 3 of the License, or
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (at your option) any later version.
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder This program is distributed in the hope that it will be useful,
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder but WITHOUT ANY WARRANTY; without even the implied warranty of
0a26144c20fa9cdcd05011ca5019cbac8e4afae0cmaeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0a26144c20fa9cdcd05011ca5019cbac8e4afae0cmaeder GNU General Public License for more details.
93603bd881e43d4ff5a57d7ca4e2b9fa619f25b4cmaeder You should have received a copy of the GNU General Public License
d1c667fd9445963d9d31e2cf5d0ead15e77082a4cmaeder along with this program. If not, see <http://www.gnu.org/licenses/>.
109a53dbf4c9233f869f63ba7a7f3fece49973c3Christian Maeder#define KRB5_CHILD SSSD_LIBEXEC_PATH"/krb5_child"
0130083f314580170af1195037be3325f125fbceChristian Maederstatic errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(1, ("Only absolute path names are allowed.\n"));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(1, ("stat failed [%d][%s].\n", errno, strerror(errno)));
7f7460e7095628f3437b116ee78d3043d11f8febChristian Maeder DEBUG(1, ("Cache file [%s] exists, but is owned by [%d] instead of "
16b71dad8d398af412d66a4f4763f1ada5b03d23Christian Maeder "[%d].\n", filename, stat_buf.st_uid, uid));
4eb859461f8fd904f40f57261cf23e5c73cf8ecaChristian Maeder DEBUG(1, ("Cache file [%s] exists, but is not a regular file.\n",
4eb859461f8fd904f40f57261cf23e5c73cf8ecaChristian Maeder ret = check_if_uid_is_active(uid, &active);
2353f65833a3da763392f771223250cd50b8d873Christian Maeder DEBUG(1, ("check_if_uid_is_active failed.\n"));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(9, ("User [%d] is still active, reusing ccache file [%s].\n",
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maederstatic int krb5_save_ccname(TALLOC_CTX *mem_ctx,
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname);
a31430de8b0632d29f42634d6395e982bf31b14dChristian Maeder DEBUG(6, ("Error %d starting transaction (%s)\n", ret, strerror(ret)));
ce8a93047aaf0dc36fa221642292d47852a9862aChristian Maeder DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maedererrno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf)
1f2c732265a1292f0d7c51a4a7ca6be5dd370df6cmaeder const char *keytab;
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB);
b76d27eba526ecac2a20400fa505ec5c642ae7d2Dominik Luecke validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0;
2353f65833a3da763392f771223250cd50b8d873Christian Maeder buf->size = 9*sizeof(uint32_t) + strlen(kr->upn) + strlen(kr->ccname) +
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder buf->size += sizeof(uint32_t) + kr->pd->newauthtok_size;
cb2044812811d66efe038d914966e04290be93faChristian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->cmd, &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp);
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp);
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
8d780c893d6df5dab3dcc7d8444b7517f6547f11Christian Maeder safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder safealign_memcpy(&buf->data[rp], kr->pd->authtok,
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, &rp);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder safealign_memcpy(&buf->data[rp], kr->pd->newauthtok,
d96bfd1d7a4595bfff87771b91797330fa939455Christian Maederstatic struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
34d14197eb3dd643a8e6ef3ed8cba5629528e97fAivaras Jakubauskas pd = talloc_get_type(be_req->req_data, struct pam_data);
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder return talloc_get_type(be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
9ee80c455784287a8b5e1b6bac1f8efa6a2f4bb3cmaeder return talloc_get_type(be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maederstatic void krb_reply(struct be_req *req, int dp_err, int result);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
2360728d4185c0c04279c999941c64d36626af79Christian Maeder child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder memset(kr, 0, sizeof(struct krb5child_req));
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksastatic errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa kr = talloc_zero(mem_ctx, struct krb5child_req);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
0d79ea4ed8512a802ecb6645edac141e0fbcee3fChristian Maederstatic void krb5_child_timeout(struct tevent_context *ev,
9ee80c455784287a8b5e1b6bac1f8efa6a2f4bb3cmaeder struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
fb89f291c4e12ee44de11d4a900c445ed727b90dEugen Kuksa struct handle_child_state *state = tevent_req_data(req,
9f4902edfa3d477e42343e0ec357a2f93b1119d1Christian Maeder DEBUG(9, ("timeout for child [%d] reached.\n", kr->child_pid));
ce8a93047aaf0dc36fa221642292d47852a9862aChristian Maeder DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno)));
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maederstatic errno_t activate_child_timeout_handler(struct tevent_req *req,
fb89f291c4e12ee44de11d4a900c445ed727b90dEugen Kuksa struct handle_child_state *state = tevent_req_data(req,
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder kr->timeout_handler = tevent_add_timer(ev, state, tv,
9f4902edfa3d477e42343e0ec357a2f93b1119d1Christian Maederstatic errno_t fork_child(struct tevent_req *req, struct tevent_context *ev,
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno)));
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno)));
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder /* We need to keep the root privileges to read the keytab file if
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * validation is enabled, otherwise we can drop them here and run
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * krb5_child with user privileges.
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * If we are offline and want to create an empty ccache file. In this
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder * case we can drop the privileges, too. */
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ||
cb2044812811d66efe038d914966e04290be93faChristian Maeder DEBUG(1, ("Could not exec LDAP child: [%d][%s].\n",
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder ret = child_handler_setup(ev, pid, NULL, NULL);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(1, ("Could not set up child signal handler\n"));
bbba6dd86153aacb0f662b182b128df0eb09fd54Christian Maeder err = activate_child_timeout_handler(req, ev, kr);
16b71dad8d398af412d66a4f4763f1ada5b03d23Christian Maeder DEBUG(1, ("activate_child_timeout_handler failed.\n"));
d27b1887e61f1dc53d77c37f59dbf5019242a686Christian Maeder } else { /* error */
fe495a0978e5aa70776103c37fb0eb2bd6abea69Eugen Kuksa DEBUG(1, ("fork failed [%d][%s].\n", errno, strerror(errno)));
31bc219bae758272d0f064281b8ce7740a4553e9Till Mossakowskistatic void handle_child_step(struct tevent_req *subreq);
a31430de8b0632d29f42634d6395e982bf31b14dChristian Maederstatic void handle_child_done(struct tevent_req *subreq);
9ee80c455784287a8b5e1b6bac1f8efa6a2f4bb3cmaederstatic struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
12aef5992d3af07dee81a4e02cf4be65a83f28bcChristian Maeder req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder DEBUG(1, ("create_send_buffer failed.\n"));
2360728d4185c0c04279c999941c64d36626af79Christian Maeder subreq = write_pipe_send(state, ev, buf->data, buf->size,
2360728d4185c0c04279c999941c64d36626af79Christian Maeder tevent_req_set_callback(subreq, handle_child_step, req);
d27b1887e61f1dc53d77c37f59dbf5019242a686Christian Maederstatic void handle_child_step(struct tevent_req *subreq)
33fcc19ef2b59493b4e91eebf701df95fd230765Christian Maeder struct tevent_req *req = tevent_req_callback_data(subreq,
ce8a93047aaf0dc36fa221642292d47852a9862aChristian Maeder struct handle_child_state *state = tevent_req_data(req,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder subreq = read_pipe_send(state, state->ev, state->kr->read_from_child_fd);
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder tevent_req_set_callback(subreq, handle_child_done, req);
91e24fc45834b35f2a3830d72565640251149bf3Christian Maederstatic void handle_child_done(struct tevent_req *subreq)
91e24fc45834b35f2a3830d72565640251149bf3Christian Maeder struct tevent_req *req = tevent_req_callback_data(subreq,
91e24fc45834b35f2a3830d72565640251149bf3Christian Maeder struct handle_child_state *state = tevent_req_data(req,
d56ece59c372cb887355825901222b9f3377f7e6Thiemo Wiedemeyer ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maederstatic int handle_child_recv(struct tevent_req *req,
22b772f8753f0cdb4508ba460356c238de2ee375Jonathan von Schroeder struct handle_child_state *state = tevent_req_data(req,
a68ff26ddb1d300f7e16097edef615f130fcd5ceChristian Maederstatic void krb5_resolve_kdc_done(struct tevent_req *subreq);
9f226cec9f978edaba67aee4c4e04e3d3b994b87Daniel Calegaristatic void krb5_resolve_kpasswd_done(struct tevent_req *subreq);
f730570f7c284b252ad2e24cf23cc594021f9e25Jonathan von Schroederstatic void krb5_find_ccache_step(struct tevent_req *req);
6f70475dddc12732bdbef3e3dd116373e34cd6b9Christian Maederstatic void krb5_save_ccname_done(struct tevent_req *req);
897a04683fb30873e84dc3360dea770a4435971cChristian Maederstatic void krb5_child_done(struct tevent_req *req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_pam_handler_cache_auth_step(struct tevent_req *req);
22b772f8753f0cdb4508ba460356c238de2ee375Jonathan von Schroederint krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
f730570f7c284b252ad2e24cf23cc594021f9e25Jonathan von Schroeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
9f226cec9f978edaba67aee4c4e04e3d3b994b87Daniel Calegaristruct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
1ebf8299efa3cdb39c73d40d15e1d1a8a2246e68notanartist const char **attrs;
8762d0e3d492aba4d1621fb0de685f0be1372864notanartist req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
bbba10ee00dcf6bcbc9f22473b1acd0983b10512notanartist DEBUG(4, ("Password reset by root is not supported.\n"));
8a5c05062ef501bf725a86a370a5145a198e81fdKlaus Luettich DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(9, ("Password changes are not possible while offline.\n"));
4c872eeb600fe8479dbda395405cf13c3d573c24Soeren D. Schulze attrs = talloc_array(state, const char *, 6);
726baec6dfb69adb27f2afb4b2027fe5e7670c4aTill Mossakowski ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = sysdb_get_user_attr(state, be_ctx->sysdb, be_ctx->domain,
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(5, ("sysdb search for upn of user [%s] failed.\n", pd->user));
4c872eeb600fe8479dbda395405cf13c3d573c24Soeren D. Schulze realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(5, ("No attributes for user [%s] found.\n", pd->user));
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder kr->upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);
427ff3172ae2dfebe3c8fc972735158999997e8aChristian Maeder /* NOTE: this is a hack, works only in some environments */
3490b73f69b58ab742417b0867d0e2d4a7778cc0Christian Maeder kr->upn = talloc_asprintf(kr, "%s@%s", pd->user, realm);
59aa5703ac7f3b99e97cd5926e77088b256c5f40Christian Maeder DEBUG(1, ("failed to build simple upn.\n"));
7bb0a9e92bc7a6f868eaa0b9c3212c0af4f96b7fEugen Kuksa DEBUG(9, ("Using simple UPN [%s].\n", kr->upn));
7968d3a131e5a684ec1ff0c6d88aae638549153dChristian Maeder kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder DEBUG(4, ("Home directory for user [%s] not known.\n", pd->user));
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(4, ("UID for user [%s] not known.\n", pd->user));
beff4152e9f0fe90885458d1a1733b183a2a8816Christian Maeder kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(4, ("GID for user [%s] not known.\n", pd->user));
78c294da55788b25e175180168371c9536a6d440Christian Maeder ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder ret = check_if_ccache_file_is_used(kr->uid, ccache_file,
bc263f610d20a9cd3014ddfca903026127fa0d48Christian Maeder DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));
78c294da55788b25e175180168371c9536a6d440Christian Maeder kerr = check_for_valid_tgt(ccache_file, realm, kr->upn,
78c294da55788b25e175180168371c9536a6d440Christian Maeder DEBUG(1, ("check_for_valid_tgt failed.\n"));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user));
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n",
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(1, ("User search for (%s) returned > 1 results!\n", pd->user));
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);
31bc219bae758272d0f064281b8ce7740a4553e9Till Mossakowskistatic void krb5_resolve_kdc_done(struct tevent_req *subreq)
a31430de8b0632d29f42634d6395e982bf31b14dChristian Maeder struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
a31430de8b0632d29f42634d6395e982bf31b14dChristian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder /* all servers have been tried and none
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder * was found good, setting offline,
dff1de7ad15d1582e25d636c3724dd202874897fChristian Maeder * but we still have to call the child to setup
91ba5d95b2472cb075646b6120a559dc6581a867Christian Maeder * the ccache file. */
7bb0a9e92bc7a6f868eaa0b9c3212c0af4f96b7fEugen Kuksa subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder DEBUG(1, ("be_resolve_server_send failed.\n"));
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder tevent_req_set_callback(subreq, krb5_resolve_kpasswd_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_resolve_kpasswd_done(struct tevent_req *subreq)
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
bbba6dd86153aacb0f662b182b128df0eb09fd54Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
55282ad62e8b6758abec43734ebde0015ac14b89Eugen Kuksa ret = be_resolve_server_recv(subreq, &state->kr->kpasswd_srv);
8c8545dd3bf34fbcbc16904b65d249658f8f9efcChristian Maeder /* all kpasswd servers have been tried and none was found good, but the
33fcc19ef2b59493b4e91eebf701df95fd230765Christian Maeder * kdc seems ok. Password changes are not possible but
d4ebd9e5adc974cfa2bdf4bdd155e07be0e26f75Christian Maeder * authentication. We return an PAM error here, but do not mark the
7bb0a9e92bc7a6f868eaa0b9c3212c0af4f96b7fEugen Kuksa * backend offline. */
4a2f7efdf67dfcda0946f1b6373f41976ddea7a4Christian Maederstatic void krb5_find_ccache_step(struct tevent_req *req)
3490b73f69b58ab742417b0867d0e2d4a7778cc0Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
1f2c732265a1292f0d7c51a4a7ca6be5dd370df6cmaeder bool private_path = false;
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa /* The ccache file should be (re)created if one of the following conditions
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * - it doesn't exist (kr->ccname == NULL)
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * - the backend is online and the current ccache file is not used, i.e
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * the related user is currently not logged in
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * (!be_is_offline(state->be_ctx) && !kr->active_ccache_present)
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * - the backend is offline and the current cache file not used and
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * it does not contain a valid tgt
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * (be_is_offline(state->be_ctx) &&
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * !kr->active_ccache_present && !kr->valid_tgt_present)
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa (be_is_offline(state->be_ctx) && !kr->active_ccache_present &&
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa (!be_is_offline(state->be_ctx) && !kr->active_ccache_present)) {
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder if (strncmp(kr->ccname, "FILE:", 5) == 0) {
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n",
f03420e44d8204b2945edaab5c70a84e7c381892Christian Maeder DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname, ret,
34d14197eb3dd643a8e6ef3ed8cba5629528e97fAivaras Jakubauskas kr->ccname = expand_ccname_template(kr, kr,
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder DEBUG(9, ("Preparing for offline operation.\n"));
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder if (kr->valid_tgt_present || kr->active_ccache_present) {
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder "ccache file is already in use.\n"));
96ae1a1d2197d0e0d5b80da2474b64c456feb1b0Christian Maeder msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname);
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1,
16b71dad8d398af412d66a4f4763f1ada5b03d23Christian Maeder subreq = handle_child_send(state, state->ev, kr);
9dd71ac51c9a6e72bcb126224f9c64131698b636Christian Maeder tevent_req_set_callback(subreq, krb5_child_done, req);
7245138e91992b96b153b8ac527e263d9dc8ff5bChristian Maederstatic struct tevent_req *krb5_next_server(struct tevent_req *req);
0ea2cddb8715a770e646895e16b7b8085f49167cChristian Maederstatic struct tevent_req *krb5_next_kdc(struct tevent_req *req);
7968d3a131e5a684ec1ff0c6d88aae638549153dChristian Maederstatic struct tevent_req *krb5_next_kpasswd(struct tevent_req *req);
7968d3a131e5a684ec1ff0c6d88aae638549153dChristian Maederstatic void krb5_child_done(struct tevent_req *subreq)
a461314c811f4187dff85c8be079a41b2f13f176Christian Maeder struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
a461314c811f4187dff85c8be079a41b2f13f176Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
0130083f314580170af1195037be3325f125fbceChristian Maeder ret = handle_child_recv(subreq, pd, &buf, &len);
0130083f314580170af1195037be3325f125fbceChristian Maeder DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));
9d6562465b41f17c7967d4e5678f34811d958cb2Christian Maeder /* A buffer with the following structure is expected.
9d6562465b41f17c7967d4e5678f34811d958cb2Christian Maeder * int32_t status of the request (required)
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder * message (zero or more)
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder * A message consists of:
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder * int32_t type of the message
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder * int32_t length of the following data
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder * uint8_t[len] data
daec53c285f692c56db0cefe16061b46ba602cf0Christian Maeder SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder while (p < len) {
93bc87ee96c68506945dbad8c704badaa42ecf14Christian Maeder SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p);
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type,
0a64bfd28dff15bc93e1f7a86e0a8052e879636dChristian Maeder DEBUG(1, ("message format error [%d] > [%d].\n", p+msg_len, len));
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder /* We need to save the name of the credential cache file. To find it
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * we check if the data part of a message starts with
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
0b13f102310e03a20b38c870b5acb88712f316a4Christian Maeder * sizeof() counts the trailing '\0' of a string. */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len],
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* This is not a fatal error */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if ((p < len) && (p + 2*sizeof(int32_t) >= len)) {
2353f65833a3da763392f771223250cd50b8d873Christian Maeder DEBUG(1, ("The remainder of the message is too short.\n"));
0ae7a79e865d4a6022d705d160530682b3c1f825Christian Maeder /* If the child request failed, but did not return an offline error code,
863d4b011d04907325f3eed8e89975e38603cb05Christian Maeder * return with the status */
0ae7a79e865d4a6022d705d160530682b3c1f825Christian Maeder if (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL &&
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder /* If the child request was successful and we run the first pass of the
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder * change password request just return success. */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* if using a dedicated kpasswd server.. */
12aef5992d3af07dee81a4e02cf4be65a83f28bcChristian Maeder /* ..which is unreachable by now.. */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder /* ..try to resolve next kpasswd server */
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder fo_set_port_status(kr->kpasswd_srv, PORT_WORKING);
057b3bffc58757a98e8e7c1aeaf5cbbc986b3117Christian Maeder /* if the KDC for auth (PAM_AUTHINFO_UNAVAIL) or
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * chpass (PAM_AUTHTOK_LOCK_BUSY) was not available while using KDC
502483734c83d0bf1eadcc94113d0362f8713784Christian Maeder * also for chpass operation... */
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa (kr->kpasswd_srv == NULL && msg_status == PAM_AUTHTOK_LOCK_BUSY)) {
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa /* ..try to resolve next KDC */
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa /* The following cases are left now:
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * - offline (msg_status == PAM_AUTHINFO_UNAVAIL or
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * msg_status == PAM_AUTHTOK_LOCK_BUSY)
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * - successful authentication or password change
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * For all these cases we expect that one of the messages for the
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa * received buffer contains the name of the credential cache file. */
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa DEBUG(1, ("Missing ccache name in child response.\n"));
fe495a0978e5aa70776103c37fb0eb2bd6abea69Eugen Kuksa ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, kr->ccname);
16b71dad8d398af412d66a4f4763f1ada5b03d23Christian Maeder ret = krb5_save_ccname(state, state->be_ctx->sysdb,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(1, ("krb5_save_ccname_send failed.\n"));
4347b243063d414f97a68b64e30a4f27a612af0aChristian Maederstatic struct tevent_req *krb5_next_server(struct tevent_req *req)
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
502483734c83d0bf1eadcc94113d0362f8713784Christian Maeder fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder fo_set_port_status(state->kr->kpasswd_srv, PORT_NOT_WORKING);
2353f65833a3da763392f771223250cd50b8d873Christian Maeder fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);
7bb0a9e92bc7a6f868eaa0b9c3212c0af4f96b7fEugen Kuksastatic struct tevent_req *krb5_next_kdc(struct tevent_req *req)
7bb0a9e92bc7a6f868eaa0b9c3212c0af4f96b7fEugen Kuksa struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
0130083f314580170af1195037be3325f125fbceChristian Maeder next_req = be_resolve_server_send(state, state->ev,
be43c3fa0292555bd126784ae27ff5c1d23438cbChristian Maeder DEBUG(1, ("be_resolve_server_send failed.\n"));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder tevent_req_set_callback(next_req, krb5_resolve_kdc_done, req);
502483734c83d0bf1eadcc94113d0362f8713784Christian Maederstatic struct tevent_req *krb5_next_kpasswd(struct tevent_req *req)
2353f65833a3da763392f771223250cd50b8d873Christian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
c5a4c5f506ea34fa527065b4187127a18c6e2418Christian Maeder next_req = be_resolve_server_send(state, state->ev,
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(1, ("be_resolve_server_send failed.\n"));
2360728d4185c0c04279c999941c64d36626af79Christian Maeder tevent_req_set_callback(next_req, krb5_resolve_kpasswd_done, req);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maederstatic void krb5_save_ccname_done(struct tevent_req *req)
8c8545dd3bf34fbcbc16904b65d249658f8f9efcChristian Maeder struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder if (dp_opt_get_bool(kr->krb5_ctx->opts,KRB5_STORE_PASSWORD_IF_OFFLINE)) {
c5a4c5f506ea34fa527065b4187127a18c6e2418Christian Maeder DEBUG(4, ("Backend is marked offline, retry later!\n"));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder if (state->be_ctx->domain->cache_credentials == TRUE) {
0ede68718d0fd43b5d67c233ccfb7a2b673fc9cbChristian Maeder /* password caching failures are not fatal errors */
1c4dfa148603d4fcf4cdd2ed66c8b6e1de0dd696Till Mossakowski password = talloc_size(state, pd->authtok_size + 1);
502483734c83d0bf1eadcc94113d0362f8713784Christian Maeder memcpy(password, pd->authtok, pd->authtok_size);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder password = talloc_size(state, pd->newauthtok_size + 1);
b6ff72be73dad3d1394cf2c71e29e67624ff030bChristian Maeder memcpy(password, pd->newauthtok, pd->newauthtok_size);
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd));
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder DEBUG(0, ("password not available, offline auth may not work.\n"));
16b71dad8d398af412d66a4f4763f1ada5b03d23Christian Maeder ret = EOK; /* password caching failures are not fatal errors */
b53688bfed888214b485cf76439d57262d80e0a7Christian Maeder talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
a3a7d8b3cdf05c8040c62dbcf9a15dc5042cd721Christian Maeder ret = sysdb_cache_password(state, state->be_ctx->sysdb,
a389e88e0acb83d8489bdc5e55bc5522b152bbecEugen Kuksa DEBUG(2, ("Failed to cache password, offline auth may not work."
done:
int ret;
goto failed;
krb5_ctx);
goto failed;
int ret;
int pam_status;
int dp_err;
if (ret) {