diff options
author | Pavel Reichl <preichl@redhat.com> | 2014-09-25 14:52:31 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2014-09-29 18:27:07 +0200 |
commit | 830ded27453015080a54d6ba85fd4999ee7e9af1 (patch) | |
tree | 2dcdecd4d211c25e7e1dd909e062e534348227db /src/responder/pam | |
parent | cb7644495e76ffa3e19ba10efb4a0f5f3817ba33 (diff) | |
download | sssd-830ded27453015080a54d6ba85fd4999ee7e9af1.tar.gz sssd-830ded27453015080a54d6ba85fd4999ee7e9af1.tar.xz sssd-830ded27453015080a54d6ba85fd4999ee7e9af1.zip |
PAM: new options pam_trusted_users & pam_public_domains
pam_public_domains option is a list of numerical UIDs or user names
that are trusted.
pam_public_domains option is a list of domains accessible even for
untrusted users.
Based on:
https://fedorahosted.org/sssd/wiki/DesignDocs/RestrictDomainsInPAM
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/responder/pam')
-rw-r--r-- | src/responder/pam/pamsrv.c | 94 | ||||
-rw-r--r-- | src/responder/pam/pamsrv.h | 7 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 80 |
3 files changed, 178 insertions, 3 deletions
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c index c0841d2bd..428b252ac 100644 --- a/src/responder/pam/pamsrv.c +++ b/src/responder/pam/pamsrv.c @@ -46,6 +46,10 @@ #include "responder/common/responder_sbus.h" #define DEFAULT_PAM_FD_LIMIT 8192 +#define ALL_UIDS_ALLOWED "all" +#define ALL_DOMAIMS_ARE_PUBLIC "all" +#define NO_DOMAIMS_ARE_PUBLIC "none" +#define DEFAULT_ALLOWED_UIDS ALL_UIDS_ALLOWED struct mon_cli_iface monitor_pam_methods = { { &mon_cli_iface_meta, 0 }, @@ -99,6 +103,82 @@ static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void /* pam_shutdown(rctx); */ } +static errno_t get_trusted_uids(struct pam_ctx *pctx) +{ + char *uid_str; + errno_t ret; + + ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx, + CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_TRUSTED_USERS, + DEFAULT_ALLOWED_UIDS, &uid_str); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n"); + goto done; + } + + if (strcmp(uid_str, ALL_UIDS_ALLOWED) == 0) { + DEBUG(SSSDBG_TRACE_FUNC, "All UIDs are allowed.\n"); + pctx->trusted_uids_count = 0; + } else { + ret = csv_string_to_uid_array(pctx->rctx, uid_str, true, + &pctx->trusted_uids_count, + &pctx->trusted_uids); + } + + talloc_free(uid_str); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to set allowed UIDs.\n"); + goto done; + } + +done: + return ret; +} + +static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) +{ + char *domains_str = NULL; + errno_t ret; + + ret = confdb_get_string(pctx->rctx->cdb, pctx->rctx, + CONFDB_PAM_CONF_ENTRY, CONFDB_PAM_PUBLIC_DOMAINS, + NO_DOMAIMS_ARE_PUBLIC, &domains_str); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get allowed UIDs.\n"); + goto done; + } + + if (strcmp(domains_str, ALL_DOMAIMS_ARE_PUBLIC) == 0) { /* all */ + /* copy all domains */ + ret = get_dom_names(mem_ctx, + pctx->rctx->domains, + &pctx->public_domains, + &pctx->public_domains_count); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "get_dom_names failed.\n"); + goto done; + } + } else if (strcmp(domains_str, NO_DOMAIMS_ARE_PUBLIC) == 0) { /* none */ + pctx->public_domains = NULL; + pctx->public_domains_count = 0; + } else { + ret = split_on_separator(mem_ctx, domains_str, ',', true, false, + &pctx->public_domains, + &pctx->public_domains_count); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n", + ret, strerror(ret)); + goto done; + } + } + + ret = EOK; + +done: + talloc_free(domains_str); + return ret; +} + static int pam_process_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb) @@ -136,6 +216,20 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, pctx->rctx = rctx; pctx->rctx->pvt_ctx = pctx; + ret = get_trusted_uids(pctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "get_trusted_uids failed: %d:[%s].\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = get_public_domains(pctx, pctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n", + ret, sss_strerror(ret)); + goto done; + } + /* Enable automatic reconnection to the Data Provider */ /* FIXME: "retries" is too generic, either get it from a global config diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 1e37a77a1..f92e7f7db 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -37,6 +37,13 @@ struct pam_ctx { int neg_timeout; time_t id_timeout; hash_table_t *id_table; + size_t trusted_uids_count; + uid_t *trusted_uids; + bool is_uid_trusted; + + /* List of domains that are accessible even for untrusted users. */ + char **public_domains; + int public_domains_count; }; struct pam_auth_dp_req { diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 561bd3d96..eb6953a74 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -762,6 +762,45 @@ static int pam_auth_req_destructor(struct pam_auth_req *preq) return 0; } +static bool is_uid_trusted(uint32_t uid, + size_t trusted_uids_count, + uid_t *trusted_uids) +{ + size_t i; + + /* root is always trusted */ + if (uid == 0) { + return true; + } + + /* All uids are allowed */ + if (trusted_uids_count == 0) { + return true; + } + + for(i = 0; i < trusted_uids_count; i++) { + if (trusted_uids[i] == uid) { + return true; + } + } + + return false; +} + +static bool is_domain_public(char *name, + char **public_dom_names, + size_t public_dom_names_count) +{ + size_t i; + + for(i=0; i < public_dom_names_count; i++) { + if (strcmp(name, public_dom_names[i]) == 0) { + return true; + } + } + return false; +} + static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) { struct sss_domain_info *dom; @@ -773,6 +812,15 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx); struct tevent_req *req; + pctx->is_uid_trusted = is_uid_trusted(cctx->client_euid, + pctx->trusted_uids_count, + pctx->trusted_uids); + + if (!pctx->is_uid_trusted) { + DEBUG(SSSDBG_MINOR_FAILURE, "uid %"PRIu32" is not trusted.\n", + cctx->client_euid); + } + preq = talloc_zero(cctx, struct pam_auth_req); if (!preq) { return ENOMEM; @@ -813,6 +861,17 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) goto done; } + /* Untrusted users can access only public domains. */ + if (!pctx->is_uid_trusted && + !is_domain_public(pd->domain, pctx->public_domains, + pctx->public_domains_count)) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Untrusted user %"PRIu32" cannot access unpublic domain %s.\n", + cctx->client_euid, pd->domain); + ret = EPERM; + goto done; + } + ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout, preq->domain, pd->user); if (ncret == EEXIST) { @@ -826,6 +885,17 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) dom = get_next_domain(dom, false)) { if (dom->fqnames) continue; + /* Untrusted users can access only public domains. */ + if (!pctx->is_uid_trusted && + !is_domain_public(dom->name, pctx->public_domains, + pctx->public_domains_count)) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Untrusted user %"PRIu32" cannot access unpublic domain %s." + " Trying next domain.\n", + cctx->client_euid, dom->name); + continue; + } + ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout, dom, pd->user); if (ncret == ENOENT) { @@ -920,7 +990,6 @@ done: } static void pam_dp_send_acct_req_done(struct tevent_req *req); - static int pam_check_user_search(struct pam_auth_req *preq) { struct sss_domain_info *dom = preq->domain; @@ -936,9 +1005,14 @@ static int pam_check_user_search(struct pam_auth_req *preq) while (dom) { /* if it is a domainless search, skip domains that require fully - * qualified names instead */ + * qualified names instead, also untrusted users can access only + * public domains */ while (dom && !preq->pd->domain && !preq->pd->name_is_upn - && dom->fqnames) { + && (dom->fqnames || + (!pctx->is_uid_trusted && + !is_domain_public(dom->name, + pctx->public_domains, + pctx->public_domains_count)))) { dom = get_next_domain(dom, false); } |