From 033f0935afbb5c818ea3e285ab1b452f51a72287 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 18 May 2011 13:28:17 +0200 Subject: [PATCH 4/6] Add server-side pac support --- src/responder/pac/pacsrv.c | 2 +- src/responder/pac/pacsrv_cmd.c | 248 ++++++++++++++++++++++++++++++++++++++++ src/sss_client/sss_cli.h | 3 + 3 files changed, 252 insertions(+), 1 deletions(-) diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c index d308665..b67f2f0 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 42ff3f8..18394fc 100644 --- a/src/responder/pac/pacsrv_cmd.c +++ b/src/responder/pac/pacsrv_cmd.c @@ -24,6 +24,253 @@ #include "confdb/confdb.h" #include "db/sysdb.h" +#include +#include + +#include "gen_ndr/krb5pac.h" +#include "gen_ndr/ndr_krb5pac.h" + +#define PAC_USER_OFFSET 200000 +#define PAC_HOME_PATH "/home/" +#define PAC_DEFAULT_SHELL "/bin/bash" + +static errno_t pac_cmd_done(struct cli_ctx *cctx, int cmd_ret) +{ + int ret; + + ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + DEBUG(1, ("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; +} + +static errno_t domsid_rid_to_uid(struct dom_sid2 *domsid, uint32_t rid, + uid_t *uid) +{ + /* Replace with a proper mapping */ + *uid = (uid_t) rid + PAC_USER_OFFSET; + return EOK; +} + +static errno_t domsid_rid_to_gid(struct dom_sid2 *domsid, uint32_t rid, + gid_t *gid) +{ + /* Replace with a proper mapping */ + *gid = (gid_t) rid + PAC_USER_OFFSET; + return EOK; +} + +static errno_t get_data_from_pac(TALLOC_CTX *mem_ctx, + uint8_t *pac_blob, size_t pac_len, + struct passwd **_pwd, char **domain) +{ + DATA_BLOB blob; + struct ndr_pull *ndr_pull; + struct PAC_DATA *pac_data; + enum ndr_err_code ndr_err; + struct passwd *pwd = NULL; + size_t c; + struct netr_SamBaseInfo *base_info; + int ret; + + blob.data = pac_blob; + blob.length = pac_len; + + ndr_pull = ndr_pull_init_blob(&blob, mem_ctx); + if (ndr_pull == NULL) { + DEBUG(1, ("ndr_pull_init_blob failed.\n")); + return ENOMEM; + } + ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; /* FIXME: is this really needed ? */ + + pac_data = talloc_zero(mem_ctx, struct PAC_DATA); + if (pac_data == NULL) { + DEBUG(1, ("talloc_zero failed.\n")); + return EOK; + return ENOMEM; + } + + ndr_err = ndr_pull_PAC_DATA(ndr_pull, NDR_SCALARS|NDR_BUFFERS, pac_data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1, ("ndr_pull_PAC_DATA failed [%d]\n", ndr_err)); + return EBADMSG; + } + + pwd = talloc_zero(mem_ctx, struct passwd); + if (pwd == NULL) { + DEBUG(1, ("talloc_zero failed.\n")); + return ENOMEM; + } + + for(c = 0; c < pac_data->num_buffers; c++) { + if (pac_data->buffers[c].type == PAC_TYPE_LOGON_INFO) { + base_info = &pac_data->buffers[c].info->logon_info.info->info3.base; + + if (base_info->account_name.size != 0) { + pwd->pw_name = talloc_strdup(pwd, + base_info->account_name.string); + if (pwd->pw_name == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + } else { + DEBUG(1, ("Missing account name in PAC.\n")); + ret = EINVAL; + goto done; + } + + if (base_info->rid > 0) { + ret = domsid_rid_to_uid(base_info->domain_sid, + base_info->rid, + &pwd->pw_uid); + if (ret != EOK) { + DEBUG(1, ("domsid_rid_to_uid failed.\n")); + goto done; + } + } else { + DEBUG(1, ("Missing user RID in PAC.\n")); + ret = EINVAL; + goto done; + } + + if (base_info->primary_gid > 0) { + ret = domsid_rid_to_gid(base_info->domain_sid, + base_info->primary_gid, + &pwd->pw_gid); + if (ret != EOK) { + DEBUG(1, ("domsid_rid_to_gid failed.\n")); + goto done; + } + } else { + DEBUG(1, ("Missing primary GID in PAC.\n")); + ret = EINVAL; + goto done; + } + + if (base_info->full_name.size != 0) { + pwd->pw_gecos = talloc_strdup(pwd, base_info->full_name.string); + } else { + DEBUG(1, ("Missing full name in PAC using account name for gecos.\n")); + pwd->pw_gecos = talloc_strdup(pwd, + base_info->account_name.string); + } + if (pwd->pw_gecos == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + + pwd->pw_dir = talloc_asprintf(mem_ctx, PAC_HOME_PATH"%s", + base_info->account_name.string); + if (pwd->pw_dir == NULL) { + DEBUG(1, ("talloc_asprintf failed.\n")); + ret = ENOMEM; + goto done; + } + + pwd->pw_shell = talloc_strdup(pwd, PAC_DEFAULT_SHELL); + if (pwd->pw_shell == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + + *domain = talloc_strdup(mem_ctx, base_info->domain.string); + if (*domain == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } + + *_pwd = pwd; + + return EOK; + } + } + + ret = EINVAL; + +done: + talloc_free(pwd); + return ret; +} + + +static errno_t pac_add_pac_user(struct cli_ctx *cctx) +{ + TALLOC_CTX *tmp_ctx = NULL; + int ret; + struct sysdb_ctx *sysdb; + char *domain_name; + struct sss_domain_info *dom = NULL; + struct passwd *pwd; + uint8_t *body; + size_t blen; + + sss_packet_get_body(cctx->creq->in, &body, &blen); + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(1, ("talloc_new failed.\n")); + return ENOMEM; + } + + ret = get_data_from_pac(tmp_ctx, body, blen, &pwd, &domain_name); + if (ret != EOK) { + DEBUG(1, ("get_pwd_from_pac failed.\n")); + goto done; + } + + for (dom = cctx->rctx->domains; dom; dom = dom->next) { + if (strcasecmp(dom->provider, domain_name) == 0) break; + } + if (dom == NULL) { + /* TODO: Maybe remove this fallback if sssd can handle sub-domains */ + DEBUG(1, ("Domain [%s] not found, trying local domain.\n", domain_name)); + for (dom = cctx->rctx->domains; dom; dom = dom->next) { + if (strcasecmp(dom->provider, "local") == 0) break; + } + if (dom == NULL) { + DEBUG(1, ("No local domain found.\n")); + ret = ENOENT; + goto done; + } + + /* The local domain is an mpg domain, gid will be set automatically + * and has to be zero */ + pwd->pw_gid = 0; + } + + + ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, dom, &sysdb); + if (ret != EOK) { + DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); + goto done; + } + + ret = sysdb_store_user(tmp_ctx, sysdb, dom, pwd->pw_name, NULL, + pwd->pw_uid, pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, + pwd->pw_shell, NULL, NULL, 0); + if (ret != EOK) { + DEBUG(1, ("sysdb_store_user failed [%d][%s].\n", ret, strerror(ret))); + goto done; + } + +done: + talloc_free(tmp_ctx); + + return pac_cmd_done(cctx, ret); +} + struct cli_protocol_version *register_cli_protocol_version(void) { static struct cli_protocol_version pac_cli_protocol_version[] = { @@ -36,6 +283,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 7c0ec11..c5751fd 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -144,6 +144,9 @@ enum sss_cli_command { SSS_NSS_ENDSPENT = 0x00B5, #endif +/* PAC responder calls */ + SSS_PAC_ADD_PAC_USER = 0x00E1, + /* PAM related calls */ SSS_PAM_AUTHENTICATE = 0x00F1, /**< see pam_sm_authenticate(3) for * details. -- 1.7.5.2