summaryrefslogtreecommitdiff
path: root/src/responder/pac
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2012-06-18 12:01:27 +0200
committerStephen Gallagher <sgallagh@redhat.com>2012-06-21 15:30:21 -0400
commitee099cd5656b60c7384493b923ddf9af5cf5d4f5 (patch)
treea205fd9421b657e70ae114bc85add80f56698ce2 /src/responder/pac
parente3f0014bb64b7e93979948936cf93cf869d3dc44 (diff)
downloadsssd-ee099cd5656b60c7384493b923ddf9af5cf5d4f5.tar.gz
sssd-ee099cd5656b60c7384493b923ddf9af5cf5d4f5.tar.bz2
sssd-ee099cd5656b60c7384493b923ddf9af5cf5d4f5.zip
PAC responder: add the core functionality
This adds support for parsing PAC and storing information contained within. In particular the user and all his memberships are stored. In case it is necessary, getgrgid() requests are sent to provider for group resolution.
Diffstat (limited to 'src/responder/pac')
-rw-r--r--src/responder/pac/pacsrv.c2
-rw-r--r--src/responder/pac/pacsrv_cmd.c471
2 files changed, 471 insertions, 2 deletions
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index feee3aee..b21bb966 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -48,7 +48,7 @@
struct sbus_method monitor_pac_methods[] = {
{ MON_CLI_METHOD_PING, monitor_common_pong },
{ MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
- { MON_CLI_METHOD_ROTATE, monitor_common_rotate_logs },
+ { MON_CLI_METHOD_ROTATE, responder_logrotate },
{ NULL, NULL }
};
diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c
index 892ef856..1d67657d 100644
--- a/src/responder/pac/pacsrv_cmd.c
+++ b/src/responder/pac/pacsrv_cmd.c
@@ -23,7 +23,475 @@
#include "util/util.h"
#include "responder/pac/pacsrv.h"
#include "confdb/confdb.h"
-#include "db/sysdb.h"
+
+static errno_t pac_cmd_done(struct cli_ctx *cctx, int cmd_ret)
+{
+ int ret;
+
+ if (cmd_ret == EAGAIN) {
+ /* async processing, just return here */
+ return EOK;
+ }
+
+ ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
+ &cctx->creq->out);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sss_packet_new failed [%d][%s].\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ sss_packet_set_error(cctx->creq->out, cmd_ret);
+
+ sss_cmd_done(cctx, NULL);
+
+ return EOK;
+}
+
+struct pac_req_ctx {
+ struct cli_ctx *cctx;
+ struct pac_ctx *pac_ctx;
+ const char *domain_name;
+ const char *user_name;
+ struct sss_domain_info *dom;
+
+ struct PAC_LOGON_INFO *logon_info;
+ struct dom_sid2 *domain_sid;
+
+ size_t gid_count;
+ gid_t *gids;
+};
+
+static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx);
+static void pac_get_domains_done(struct tevent_req *req);
+static errno_t save_pac_user(struct pac_req_ctx *pr_ctx);
+static void pac_get_group_done(struct tevent_req *subreq);
+static errno_t pac_save_memberships_next(struct tevent_req *req);
+static errno_t pac_store_membership(struct pac_req_ctx *pr_ctx,
+ struct sysdb_ctx *group_sysdb,
+ struct ldb_dn *user_dn,
+ int gid_iter);
+struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx);
+static void pac_save_memberships_done(struct tevent_req *req);
+
+
+static errno_t pac_add_pac_user(struct cli_ctx *cctx)
+{
+ int ret;
+ uint8_t *body;
+ size_t blen;
+ struct pac_req_ctx *pr_ctx;
+ struct tevent_req *req;
+
+ sss_packet_get_body(cctx->creq->in, &body, &blen);
+
+ pr_ctx = talloc_zero(cctx, struct pac_req_ctx);
+ if (pr_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+ return ENOMEM;
+ }
+
+ pr_ctx->cctx = cctx;
+
+ pr_ctx->pac_ctx = talloc_get_type(cctx->rctx->pvt_ctx, struct pac_ctx);
+ if (pr_ctx->pac_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Cannot find pac responder context.\n"));
+ return EINVAL;
+ }
+
+ ret = get_data_from_pac(pr_ctx, body, blen,
+ &pr_ctx->logon_info);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_data_from_pac failed.\n"));
+ goto done;
+ }
+
+ pr_ctx->domain_name = pr_ctx->logon_info->info3.base.logon_domain.string;
+ if (pr_ctx->domain_name == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("No domain name in PAC"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ pr_ctx->user_name = pr_ctx->logon_info->info3.base.account_name.string;
+ if (pr_ctx->user_name == NULL) {
+ ret = EINVAL;
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Missing account name in PAC.\n"));
+ goto done;
+ }
+
+
+ pr_ctx->dom = responder_get_domain(pr_ctx, cctx->rctx, pr_ctx->domain_name);
+ if (pr_ctx->dom == NULL) {
+ req = sss_dp_get_domains_send(cctx->rctx, cctx->rctx, true,
+ pr_ctx->domain_name);
+ if (req == NULL) {
+ ret = ENOMEM;
+ } else {
+ tevent_req_set_callback(req, pac_get_domains_done, pr_ctx);
+ ret = EAGAIN;
+ }
+ goto done;
+ }
+
+ ret = pac_add_user_next(pr_ctx);
+
+done:
+ if (ret != EAGAIN) {
+ talloc_free(pr_ctx);
+ }
+ return pac_cmd_done(cctx, ret);
+}
+
+static void pac_get_domains_done(struct tevent_req *req)
+{
+ struct pac_req_ctx *pr_ctx = tevent_req_callback_data(req,
+ struct pac_req_ctx);
+ struct cli_ctx *cctx = pr_ctx->cctx;
+ int ret;
+
+ ret = sss_dp_get_domains_recv(req);
+ talloc_free(req);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ pr_ctx->dom = responder_get_domain(pr_ctx, cctx->rctx, pr_ctx->domain_name);
+ if (pr_ctx->dom == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Corresponding domain [%s] has not been "
+ "found\n", pr_ctx->domain_name));
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = pac_add_user_next(pr_ctx);
+
+done:
+ if (ret != EAGAIN) {
+ talloc_free(pr_ctx);
+ }
+ pac_cmd_done(cctx, ret);
+}
+
+static errno_t pac_add_user_next(struct pac_req_ctx *pr_ctx)
+{
+ int ret;
+ struct tevent_req *req;
+ struct dom_sid *my_dom_sid;
+
+ ret = save_pac_user(pr_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("save_pac_user failed.\n"));
+ goto done;
+ }
+
+ ret = get_my_domain_sid(pr_ctx->pac_ctx, pr_ctx->dom, &my_dom_sid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_my_domain_sid failed.\n"));
+ goto done;
+ }
+
+ ret = get_gids_from_pac(pr_ctx, pr_ctx->pac_ctx->range_map, my_dom_sid,
+ pr_ctx->logon_info, &pr_ctx->gid_count,
+ &pr_ctx->gids);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_gids_from_pac failed.\n"));
+ goto done;
+ }
+
+ req = pac_save_memberships_send(pr_ctx);
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(req, pac_save_memberships_done, pr_ctx);
+
+ ret = EAGAIN;
+
+done:
+ return ret;
+}
+
+static errno_t save_pac_user(struct pac_req_ctx *pr_ctx)
+{
+ struct sysdb_ctx *sysdb;
+ int ret;
+ const char *attrs[] = {SYSDB_NAME, SYSDB_UIDNUM, SYSDB_GIDNUM, NULL};
+ struct ldb_message *msg;
+ struct passwd *pwd = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ sysdb = pr_ctx->dom->sysdb;
+ if (sysdb == NULL) {
+ ret = EINVAL;
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Fatal: Sysdb CTX not found for this domain!\n"));
+ goto done;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n"));
+ goto done;
+ }
+
+ ret = sysdb_search_user_by_name(tmp_ctx, sysdb, pr_ctx->user_name, attrs,
+ &msg);
+ if (ret == EOK) {
+ /* TODO: check id uid and gid are equal. */
+ } else if (ret == ENOENT) {
+ ret = get_pwd_from_pac(tmp_ctx, pr_ctx->pac_ctx, pr_ctx->dom,
+ pr_ctx->logon_info, &pwd);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_pwd_from_pac failed.\n"));
+ goto done;
+ }
+
+ ret = sysdb_store_user(sysdb, pwd->pw_name, NULL,
+ pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos,
+ pwd->pw_dir,
+ pwd->pw_shell, NULL, NULL,
+ pr_ctx->dom->user_timeout, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_store_user failed [%d][%s].\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_user_by_name failed.\n"));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+struct pac_save_memberships_state {
+ int gid_iter;
+ struct ldb_dn *user_dn;
+
+ struct pac_req_ctx *pr_ctx;
+ struct sss_domain_info *group_dom;
+};
+
+struct tevent_req *pac_save_memberships_send(struct pac_req_ctx *pr_ctx)
+{
+ struct pac_save_memberships_state *state;
+ struct sss_domain_info *dom = pr_ctx->dom;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(pr_ctx, &state, struct pac_save_memberships_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->gid_iter = 0;
+ state->user_dn = sysdb_user_dn(dom->sysdb, state, dom->name,
+ pr_ctx->user_name);
+ if (state->user_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ state->pr_ctx = pr_ctx;
+
+ /* Remote users are members of local groups */
+ if (pr_ctx->dom->parent != NULL) {
+ state->group_dom = pr_ctx->dom->parent;
+ } else {
+ state->group_dom = pr_ctx->dom;
+ }
+
+ ret = pac_save_memberships_next(req);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, pr_ctx->cctx->ev);
+ }
+
+done:
+ if (ret != EOK && ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, pr_ctx->cctx->ev);
+ }
+
+ return req;
+}
+
+static errno_t pac_save_memberships_next(struct tevent_req *req)
+{
+ errno_t ret;
+ uint32_t gid;
+ struct tevent_req *subreq;
+ struct pac_save_memberships_state *state;
+ struct pac_req_ctx *pr_ctx;
+
+ state = tevent_req_data(req, struct pac_save_memberships_state);
+ pr_ctx = state->pr_ctx;
+
+ while (state->gid_iter < pr_ctx->gid_count) {
+ gid = pr_ctx->gids[state->gid_iter];
+
+ ret = pac_store_membership(state->pr_ctx, state->group_dom->sysdb,
+ state->user_dn, state->gid_iter);
+ if (ret == EOK) {
+ state->gid_iter++;
+ continue;
+ } else if (ret == ENOENT) {
+ subreq = sss_dp_get_account_send(state, pr_ctx->cctx->rctx,
+ state->group_dom, true,
+ SSS_DP_GROUP, NULL,
+ gid, NULL);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(subreq, pac_get_group_done, req);
+
+ return EAGAIN;
+ } else {
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ return ret;
+}
+
+static void pac_get_group_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct pac_save_memberships_state *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct pac_save_memberships_state);
+
+ errno_t ret;
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ char *err_msg;
+
+ ret = sss_dp_get_account_recv(req, subreq,
+ &err_maj, &err_min,
+ &err_msg);
+ talloc_zfree(subreq);
+ talloc_zfree(err_msg);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = pac_store_membership(state->pr_ctx, state->group_dom->sysdb,
+ state->user_dn, state->gid_iter);
+ if (ret != EOK) {
+ goto error;
+ }
+ state->gid_iter++;
+
+ ret = pac_save_memberships_next(req);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else if (ret != EAGAIN) {
+ goto error;
+ }
+
+ return;
+
+error:
+ tevent_req_error(req, ret);
+}
+
+static errno_t
+pac_store_membership(struct pac_req_ctx *pr_ctx,
+ struct sysdb_ctx *group_sysdb,
+ struct ldb_dn *user_dn,
+ int gid_iter)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *group_name;
+ struct sysdb_attrs *group_attrs;
+ struct ldb_message *group;
+ uint32_t gid;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ gid = pr_ctx->gids[gid_iter];
+
+ ret = sysdb_search_group_by_gid(tmp_ctx, group_sysdb,
+ gid, NULL, &group);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ group_name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
+ if (group_name == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ group_attrs = talloc_zero(tmp_ctx, struct sysdb_attrs);
+ if (group_attrs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ group_attrs->num = 1;
+ group_attrs->a = ldb_msg_find_element(group, SYSDB_MEMBER);
+ if (group_attrs->a == NULL) {
+ group_attrs->a = talloc_zero(group_attrs, struct ldb_message_element);
+ if (group_attrs->a == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ group_attrs->a[0].name = talloc_strdup(group_attrs->a, SYSDB_MEMBER);
+ if (group_attrs->a[0].name == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = sysdb_attrs_add_string(group_attrs, SYSDB_MEMBER,
+ ldb_dn_get_linearized(user_dn));
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sysdb_store_group(group_sysdb, group_name, gid,
+ group_attrs, pr_ctx->dom->group_timeout, 0);
+ if (ret != EOK) {
+ goto done;
+ }
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t pac_save_memberships_recv(struct tevent_req *subreq)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(subreq);
+
+ return EOK;
+}
+
+static void pac_save_memberships_done(struct tevent_req *req)
+{
+ struct pac_req_ctx *pr_ctx = tevent_req_callback_data(req, struct pac_req_ctx);
+ struct cli_ctx *cctx = pr_ctx->cctx;
+ errno_t ret;
+
+ ret = pac_save_memberships_recv(req);
+ talloc_zfree(req);
+
+ talloc_free(pr_ctx);
+ pac_cmd_done(cctx, ret);
+}
struct cli_protocol_version *register_cli_protocol_version(void)
{
@@ -37,6 +505,7 @@ struct cli_protocol_version *register_cli_protocol_version(void)
static struct sss_cmd_table pac_cmds[] = {
{SSS_GET_VERSION, sss_cmd_get_version},
+ {SSS_PAC_ADD_PAC_USER, pac_add_pac_user},
{SSS_CLI_NULL, NULL}
};