summaryrefslogtreecommitdiffstats
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
parente3f0014bb64b7e93979948936cf93cf869d3dc44 (diff)
downloadsssd-ee099cd5656b60c7384493b923ddf9af5cf5d4f5.tar.gz
sssd-ee099cd5656b60c7384493b923ddf9af5cf5d4f5.tar.xz
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.
-rw-r--r--src/responder/pac/pacsrv.c2
-rw-r--r--src/responder/pac/pacsrv_cmd.c471
-rw-r--r--src/sss_client/sss_cli.h4
3 files changed, 475 insertions, 2 deletions
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index feee3aeed..b21bb966d 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 892ef8568..1d67657dd 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}
};
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 647d233f6..483b809bf 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -217,6 +217,10 @@ enum sss_cli_command {
SSS_CMD_RENEW = 0x00F8, /**< Renew a credential with a limited
* lifetime, e.g. a Kerberos Ticket
* Granting Ticket (TGT) */
+
+/* PAC responder calls */
+ SSS_PAC_ADD_PAC_USER = 0x0101,
+
};
/**