summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am9
-rw-r--r--src/config/SSSDConfig.py8
-rw-r--r--src/man/sssd-ldap.5.xml101
-rw-r--r--src/providers/ipa/ipa_common.c25
-rw-r--r--src/providers/ipa/ipa_common.h2
-rw-r--r--src/providers/ldap/ldap_common.c106
-rw-r--r--src/providers/ldap/ldap_common.h5
-rw-r--r--src/providers/ldap/ldap_init.c31
-rw-r--r--src/providers/ldap/sdap.c13
-rw-r--r--src/providers/ldap/sdap.h19
-rw-r--r--src/providers/ldap/sdap_async_autofs.c833
-rw-r--r--src/providers/ldap/sdap_autofs.c291
-rw-r--r--src/providers/ldap/sdap_autofs.h47
13 files changed, 1488 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index becc67ba0..97d2bff4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -354,6 +354,7 @@ dist_noinst_HEADERS = \
src/providers/ldap/sdap_sudo_cache.h \
src/providers/ldap/sdap_sudo_timer.h \
src/providers/ldap/sdap_sudo.h \
+ src/providers/ldap/sdap_autofs.h \
src/providers/ldap/sdap_id_op.h \
src/providers/ipa/ipa_common.h \
src/providers/ipa/ipa_access.h \
@@ -997,6 +998,10 @@ libsss_ldap_la_SOURCES += src/providers/ldap/sdap_sudo_cache.c \
src/providers/ldap/sdap_sudo_timer.c \
src/providers/ldap/sdap_sudo.c
endif
+if BUILD_AUTOFS
+libsss_ldap_la_SOURCES += src/providers/ldap/sdap_autofs.c \
+ src/providers/ldap/sdap_async_autofs.c
+endif
libsss_proxy_la_SOURCES = \
src/providers/proxy/proxy_common.c \
@@ -1116,6 +1121,10 @@ libsss_ipa_la_SOURCES += src/providers/ldap/sdap_sudo_cache.c \
src/providers/ldap/sdap_sudo_timer.c \
src/providers/ldap/sdap_sudo.c
endif
+if BUILD_AUTOFS
+libsss_ipa_la_SOURCES += src/providers/ldap/sdap_autofs.c \
+ src/providers/ldap/sdap_async_autofs.c
+endif
krb5_child_SOURCES = \
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index 740ab27fa..c27bade96 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -277,6 +277,14 @@ option_strings = {
'ldap_sudorule_notafter' : _('Sudo rule notafter attribute'),
'ldap_sudorule_order' : _('Sudo rule order attribute'),
+ # [provider/ldap/autofs]
+ 'ldap_autofs_map_object_class' : _('Object class for automounter maps'),
+ 'ldap_autofs_map_name' : _('Automounter map name attribute'),
+ 'ldap_autofs_entry_object_class' : _('Object class for automounter map entries'),
+ 'ldap_autofs_entry_key' : _('Automounter map entry key attribute'),
+ 'ldap_autofs_entry_value' : _('Automounter map entry value attribute'),
+ 'ldap_autofs_search_base' : _('Base DN for automonter map lookups'),
+
# [provider/simple/access]
'simple_allow_users' : _('Comma separated list of allowed users'),
'simple_deny_users' : _('Comma separated list of prohibited users'),
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index fc396d94e..0d4885d24 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1813,6 +1813,85 @@ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com
</para>
</refsect1>
+ <refsect1 id='autofs-options' condition="with_autofs">
+ <title>AUTOFS OPTIONS</title>
+ <para>
+ Please note that the default values correspond to the default
+ schema which is RFC2307.
+ </para>
+ <para>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/experimental.xml" />
+ <variablelist>
+ <varlistentry>
+ <term>ldap_autofs_map_object_class (string)</term>
+ <listitem>
+ <para>
+ The object class of an automount map entry in LDAP.
+ </para>
+ <para>
+ Default: automountMap
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>ldap_autofs_map_name (string)</term>
+ <listitem>
+ <para>
+ The name of an automount map entry in LDAP.
+ </para>
+ <para>
+ Default: ou
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>ldap_autofs_entry_object_class (string)</term>
+ <listitem>
+ <para>
+ The object class of an automount map entry
+ in LDAP.
+ </para>
+ <para>
+ Default: automountMap
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>ldap_autofs_entry_key (string)</term>
+ <listitem>
+ <para>
+ The key of an automount entry in LDAP. The
+ entry usually corresponds to a mount point.
+ </para>
+ <para>
+ Default: cn
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>ldap_autofs_entry_value (string)</term>
+ <listitem>
+ <para>
+ The key of an automount entry in LDAP. The
+ entry usually corresponds to a mount point.
+ </para>
+ <para>
+ Default: automountInformation
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
<refsect1 id='advanced-options'>
<title>ADVANCED OPTIONS</title>
<para>
@@ -1943,6 +2022,28 @@ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com
</listitem>
</varlistentry>
+ <varlistentry condition="with_autofs">
+ <term>ldap_autofs_search_base (string)</term>
+ <listitem>
+ <para>
+ An optional base DN to restrict automounter searches
+ to a specific subtree.
+ </para>
+ <para>
+ See <quote>ldap_search_base</quote> for
+ information about configuring multiple search
+ bases.
+ </para>
+ <para>
+ Default: the value of
+ <emphasis>ldap_search_base</emphasis>
+ </para>
+ <para>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/experimental.xml" />
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect1>
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index e8df5e152..2e6dad8ae 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -65,6 +65,7 @@ struct dp_option ipa_def_ldap_opts[] = {
{ "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_sudo_refresh_enabled", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "ldap_sudo_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+ { "ldap_autofs_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING },
{ "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
{ "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
@@ -478,6 +479,30 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
if (ret != EOK) goto done;
if (NULL == dp_opt_get_string(ipa_opts->id->basic,
+ SDAP_AUTOFS_SEARCH_BASE)) {
+ value = talloc_asprintf(tmpctx, "cn=default,cn=automount,%s", basedn);
+ if (!value) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dp_opt_set_string(ipa_opts->id->basic,
+ SDAP_AUTOFS_SEARCH_BASE,
+ value);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, ("Option %s set to %s\n",
+ ipa_opts->id->basic[SDAP_AUTOFS_SEARCH_BASE].opt_name,
+ dp_opt_get_string(ipa_opts->id->basic,
+ SDAP_AUTOFS_SEARCH_BASE)));
+ }
+ ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id->basic,
+ SDAP_AUTOFS_SEARCH_BASE,
+ &ipa_opts->id->autofs_search_bases);
+
+ if (NULL == dp_opt_get_string(ipa_opts->id->basic,
SDAP_SUDO_SEARCH_BASE)) {
#if 0
ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_SUDO_SEARCH_BASE,
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 5bf1b7c9d..9cbd993f5 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -35,7 +35,7 @@ struct ipa_service {
/* the following defines are used to keep track of the options in the ldap
* module, so that if they change and ipa is not updated correspondingly
* this will trigger a runtime abort error */
-#define IPA_OPTS_BASIC_TEST 59
+#define IPA_OPTS_BASIC_TEST 60
#define IPA_OPTS_SVC_TEST 5
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index cce3c0bcf..3b8e0eeb5 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -28,6 +28,7 @@
#include "providers/krb5/krb5_common.h"
#include "db/sysdb_sudo.h"
#include "db/sysdb_services.h"
+#include "db/sysdb_autofs.h"
#include "util/sss_krb5.h"
#include "util/crypto/sss_crypto.h"
@@ -55,6 +56,7 @@ struct dp_option default_basic_opts[] = {
{ "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_sudo_refresh_enabled", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "ldap_sudo_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+ { "ldap_autofs_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_schema", DP_OPT_STRING, { "rfc2307" }, NULL_STRING },
{ "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
{ "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
@@ -242,6 +244,28 @@ struct sdap_attr_map service_map[] = {
{ "ldap_service_entry_usn", NULL, SYSDB_USN, NULL }
};
+struct sdap_attr_map rfc2307_autofs_mobject_map[] = {
+ { "ldap_autofs_map_object_class", "automountMap", SYSDB_AUTOFS_MAP_OC, NULL },
+ { "ldap_autofs_map_name", "ou", SYSDB_AUTOFS_MAP_NAME, NULL }
+};
+
+struct sdap_attr_map rfc2307_autofs_entry_map[] = {
+ { "ldap_autofs_entry_object_class", "automount", SYSDB_AUTOFS_ENTRY_OC, NULL },
+ { "ldap_autofs_entry_key", "cn", SYSDB_AUTOFS_ENTRY_KEY, NULL },
+ { "ldap_autofs_entry_value", "automountInformation", SYSDB_AUTOFS_ENTRY_VALUE, NULL },
+};
+
+struct sdap_attr_map rfc2307bis_autofs_mobject_map[] = {
+ { "ldap_autofs_map_object_class", "automountMap", SYSDB_AUTOFS_MAP_OC, NULL },
+ { "ldap_autofs_map_name", "automountMapName", SYSDB_AUTOFS_MAP_NAME, NULL }
+};
+
+struct sdap_attr_map rfc2307bis_autofs_entry_map[] = {
+ { "ldap_autofs_entry_object_class", "automount", SYSDB_AUTOFS_ENTRY_OC, NULL },
+ { "ldap_autofs_entry_key", "automountKey", SYSDB_AUTOFS_ENTRY_KEY, NULL },
+ { "ldap_autofs_entry_value", "automountInformation", SYSDB_AUTOFS_ENTRY_VALUE, NULL },
+};
+
int ldap_get_options(TALLOC_CTX *memctx,
struct confdb_ctx *cdb,
const char *conf_path,
@@ -595,6 +619,86 @@ int ldap_get_sudo_options(TALLOC_CTX *memctx,
return EOK;
}
+int ldap_get_autofs_options(TALLOC_CTX *memctx,
+ struct confdb_ctx *cdb,
+ const char *conf_path,
+ struct sdap_options *opts)
+{
+ const char *search_base;
+ struct sdap_attr_map *default_entry_map;
+ struct sdap_attr_map *default_mobject_map;
+ int ret;
+
+ /* search base */
+ search_base = dp_opt_get_string(opts->basic, SDAP_SEARCH_BASE);
+ if (search_base != NULL) {
+ /* set autofs search bases if they are not */
+ if (dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE) == NULL) {
+ ret = dp_opt_set_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE,
+ search_base);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not set autofs search base"
+ "to default value\n"));
+ return ret;
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, ("Option %s set to %s\n",
+ opts->basic[SDAP_AUTOFS_SEARCH_BASE].opt_name,
+ dp_opt_get_string(opts->basic, SDAP_AUTOFS_SEARCH_BASE)));
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, ("Error: no autofs search base set\n"));
+ return ENOENT;
+ }
+
+ ret = sdap_parse_search_base(opts, opts->basic,
+ SDAP_AUTOFS_SEARCH_BASE,
+ &opts->autofs_search_bases);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not parse autofs search base\n"));
+ return ret;
+ }
+
+ /* attribute maps */
+ switch (opts->schema_type) {
+ case SDAP_SCHEMA_RFC2307:
+ default_mobject_map = rfc2307_autofs_mobject_map;
+ default_entry_map = rfc2307_autofs_entry_map;
+ break;
+ case SDAP_SCHEMA_RFC2307BIS:
+ case SDAP_SCHEMA_IPA_V1:
+ case SDAP_SCHEMA_AD:
+ default_mobject_map = rfc2307bis_autofs_mobject_map;
+ default_entry_map = rfc2307bis_autofs_entry_map;
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown LDAP schema!\n"));
+ return EINVAL;
+ }
+
+ ret = sdap_get_map(opts, cdb, conf_path,
+ default_mobject_map,
+ SDAP_OPTS_AUTOFS_MAP,
+ &opts->autofs_mobject_map);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not get autofs map object attribute map\n"));
+ return ret;
+ }
+
+ ret = sdap_get_map(opts, cdb, conf_path,
+ default_entry_map,
+ SDAP_OPTS_AUTOFS_ENTRY,
+ &opts->autofs_entry_map);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Could not get autofs entry object attribute map\n"));
+ return ret;
+ }
+
+ return EOK;
+}
+
errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
struct dp_option *opts, int class,
struct sdap_search_base ***_search_bases)
@@ -635,6 +739,8 @@ errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
break;
case SDAP_SERVICE_SEARCH_BASE:
class_name = "SERVICE";
+ case SDAP_AUTOFS_SEARCH_BASE:
+ class_name = "AUTOFS";
break;
default:
DEBUG(SSSDBG_CONF_SETTINGS,
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 603a1ed92..c377bcb67 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -124,6 +124,11 @@ int ldap_get_sudo_options(TALLOC_CTX *memctx,
const char *conf_path,
struct sdap_options *opts);
+int ldap_get_autofs_options(TALLOC_CTX *memctx,
+ struct confdb_ctx *cdb,
+ const char *conf_path,
+ struct sdap_options *opts);
+
int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index dd61a1e1a..8c98c8eaa 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -27,6 +27,7 @@
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/sdap_access.h"
#include "providers/ldap/sdap_sudo.h"
+#include "providers/ldap/sdap_autofs.h"
static void sdap_shutdown(struct be_req *req);
@@ -411,6 +412,36 @@ int sssm_ldap_sudo_init(struct be_ctx *be_ctx,
return sdap_sudo_init(be_ctx, id_ctx, ops, &data);
}
+int sssm_ldap_autofs_init(struct be_ctx *be_ctx,
+ struct bet_ops **ops,
+ void **pvt_data)
+{
+#ifdef BUILD_AUTOFS
+ struct sdap_id_ctx *id_ctx;
+ void *data;
+ int ret;
+
+ ret = sssm_ldap_id_init(be_ctx, ops, &data);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot init LDAP ID provider [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ id_ctx = talloc_get_type(data, struct sdap_id_ctx);
+ if (!id_ctx) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No ID provider?\n"));
+ return EIO;
+ }
+
+ return sdap_autofs_init(be_ctx, id_ctx, ops, pvt_data);
+#else
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Autofs init handler called but SSSD is "
+ "built without autofs support, ignoring\n"));
+ return EOK;
+#endif
+}
+
static void sdap_shutdown(struct be_req *req)
{
/* TODO: Clean up any internal data */
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index 27cffd79a..1f97f554d 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -717,6 +717,8 @@ static errno_t sdap_set_search_base(struct sdap_options *opts,
break;
case SDAP_SERVICE_SEARCH_BASE:
bases = &opts->service_search_bases;
+ case SDAP_AUTOFS_SEARCH_BASE:
+ bases = &opts->autofs_search_bases;
break;
default:
return EINVAL;
@@ -750,7 +752,8 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
||!opts->user_search_bases
|| !opts->group_search_bases
|| !opts->netgroup_search_bases
- || !opts->sudo_search_bases) {
+ || !opts->sudo_search_bases
+ || !opts->autofs_search_bases) {
naming_context = get_naming_context(opts->basic, rootdse);
if (naming_context == NULL) {
DEBUG(1, ("get_naming_context failed.\n"));
@@ -812,6 +815,14 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
if (ret != EOK) goto done;
}
+ /* autofs */
+ if (!opts->autofs_search_bases) {
+ ret = sdap_set_search_base(opts,
+ SDAP_AUTOFS_SEARCH_BASE,
+ naming_context);
+ if (ret != EOK) goto done;
+ }
+
ret = EOK;
done:
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 2e1dfa959..0a0f996d1 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -168,6 +168,7 @@ enum sdap_basic_opt {
SDAP_SUDO_SEARCH_BASE,
SDAP_SUDO_REFRESH_ENABLED,
SDAP_SUDO_REFRESH_TIMEOUT,
+ SDAP_AUTOFS_SEARCH_BASE,
SDAP_SCHEMA,
SDAP_OFFLINE_TIMEOUT,
SDAP_FORCE_UPPER_CASE_REALM,
@@ -311,6 +312,21 @@ enum sdap_service_attrs {
SDAP_OPTS_SERVICES /* attrs counter */
};
+enum sdap_autofs_map_attrs {
+ SDAP_OC_AUTOFS_MAP,
+ SDAP_AT_AUTOFS_MAP_NAME,
+
+ SDAP_OPTS_AUTOFS_MAP /* attrs counter */
+};
+
+enum sdap_autofs_entry_attrs {
+ SDAP_OC_AUTOFS_ENTRY,
+ SDAP_AT_AUTOFS_ENTRY_KEY,
+ SDAP_AT_AUTOFS_ENTRY_VALUE,
+
+ SDAP_OPTS_AUTOFS_ENTRY /* attrs counter */
+};
+
struct sdap_attr_map {
const char *opt_name;
const char *def_name;
@@ -335,6 +351,8 @@ struct sdap_options {
/* FIXME - should this go to a special struct to avoid mixing with name-service-switch maps? */
struct sdap_attr_map *sudorule_map;
+ struct sdap_attr_map *autofs_mobject_map;
+ struct sdap_attr_map *autofs_entry_map;
/* supported schema types */
enum schema_type {
@@ -350,6 +368,7 @@ struct sdap_options {
struct sdap_search_base **netgroup_search_bases;
struct sdap_search_base **sudo_search_bases;
struct sdap_search_base **service_search_bases;
+ struct sdap_search_base **autofs_search_bases;
};
struct sdap_server_opts {
diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
new file mode 100644
index 000000000..ce8a1f96a
--- /dev/null
+++ b/src/providers/ldap/sdap_async_autofs.c
@@ -0,0 +1,833 @@
+/*
+ SSSD
+
+ Async LDAP Helper routines for autofs
+
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2012 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 "db/sysdb.h"
+#include "providers/ldap/sdap_async_private.h"
+#include "db/sysdb_autofs.h"
+#include "providers/ldap/ldap_common.h"
+
+/* ====== Utility functions ====== */
+static const char *
+get_autofs_map_name(struct sysdb_attrs *map, struct sdap_options *opts)
+{
+ errno_t ret;
+ struct ldb_message_element *el;
+
+ ret = sysdb_attrs_get_el(map,
+ opts->autofs_mobject_map[SDAP_AT_AUTOFS_MAP_NAME].sys_name,
+ &el);
+ if (ret) return NULL;
+ if (el->num_values == 0) return NULL;
+
+ return (const char *)el->values[0].data;
+}
+
+static const char *
+get_autofs_entry_key(struct sysdb_attrs *entry, struct sdap_options *opts)
+{
+ errno_t ret;
+ struct ldb_message_element *el;
+
+ ret = sysdb_attrs_get_el(entry,
+ opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].sys_name,
+ &el);
+ if (ret) return NULL;
+ if (el->num_values == 0) return NULL;
+
+ return (const char *)el->values[0].data;
+}
+
+static errno_t
+save_autofs_entry(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sysdb_attrs *entry)
+{
+ const char *key;
+ const char *value;
+ struct ldb_message_element *el;
+ errno_t ret;
+
+ key = get_autofs_entry_key(entry, opts);
+ if (!key) return EINVAL;
+
+ ret = sysdb_attrs_get_el(entry,
+ opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_VALUE].sys_name,
+ &el);
+ if (ret) return ret;
+ if (el->num_values == 0) return EINVAL;
+ else value = (const char *)el->values[0].data;
+
+ ret = sysdb_save_autofsentry(sysdb, key, value, NULL);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t
+save_autofs_entries(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ char **add_entries,
+ struct sysdb_attrs **entries,
+ size_t num_entries)
+{
+ errno_t ret, tret;
+ const char *key;
+ bool in_transaction = false;
+ int i, j;
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot start sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ in_transaction = true;
+
+ for (i=0; add_entries[i]; i++) {
+ for (j=0; j < num_entries; j++) {
+ key = get_autofs_entry_key(entries[j], opts);
+ if (!key) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("An entry without name? Skipping\n"));
+ return EINVAL;
+ }
+
+ if (strcmp(add_entries[i], key)) {
+ continue;
+ }
+
+ ret = save_autofs_entry(sysdb, opts, entries[j]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Cannot save autofs entry [%d]: %s. Ignoring.\n",
+ ret, strerror(ret)));
+ continue;
+ }
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot commit sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+done:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(sysdb);
+ if (tret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot cancel sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ }
+ }
+ return ret;
+}
+
+static errno_t
+save_autofs_map(struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ struct sdap_options *opts,
+ struct sysdb_attrs *map)
+{
+ const char *mapname;
+ errno_t ret;
+ time_t now;
+
+ mapname = get_autofs_map_name(map, opts);
+ if (!mapname) return EINVAL;
+
+ now = time(NULL);
+
+ ret = sysdb_save_autofsmap(sysdb, mapname, mapname,
+ NULL, dom->autofsmap_timeout, now);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return EOK;
+}
+
+struct automntmaps_process_members_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sss_domain_info *dom;
+ int timeout;
+ struct sysdb_ctx *sysdb;
+
+ char *filter;
+ const char **attrs;
+
+ struct sysdb_attrs *map;
+
+ struct sysdb_attrs **entries;
+ size_t entries_count;
+};
+
+static void
+automntmaps_process_members_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+automntmaps_process_members_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ struct sss_domain_info *dom,
+ int timeout,
+ struct sysdb_ctx *sysdb,
+ struct sysdb_attrs *map)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct automntmaps_process_members_state *state;
+ const char *orig_dn;
+ char *clean_orig_dn;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct automntmaps_process_members_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->dom = dom;
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->timeout = timeout;
+
+ state->map = map;
+
+ state->filter = talloc_asprintf(state, "(&(%s=*)(objectclass=%s))",
+ opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].name,
+ opts->autofs_entry_map[SDAP_OC_AUTOFS_ENTRY].name);
+ if (!state->filter) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ ret = build_attrs_from_map(state, opts->autofs_entry_map,
+ SDAP_OPTS_AUTOFS_ENTRY, &state->attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build attributes from map\n"));
+ ret = ENOMEM;
+ goto immediate;
+ }
+
+ ret = sysdb_attrs_get_string(state->map, SYSDB_ORIG_DN, &orig_dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get originalDN\n"));
+ goto immediate;
+ }
+
+ /* FIXME - should test if the DN is in the current base? */
+ ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot sanitize originalDN\n"));
+ goto immediate;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Examining autofs map [%s]\n", clean_orig_dn));
+
+ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+ clean_orig_dn, LDAP_SCOPE_SUBTREE,
+ state->filter, state->attrs,
+ opts->autofs_entry_map,
+ SDAP_OPTS_AUTOFS_ENTRY,
+ state->timeout);
+ if (!subreq) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot start search for entries\n"));
+ goto immediate;
+ }
+ tevent_req_set_callback(subreq, automntmaps_process_members_done, req);
+ return req;
+
+immediate:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ tevent_req_done(req);
+ }
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void
+automntmaps_process_members_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct automntmaps_process_members_state *state =
+ tevent_req_data(req, struct automntmaps_process_members_state);
+ errno_t ret;
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->entries_count, &state->entries);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Search for autofs entries, returned %d results.\n",
+ state->entries_count));
+
+ tevent_req_done(req);
+ return;
+}
+
+static errno_t
+automntmaps_process_members_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *entries_count,
+ struct sysdb_attrs ***entries)
+{
+ struct automntmaps_process_members_state *state;
+ state = tevent_req_data(req, struct automntmaps_process_members_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (entries_count) {
+ *entries_count = state->entries_count;
+ }
+
+ if (entries) {
+ *entries = talloc_steal(mem_ctx, state->entries);
+ }
+
+ return EOK;
+}
+
+struct sdap_get_automntmap_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+ const char **attrs;
+ const char *base_filter;
+ char *filter;
+ int timeout;
+
+ char *higher_timestamp;
+
+ struct sysdb_attrs **map;
+ size_t count;
+
+ struct sysdb_attrs **entries;
+ size_t entries_count;
+
+ size_t base_iter;
+ struct sdap_search_base **search_bases;
+};
+
+static errno_t
+sdap_get_automntmap_next_base(struct tevent_req *req);
+static void
+sdap_get_automntmap_process(struct tevent_req *subreq);
+
+static struct tevent_req *
+sdap_get_automntmap_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sdap_search_base **search_bases,
+ struct sdap_handle *sh,
+ const char **attrs,
+ const char *filter,
+ int timeout)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct sdap_get_automntmap_state *state;
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_automntmap_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->dom = dom;
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->attrs = attrs;
+ state->higher_timestamp = NULL;
+ state->map = NULL;
+ state->count = 0;
+ state->timeout = timeout;
+ state->base_filter = filter;
+ state->base_iter = 0;
+ state->search_bases = search_bases;
+
+ ret = sdap_get_automntmap_next_base(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, state->ev);
+ }
+ return req;
+}
+
+static errno_t
+sdap_get_automntmap_next_base(struct tevent_req *req)
+{
+ struct tevent_req *subreq;
+ struct sdap_get_automntmap_state *state;
+
+ state = tevent_req_data(req, struct sdap_get_automntmap_state);
+
+ talloc_zfree(state->filter);
+ state->filter = sdap_get_id_specific_filter(state,
+ state->base_filter,
+ state->search_bases[state->base_iter]->filter);
+ if (!state->filter) {
+ return ENOMEM;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Searching for automount maps with base [%s]\n",
+ state->search_bases[state->base_iter]->basedn));
+
+ subreq = sdap_get_generic_send(
+ state, state->ev, state->opts, state->sh,
+ state->search_bases[state->base_iter]->basedn,
+ state->search_bases[state->base_iter]->scope,
+ state->filter, state->attrs,
+ state->opts->autofs_mobject_map, SDAP_OPTS_AUTOFS_MAP,
+ state->timeout);
+ if (!subreq) {
+ return EIO;
+ }
+ tevent_req_set_callback(subreq, sdap_get_automntmap_process, req);
+
+ return EOK;
+}
+
+static void
+sdap_get_automntmap_done(struct tevent_req *subreq);
+
+static void
+sdap_get_automntmap_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_automntmap_state *state = tevent_req_data(req,
+ struct sdap_get_automntmap_state);
+ errno_t ret;
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->count, &state->map);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Search for autofs maps, returned %d results.\n", state->count));
+
+ if (state->count == 0) {
+ /* No maps found in this search */
+ state->base_iter++;
+ if (state->search_bases[state->base_iter]) {
+ /* There are more search bases to try */
+ ret = sdap_get_automntmap_next_base(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ENOENT);
+ }
+ return;
+ }
+
+ tevent_req_error(req, ENOENT);
+ return;
+ } else if (state->count > 1) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("The search yielded more than one autofs map\n"));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, ("Processing autofs maps\n"));
+ subreq = automntmaps_process_members_send(state, state->ev, state->opts,
+ state->sh, state->dom,
+ state->timeout, state->sysdb,
+ state->map[0]);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_get_automntmap_done, req);
+
+ return;
+}
+
+static void
+sdap_get_automntmap_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_automntmap_state *state = tevent_req_data(req,
+ struct sdap_get_automntmap_state);
+ errno_t ret;
+
+ ret = automntmaps_process_members_recv(subreq, state, &state->entries_count,
+ &state->entries);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("automount map members received\n"));
+ tevent_req_done(req);
+ return;
+}
+
+static errno_t
+sdap_get_automntmap_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct sysdb_attrs **map,
+ size_t *entries_count,
+ struct sysdb_attrs ***entries)
+{
+ struct sdap_get_automntmap_state *state = tevent_req_data(req,
+ struct sdap_get_automntmap_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (map) {
+ *map = talloc_steal(mem_ctx, state->map[0]);
+ }
+
+ if (entries_count) {
+ *entries_count = state->entries_count;
+ }
+
+ if (entries) {
+ *entries = talloc_steal(mem_ctx, state->entries);
+ }
+
+ return EOK;
+}
+
+struct sdap_autofs_setautomntent_state {
+ char *filter;
+ const char **attrs;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sysdb_ctx *sysdb;
+ struct sdap_id_op *sdap_op;
+ struct sss_domain_info *dom;
+
+ const char *mapname;
+ struct sysdb_attrs *map;
+ struct sysdb_attrs **entries;
+ size_t entries_count;
+
+ int dp_error;
+};
+
+static void
+sdap_autofs_setautomntent_done(struct tevent_req *subreq);
+
+struct tevent_req *
+sdap_autofs_setautomntent_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ struct sdap_id_op *op,
+ struct sdap_options *opts,
+ const char *mapname)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct sdap_autofs_setautomntent_state *state;
+ char *clean_mapname;
+ errno_t ret;
+
+ req = tevent_req_create(memctx, &state,
+ struct sdap_autofs_setautomntent_state);
+ if (!req) return NULL;
+
+ if (!mapname) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No map name given\n"));
+ ret = EINVAL;
+ goto fail;
+ }
+
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->opts = opts;
+ state->sdap_op = op;
+ state->dom = dom;
+ state->mapname = mapname;
+
+ ret = sss_filter_sanitize(state, mapname, &clean_mapname);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ state->opts->autofs_mobject_map[SDAP_AT_AUTOFS_MAP_NAME].name,
+ clean_mapname,
+ state->opts->autofs_mobject_map[SDAP_OC_AUTOFS_MAP].name);
+ if (!state->filter) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ talloc_free(clean_mapname);
+
+ ret = build_attrs_from_map(state, state->opts->autofs_mobject_map,
+ SDAP_OPTS_AUTOFS_MAP, &state->attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build attributes from map\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ subreq = sdap_get_automntmap_send(state, ev, dom,
+ sysdb, state->opts,
+ state->opts->autofs_search_bases,
+ state->sh,
+ state->attrs, state->filter,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, sdap_autofs_setautomntent_done, req);
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t
+sdap_autofs_setautomntent_save(struct tevent_req *req);
+
+static void
+sdap_autofs_setautomntent_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_autofs_setautomntent_state *state = tevent_req_data(req,
+ struct sdap_autofs_setautomntent_state);
+
+ ret = sdap_get_automntmap_recv(subreq, state, &state->map,
+ &state->entries_count, &state->entries);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not find automount map\n"));
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("sdap_get_automntmap_recv failed [%d]: %s\n",
+ ret, strerror(ret)));
+ }
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ ret = sdap_autofs_setautomntent_save(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not save automount map\n"));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ return;
+}
+
+static errno_t
+sdap_autofs_setautomntent_save(struct tevent_req *req)
+{
+ struct sdap_autofs_setautomntent_state *state = tevent_req_data(req,
+ struct sdap_autofs_setautomntent_state);
+ errno_t ret, tret;
+ bool in_transaction = false;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *sysdb_map;
+ struct ldb_message_element *map_members = NULL;
+ char **sysdb_entrylist;
+ char **ldap_entrylist;
+ char **add_entries;
+ char **del_entries;
+ size_t i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ if (state->entries_count == 0) {
+ /* No entries for this map in LDAP.
+ * We need to ensure that there are no entries
+ * in the sysdb either.
+ */
+ ldap_entrylist = NULL;
+ } else {
+ ret = sysdb_attrs_to_list(
+ tmp_ctx, state->entries,
+ state->entries_count,
+ state->opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].name,
+ &ldap_entrylist);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ }
+
+ ret = sysdb_get_map_byname(tmp_ctx, state->sysdb, state->mapname,
+ &sysdb_map);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("cache lookup for the map failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ if (sysdb_map) {
+ map_members = ldb_msg_find_element(sysdb_map, SYSDB_MEMBER);
+ }
+
+ if (!map_members || map_members->num_values == 0) {
+ /* No map members for this map in sysdb currently */
+ sysdb_entrylist = NULL;
+ } else {
+ sysdb_entrylist = talloc_array(state, char *, map_members->num_values+1);
+ if (!sysdb_entrylist) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Get a list of the map members by name only */
+ for (i=0; i < map_members->num_values; i++) {
+ ret = sysdb_map_entry_name(sysdb_entrylist, state->sysdb,
+ (const char *) map_members->values[i].data,
+ &sysdb_entrylist[i]);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+ sysdb_entrylist[map_members->num_values] = NULL;
+ }
+
+ /* Find the differences between the sysdb and LDAP lists
+ * Entries in the sysdb only must be removed.
+ */
+ ret = diff_string_lists(tmp_ctx, ldap_entrylist, sysdb_entrylist,
+ &add_entries, &del_entries, NULL);
+ if (ret != EOK) goto done;
+
+ ret = sysdb_transaction_start(state->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot start sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ in_transaction = true;
+
+ /* Save the map itself */
+ ret = save_autofs_map(state->sysdb, state->dom, state->opts, state->map);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Cannot save autofs map entry [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ /* Create entries that don't exist yet */
+ if (add_entries && add_entries[0]) {
+ ret = save_autofs_entries(state->sysdb, state->opts,
+ add_entries, state->entries,
+ state->entries_count);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Cannot save autofs entries [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ }
+
+ /* Save the memberships */
+ DEBUG(SSSDBG_TRACE_FUNC, ("Updating memberships for %s\n", state->mapname));
+ ret = sysdb_autofs_map_update_members(state->sysdb, state->mapname,
+ (const char *const *) add_entries,
+ (const char *const *) del_entries);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Membership update failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sysdb_transaction_commit(state->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot commit sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+done:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(state->sysdb);
+ if (tret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Cannot cancel sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ }
+ }
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+errno_t
+sdap_autofs_setautomntent_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c
new file mode 100644
index 000000000..5e3e3320c
--- /dev/null
+++ b/src/providers/ldap/sdap_autofs.c
@@ -0,0 +1,291 @@
+/*
+ SSSD
+
+ LDAP handler for autofs
+
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2012 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 <errno.h>
+#include <tevent.h>
+
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_autofs.h"
+#include "providers/ldap/sdap.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/dp_backend.h"
+#include "db/sysdb_autofs.h"
+#include "util/util.h"
+
+static void
+sdap_autofs_shutdown(struct be_req *req)
+{
+ sdap_handler_done(req, DP_ERR_OK, EOK, NULL);
+}
+
+void sdap_autofs_handler(struct be_req *be_req);
+
+/* Autofs Handler */
+struct bet_ops sdap_autofs_ops = {
+ .handler = sdap_autofs_handler,
+ .finalize = sdap_autofs_shutdown
+};
+
+int sdap_autofs_init(struct be_ctx *be_ctx,
+ struct sdap_id_ctx *id_ctx,
+ struct bet_ops **ops,
+ void **pvt_data)
+{
+ int ret;
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing autofs LDAP back end\n"));
+
+ *ops = &sdap_autofs_ops;
+ *pvt_data = id_ctx;
+
+ ret = ldap_get_autofs_options(id_ctx, be_ctx->cdb,
+ be_ctx->conf_path, id_ctx->opts);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return ret;
+}
+
+static struct tevent_req *
+sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *map_name);
+
+static void sdap_autofs_handler_done(struct tevent_req *req);
+
+void sdap_autofs_handler(struct be_req *be_req)
+{
+ struct sdap_id_ctx *id_ctx;
+ struct be_autofs_req *autofs_req;
+ struct tevent_req *req;
+ int ret = EOK;
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, ("sdap autofs handler called\n"));
+
+ id_ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_AUTOFS].pvt_bet_data,
+ struct sdap_id_ctx);
+
+ if (be_is_offline(id_ctx->be)) {
+ return sdap_handler_done(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
+ }
+
+ autofs_req = talloc_get_type(be_req->req_data, struct be_autofs_req);
+
+ DEBUG(SSSDBG_FUNC_DATA, ("Requested refresh for: %s\n",
+ autofs_req->mapname ? autofs_req->mapname : "<ALL>\n"));
+
+ req = sdap_autofs_get_map_send(be_req, be_req->be_ctx->ev,
+ id_ctx, autofs_req->mapname);
+ if (!req) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(req, sdap_autofs_handler_done, be_req);
+
+ return;
+fail:
+ be_req->fn(be_req, DP_ERR_FATAL, ret, NULL);
+}
+
+struct autofs_get_map_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+ struct sdap_id_op *op;
+ const char *map_name;
+
+ int dp_error;
+};
+
+static errno_t
+sdap_autofs_get_map_retry(struct tevent_req *req);
+static void
+sdap_autofs_get_map_connect_done(struct tevent_req *subreq);
+static void
+sdap_autofs_get_map_done(struct tevent_req *req);
+
+static struct tevent_req *
+sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *map_name)
+{
+ struct tevent_req *req;
+ struct autofs_get_map_state *state;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct autofs_get_map_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->dp_error = DP_ERR_FATAL;
+ state->map_name = map_name;
+
+ state->op = sdap_id_op_create(state, state->ctx->conn_cache);
+ if (!state->op) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sdap_autofs_get_map_retry(req);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t
+sdap_autofs_get_map_retry(struct tevent_req *req)
+{
+ struct autofs_get_map_state *state =
+ tevent_req_data(req, struct autofs_get_map_state);
+ struct tevent_req *subreq;
+ int ret = EOK;
+
+ subreq = sdap_id_op_connect_send(state->op, state, &ret);
+ if (!subreq) {
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, sdap_autofs_get_map_connect_done, req);
+ return EOK;
+}
+
+static void
+sdap_autofs_get_map_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct autofs_get_map_state *state =
+ tevent_req_data(req, struct autofs_get_map_state);
+ int dp_error = DP_ERR_FATAL;
+ int ret;
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ state->dp_error = dp_error;
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_autofs_setautomntent_send(state, state->ev,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
+ sdap_id_op_handle(state->op),
+ state->op,
+ state->ctx->opts,
+ state->map_name);
+ if (!subreq) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("sdap_autofs_setautomntent_send failed\n"));
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_autofs_get_map_done, req);
+
+}
+
+static void
+sdap_autofs_get_map_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct autofs_get_map_state *state =
+ tevent_req_data(req, struct autofs_get_map_state);
+ int dp_error = DP_ERR_FATAL;
+ int ret;
+
+ ret = sdap_autofs_setautomntent_recv(subreq);
+ talloc_zfree(subreq);
+
+ ret = sdap_id_op_done(state->op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = sdap_autofs_get_map_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ return;
+ }
+
+ if (ret && ret != ENOENT) {
+ state->dp_error = dp_error;
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (ret == ENOENT) {
+ ret = sysdb_delete_autofsmap(state->ctx->be->sysdb, state->map_name);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Cannot delete autofs map %s [%d]: %s\n",
+ state->map_name, ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+ }
+
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+}
+
+static errno_t
+sdap_autofs_get_map_recv(struct tevent_req *req, int *dp_error_out)
+{
+ struct autofs_get_map_state *state =
+ tevent_req_data(req, struct autofs_get_map_state);
+
+ if (dp_error_out) {
+ *dp_error_out = state->dp_error;
+ }
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+static void
+sdap_autofs_handler_done(struct tevent_req *req)
+{
+ struct be_req *be_req =
+ tevent_req_callback_data(req, struct be_req);
+ int dperr;
+ errno_t ret;
+
+ ret = sdap_autofs_get_map_recv(req, &dperr);
+ sdap_handler_done(be_req, dperr, ret, strerror(ret));
+}
+
diff --git a/src/providers/ldap/sdap_autofs.h b/src/providers/ldap/sdap_autofs.h
new file mode 100644
index 000000000..0369e2645
--- /dev/null
+++ b/src/providers/ldap/sdap_autofs.h
@@ -0,0 +1,47 @@
+/*
+ SSSD
+
+ LDAP handler for autofs
+
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2012 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/>.
+*/
+
+#ifndef _SDAP_AUTOFS_H_
+#define _SDAP_AUTOFS_H_
+
+int sdap_autofs_init(struct be_ctx *be_ctx,
+ struct sdap_id_ctx *id_ctx,
+ struct bet_ops **ops,
+ void **pvt_data);
+
+struct tevent_req *
+sdap_autofs_setautomntent_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_handle *sh,
+ struct sdap_id_op *op,
+ struct sdap_options *opts,
+ const char *mapname);
+
+errno_t
+sdap_autofs_setautomntent_recv(struct tevent_req *req);
+
+#endif /* _SDAP_AUTOFS_H_ */
+