summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Reichl <preichl@redhat.com>2014-09-25 14:52:31 +0100
committerJakub Hrozek <jhrozek@redhat.com>2014-09-29 18:27:07 +0200
commit830ded27453015080a54d6ba85fd4999ee7e9af1 (patch)
tree2dcdecd4d211c25e7e1dd909e062e534348227db
parentcb7644495e76ffa3e19ba10efb4a0f5f3817ba33 (diff)
downloadsssd-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>
-rw-r--r--src/confdb/confdb.h2
-rw-r--r--src/config/SSSDConfig/__init__.py.in2
-rw-r--r--src/config/etc/sssd.api.conf2
-rw-r--r--src/man/sssd.conf.5.xml50
-rw-r--r--src/responder/pam/pamsrv.c94
-rw-r--r--src/responder/pam/pamsrv.h7
-rw-r--r--src/responder/pam/pamsrv_cmd.c80
-rw-r--r--src/util/domain_info_utils.c60
-rw-r--r--src/util/util.h5
9 files changed, 299 insertions, 3 deletions
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 1697c69f0..720b7dc1c 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -111,6 +111,8 @@
#define CONFDB_PAM_VERBOSITY "pam_verbosity"
#define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
#define CONFDB_PAM_PWD_EXPIRATION_WARNING "pam_pwd_expiration_warning"
+#define CONFDB_PAM_TRUSTED_USERS "pam_trusted_users"
+#define CONFDB_PAM_PUBLIC_DOMAINS "pam_public_domains"
/* SUDO */
#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 9a49b91b9..ee48094d0 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -82,6 +82,8 @@ option_strings = {
'pam_verbosity' : _('What kind of messages are displayed to the user during authentication'),
'pam_id_timeout' : _('How many seconds to keep identity information cached for PAM requests'),
'pam_pwd_expiration_warning' : _('How many days before password expiration a warning should be displayed'),
+ 'pam_trusted_users' : _('List of trusted uids or user\'s name'),
+ 'pam_public_domains' : _('List of domains accessible even for untrusted users.'),
# [sudo]
'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'),
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 52629ded4..c47ce348c 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -55,6 +55,8 @@ pam_verbosity = int, None, false
pam_id_timeout = int, None, false
pam_pwd_expiration_warning = int, None, false
get_domains_timeout = int, None, false
+pam_trusted_users = str, None, false
+pam_public_domains = str, None, false
[sudo]
# sudo service
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index ad091e46e..d57341661 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -836,6 +836,56 @@ fallback_homedir = /home/%u
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>pam_trusted_users (string)</term>
+ <listitem>
+ <para>
+ Specifies the comma-separated list of UID values or
+ user names that are allowed to access the PAM
+ responder. User names are resolved to UIDs at
+ startup.
+ </para>
+ <para>
+ Default: all (All users are allowed to access
+ the PAM responder)
+ </para>
+ <para>
+ Please note that UID 0 is always allowed to access
+ the PAM responder even in case it is not in the
+ pam_trusted_users list.
+ </para>
+ <para>
+ Also please note that if there is a user name in
+ pam_trusted_users list which fails to be resolved
+ it will cause that SSSD will not be started.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>pam_public_domains (string)</term>
+ <listitem>
+ <para>
+ Specifies the comma-separated list of domain names
+ that are accessible even to untrusted users.
+ </para>
+ <para>
+ Two special values for pam_public_domains option
+ are defined:
+ </para>
+ <para>
+ all (Untrusted users are allowed to access
+ all domains in PAM responder.)
+ </para>
+ <para>
+ none (Untrusted users are not allowed to access
+ any domains PAM in responder.)
+ </para>
+ <para>
+ Default: none
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
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);
}
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 8933f5235..520feb36d 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -569,3 +569,63 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+/* Save domain names, do not descend. */
+errno_t get_dom_names(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *start_dom,
+ char ***_dom_names,
+ int *_dom_names_count)
+{
+ struct sss_domain_info *dom;
+ TALLOC_CTX *tmp_ctx;
+ char **dom_names;
+ size_t count, i;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* get count of domains*/
+ count = 0;
+ dom = start_dom;
+ while (dom) {
+ count++;
+ dom = get_next_domain(dom, false);
+ }
+
+ dom_names = talloc_array(tmp_ctx, char*, count);
+ if (dom_names == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* copy names */
+ i = 0;
+ dom = start_dom;
+ while (dom) {
+ dom_names[i] = talloc_strdup(dom_names, dom->name);
+ if (dom_names[i] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ dom = get_next_domain(dom, false);
+ i++;
+ }
+
+ if (_dom_names != NULL ) {
+ *_dom_names = talloc_steal(mem_ctx, dom_names);
+ }
+
+ if (_dom_names_count != NULL ) {
+ *_dom_names_count = count;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index d3b746be3..df82b3fa4 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -547,6 +547,11 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
errno_t sss_write_domain_mappings(struct sss_domain_info *domain,
bool add_capaths);
+errno_t get_dom_names(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *start_dom,
+ char ***_dom_names,
+ int *_dom_names_count);
+
/* from util_lock.c */
errno_t sss_br_lock_file(int fd, size_t start, size_t len,
int num_tries, useconds_t wait);