summaryrefslogtreecommitdiffstats
path: root/src/providers/krb5/krb5_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/krb5/krb5_access.c')
-rw-r--r--src/providers/krb5/krb5_access.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/providers/krb5/krb5_access.c b/src/providers/krb5/krb5_access.c
new file mode 100644
index 0000000..2ae5abe
--- /dev/null
+++ b/src/providers/krb5/krb5_access.c
@@ -0,0 +1,220 @@
+/*
+ SSSD
+
+ Kerberos 5 Backend Module - access control
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ 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 "util/util.h"
+#include "providers/krb5/krb5_auth.h"
+#include "providers/krb5/krb5_common.h"
+#include "providers/krb5/krb5_utils.h"
+
+struct krb5_access_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+
+ struct pam_data *pd;
+ struct krb5_ctx *krb5_ctx;
+ struct krb5child_req *kr;
+
+ bool access_allowed;
+};
+
+static void krb5_access_done(struct tevent_req *subreq);
+struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct pam_data *pd,
+ struct krb5_ctx *krb5_ctx)
+{
+ struct krb5_access_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ int ret;
+ const char **attrs;
+ struct ldb_result *res;
+ struct sss_domain_info *dom;
+
+ req = tevent_req_create(mem_ctx, &state, struct krb5_access_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->be_ctx = be_ctx;
+ state->pd = pd;
+ state->krb5_ctx = krb5_ctx;
+ state->access_allowed = false;
+
+ ret = get_domain_or_subdomain(be_ctx, pd->domain, &dom);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n");
+ goto done;
+ }
+
+ ret = krb5_setup(state, pd, dom, krb5_ctx, &state->kr);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n");
+ goto done;
+ }
+
+ if (pd->cmd != SSS_PAM_ACCT_MGMT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unexpected pam task %d.\n", pd->cmd);
+ ret = EINVAL;
+ goto done;
+ }
+
+ attrs = talloc_array(state, const char *, 5);
+ if (attrs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ attrs[0] = SYSDB_UPN;
+ attrs[1] = SYSDB_UIDNUM;
+ attrs[2] = SYSDB_GIDNUM;
+ attrs[3] = SYSDB_CANONICAL_UPN;
+ attrs[4] = NULL;
+
+ ret = sysdb_get_user_attr(state, be_ctx->domain, state->pd->user, attrs,
+ &res);
+ if (ret) {
+ DEBUG(SSSDBG_FUNC_DATA,
+ "sysdb search for upn of user [%s] failed.\n", pd->user);
+ goto done;
+ }
+
+ switch (res->count) {
+ case 0:
+ DEBUG(SSSDBG_FUNC_DATA,
+ "No attributes for user [%s] found.\n", pd->user);
+ ret = ENOENT;
+ goto done;
+ break;
+ case 1:
+ ret = find_or_guess_upn(state, res->msgs[0], krb5_ctx, be_ctx->domain,
+ state->kr->user, pd->domain, &state->kr->upn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
+ goto done;
+ }
+
+ state->kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM,
+ 0);
+ if (state->kr->uid == 0) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "UID for user [%s] not known.\n", pd->user);
+ ret = ENOENT;
+ goto done;
+ }
+
+ state->kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM,
+ 0);
+ if (state->kr->gid == 0) {
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "GID for user [%s] not known.\n", pd->user);
+ ret = ENOENT;
+ goto done;
+ }
+
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "User search for [%s] returned > 1 results!\n", pd->user);
+ ret = EINVAL;
+ goto done;
+ break;
+ }
+
+ subreq = handle_child_send(state, state->ev, state->kr);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "handle_child_send failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, krb5_access_done, req);
+ return req;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, state->ev);
+ return req;
+}
+
+static void krb5_access_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+ struct krb5_access_state *state = tevent_req_data(req,
+ struct krb5_access_state);
+ int ret;
+ uint8_t *buf = NULL;
+ ssize_t len = -1;
+ int32_t msg_status;
+
+ ret = handle_child_recv(subreq, state, &buf, &len);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "child failed [%d][%s].\n", ret, strerror(ret));
+ goto fail;
+ }
+
+ if ((size_t) len != sizeof(int32_t)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "message has the wrong size.\n");
+ ret = EINVAL;
+ goto fail;
+ }
+
+ SAFEALIGN_COPY_INT32(&msg_status, buf, NULL);
+
+ if (msg_status == EOK) {
+ state->access_allowed = true;
+ } else {
+ state->access_allowed = false;
+ }
+
+ tevent_req_done(req);
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+int krb5_access_recv(struct tevent_req *req, bool *access_allowed)
+{
+ struct krb5_access_state *state = tevent_req_data(req,
+ struct krb5_access_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *access_allowed = state->access_allowed;
+
+ return EOK;
+}