summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--src/confdb/confdb.h6
-rw-r--r--src/config/etc/sssd.api.conf2
-rw-r--r--src/man/sssd.conf.5.xml24
-rw-r--r--src/providers/data_provider.h1
-rw-r--r--src/responder/common/responder.h11
-rw-r--r--src/responder/common/responder_common.c8
-rw-r--r--src/responder/common/responder_get_domains.c340
8 files changed, 394 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 5a14b6fc..303264c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -246,7 +246,8 @@ SSSD_RESPONDER_OBJ = \
src/responder/common/responder_cmd.c \
src/responder/common/responder_common.c \
src/responder/common/responder_dp.c \
- src/responder/common/responder_packet.c
+ src/responder/common/responder_packet.c \
+ src/responder/common/responder_get_domains.c
SSSD_TOOLS_OBJ = \
src/tools/sss_sync_ops.c \
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index d0b383e5..18f6c1fd 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -68,6 +68,9 @@
#define CONFDB_MONITOR_TRY_INOTIFY "try_inotify"
#define CONFDB_MONITOR_KRB5_RCACHEDIR "krb5_rcache_dir"
+/* Responders */
+#define CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT "get_domains_timeout"
+
/* NSS */
#define CONFDB_NSS_CONF_ENTRY "config/nss"
#define CONFDB_NSS_ENUM_CACHE_TIMEOUT "enum_cache_timeout"
@@ -193,9 +196,12 @@ struct sss_domain_info {
struct sysdb_ctx *sysdb;
+ struct sss_domain_info **subdomains;
+ uint32_t subdomain_count;
struct sss_domain_info *parent;
char *flat_name;
char *domain_id;
+ struct timeval subdomains_last_checked;
struct sss_domain_info *next;
};
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 7b238ffd..65c0fcef 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -35,6 +35,7 @@ override_homedir = str, None, false
allowed_shells = list, str, false
vetoed_shells = list, str, false
shell_fallback = str, None, false
+get_domains_timeout = int, None, false
[pam]
# Authentication service
@@ -44,6 +45,7 @@ offline_failed_login_delay = int, None, false
pam_verbosity = int, None, false
pam_id_timeout = int, None, false
pam_pwd_expiration_warning = int, None, false
+get_domains_timeout = int, None, false
[sudo]
# sudo service
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 5743b89d..32966e8b 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -498,6 +498,18 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>get_domains_timeout (int)</term>
+ <listitem>
+ <para>
+ Specifies time in seconds for which the list of
+ subdomains will be considered valid.
+ </para>
+ <para>
+ Default: 60
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<refsect2 id='PAM'>
@@ -624,6 +636,18 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>get_domains_timeout (int)</term>
+ <listitem>
+ <para>
+ Specifies time in seconds for which the list of
+ subdomains will be considered valid.
+ </para>
+ <para>
+ Default: 60
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index d119c2b5..fb3ad041 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -53,6 +53,7 @@
#define DP_METHOD_SUDOHANDLER "sudoHandler"
#define DP_METHOD_AUTOFSHANDLER "autofsHandler"
#define DP_METHOD_HOSTHANDLER "hostHandler"
+#define DP_METHOD_GETDOMAINS "getDomains"
/**
* @defgroup pamHandler PAM DBUS request
* @ingroup sss_pam
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 1309c14d..f331fee3 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -86,6 +86,7 @@ struct resp_ctx {
struct be_conn *be_conns;
struct sss_domain_info *domains;
+ int domains_timeout;
struct sysdb_ctx_list *db_list;
struct sss_cmd_table *sss_cmds;
@@ -96,6 +97,8 @@ struct resp_ctx {
hash_table_t *dp_request_table;
+ struct timeval get_domains_last_call;
+
void *pvt_ctx;
};
@@ -273,4 +276,12 @@ bool sss_utf8_check(const uint8_t *s, size_t n);
void responder_set_fd_limit(rlim_t fd_limit);
+#define GET_DOMAINS_DEFAULT_TIMEOUT 60
+
+struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ bool force,
+ const char *hint);
+
+errno_t sss_dp_get_domains_recv(struct tevent_req *req);
#endif /* __SSS_RESPONDER_H__ */
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 52b271b9..66148387 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -545,6 +545,14 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
rctx->priv_sock_name = sss_priv_pipe_name;
rctx->confdb_service_path = confdb_service_path;
+ ret = confdb_get_int(rctx->cdb, rctx->confdb_service_path,
+ CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT,
+ GET_DOMAINS_DEFAULT_TIMEOUT, &rctx->domains_timeout);
+ if (rctx->domains_timeout < 0) {
+ DEBUG(SSSDBG_CONF_SETTINGS, ("timeout can't be set to negative value, setting default\n"));
+ rctx->domains_timeout = GET_DOMAINS_DEFAULT_TIMEOUT;
+ }
+
ret = confdb_get_domains(rctx->cdb, &rctx->domains);
if (ret != EOK) {
DEBUG(0, ("fatal error setting up domain map\n"));
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
new file mode 100644
index 00000000..702593f6
--- /dev/null
+++ b/src/responder/common/responder_get_domains.c
@@ -0,0 +1,340 @@
+/*
+ Authors:
+ Jan Zeleny <jzeleny@redhat.com>
+
+ Copyright (C) 2011 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "responder/common/responder.h"
+#include "providers/data_provider.h"
+#include "db/sysdb.h"
+
+struct sss_dp_domains_info {
+ struct resp_ctx *rctx;
+ struct sss_domain_info *dom;
+ const char *hint;
+ bool force;
+
+ struct sss_dp_req_state *state;
+};
+
+static DBusMessage *sss_dp_get_domains_msg(void *pvt);
+static errno_t get_domains_next(struct tevent_req *req);
+static void sss_dp_get_domains_callback(struct tevent_req *subreq);
+
+static errno_t get_domains_done(struct tevent_req *req);
+static errno_t check_last_request(struct resp_ctx *rctx, const char *hint);
+
+struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ bool force,
+ const char *hint)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct sss_dp_domains_info *info;
+
+ req = tevent_req_create(mem_ctx, &info, struct sss_dp_domains_info);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (rctx->domains == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No domains configured.\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (!force) {
+ ret = check_last_request(rctx, hint);
+
+ if (ret == EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Last call was too recent, nothing to do!\n"));
+ goto done;
+ } else if (ret != EAGAIN) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("check_domain_request failed with [%d][%s]\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ }
+
+ info->rctx = rctx;
+ info->dom = rctx->domains;
+ info->force = force;
+ if (hint != NULL) {
+ info->hint = hint;
+ } else {
+ info->hint = talloc_strdup(info, "");
+ if (info->hint == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = get_domains_next(req);
+ if (ret == EAGAIN) {
+ ret = EOK;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, rctx->ev);
+ }
+
+ return req;
+}
+
+static errno_t get_domains_next(struct tevent_req *req)
+{
+ struct sss_dp_domains_info *info;
+ struct tevent_req *subreq;
+ struct sss_dp_req_state *state;
+ errno_t ret;
+ char *key;
+
+ info = tevent_req_data(req, struct sss_dp_domains_info);
+ if (info->dom == NULL) {
+ /* Note that tevent_req_post() is not here. This will
+ * influence the program only in case that this will
+ * be the first call of the function (i.e. there is no
+ * problem when this is called from get_domains_done(),
+ * it is in fact required). In case no domains are in
+ * the state, it should be treated as an error one level
+ * above.
+ */
+ tevent_req_done(req);
+ return EOK;
+ }
+
+ subreq = tevent_req_create(info, &state, struct sss_dp_req_state);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ key = talloc_asprintf(info, "domains@%s", info->dom->name);
+ if (key == NULL) {
+ talloc_free(subreq);
+ return ENOMEM;
+ }
+
+ ret = sss_dp_issue_request(info, info->rctx, key, info->dom,
+ sss_dp_get_domains_msg, info, subreq);
+ talloc_free(key);
+ if (ret != EOK) {
+ talloc_free(subreq);
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, sss_dp_get_domains_callback, req);
+
+ return EAGAIN;
+}
+
+static DBusMessage *
+sss_dp_get_domains_msg(void *pvt)
+{
+ struct sss_dp_domains_info *info;
+ DBusMessage *msg = NULL;
+ dbus_bool_t dbret;
+
+ info = talloc_get_type(pvt, struct sss_dp_domains_info);
+
+ msg = dbus_message_new_method_call(NULL,
+ DP_PATH,
+ DP_INTERFACE,
+ DP_METHOD_GETDOMAINS);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory?!\n"));
+ return NULL;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Sending get domains request for [%s][%sforced][%s]\n",
+ info->dom->name, info->force ? "" : "not ", info->hint));
+
+ /* Send the hint argument to provider as well. This will
+ * be useful for some cases of transitional trust where
+ * the server might not know all trusted domains
+ */
+ dbret = dbus_message_append_args(msg,
+ DBUS_TYPE_BOOLEAN, &info->force,
+ DBUS_TYPE_STRING, &info->hint,
+ DBUS_TYPE_INVALID);
+ if (!dbret) {
+ DEBUG(SSSDBG_OP_FAILURE ,("Failed to build message\n"));
+ dbus_message_unref(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+static void sss_dp_get_domains_callback(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
+ struct sss_dp_domains_info *info = tevent_req_data(req, struct sss_dp_domains_info);
+ errno_t ret;
+ dbus_uint16_t dp_err;
+ dbus_uint32_t dp_ret;
+ char *err_msg;
+
+ /* TODO: handle errors better */
+ ret = sss_dp_req_recv(info, subreq, &dp_err, &dp_ret, &err_msg);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ ret = get_domains_done(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("get_domains_done failed, "
+ "trying next domain.\n"));
+ goto fail;
+ }
+
+ info->dom = info->dom->next;
+ ret = get_domains_next(req);
+ if (ret != EOK && ret != EAGAIN) {
+ goto fail;
+ }
+
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static errno_t get_domains_done(struct tevent_req *req)
+{
+ int ret;
+ size_t c;
+ struct sss_dp_domains_info *state;
+ struct sss_domain_info *domain;
+ struct sss_domain_info **new_sd_list = NULL;
+ size_t subdomain_count;
+ struct subdomain_info **subdomains;
+
+ state = tevent_req_data(req, struct sss_dp_domains_info);
+ domain = state->dom;
+
+ /* Retrieve all subdomains of this domain from sysdb
+ * and create their struct sss_domain_info representations
+ */
+ ret = sysdb_get_subdomains(domain, domain->sysdb,
+ &subdomain_count, &subdomains);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FUNC_DATA, ("sysdb_get_subdomains failed.\n"));
+ goto done;
+ }
+
+ new_sd_list = talloc_zero_array(domain, struct sss_domain_info *,
+ subdomain_count);
+ if (new_sd_list == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ for (c = 0; c < subdomain_count; c++) {
+ DEBUG(SSSDBG_FUNC_DATA, ("Adding subdomain [%s] to the domain [%s]!\n",
+ subdomains[c]->name, domain->name));
+ new_sd_list[c] = new_subdomain(new_sd_list, domain,
+ subdomains[c]->name,
+ subdomains[c]->flat_name,
+ subdomains[c]->id);
+ if (new_sd_list[c] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ /* Link all subdomains into single-linked list
+ * (the list is used when processing all domains)
+ */
+ while (c > 1) {
+ new_sd_list[c-1]->next = new_sd_list[c];
+ --c;
+ }
+
+ errno = 0;
+ ret = gettimeofday(&domain->subdomains_last_checked, NULL);
+ if (ret == -1) {
+ ret = errno;
+ goto done;
+ }
+
+ domain->subdomain_count = subdomain_count;
+ talloc_zfree(domain->subdomains);
+ domain->subdomains = new_sd_list;
+ new_sd_list = NULL;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Failed to update sub-domains "
+ "of domain [%s].\n", domain->name));
+ talloc_free(new_sd_list);
+ }
+
+ return ret;
+}
+
+errno_t sss_dp_get_domains_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+static errno_t check_last_request(struct resp_ctx *rctx, const char *hint)
+{
+ struct sss_domain_info *dom;
+ time_t now = time(NULL);
+ time_t diff;
+ int i;
+
+ diff = now-rctx->get_domains_last_call.tv_sec;
+ if (diff >= rctx->domains_timeout) {
+ /* Timeout, expired, fetch domains again */
+ return EAGAIN;
+ }
+
+ if (hint != NULL) {
+ dom = rctx->domains;
+ while (dom) {
+ for (i = 0; i< dom->subdomain_count; i++) {
+ if (strcasecmp(dom->subdomains[i]->name, hint) == 0) {
+ diff = now-dom->subdomains_last_checked.tv_sec;
+ if (diff >= rctx->domains_timeout) {
+ /* Timeout, expired, fetch domains again */
+ return EAGAIN;
+ }
+ /* Skip the rest of this domain, but check other domains
+ * perhaps this subdomain will be also a part of another
+ * domain where it will need refreshing
+ */
+ break;
+ }
+ }
+ dom = dom->next;
+ }
+ }
+
+ return EOK;
+}