From 41606494979da8cb7fb09170687131a556a643c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 11 Nov 2019 13:56:34 +0100
Subject: [PATCH 102/103] autofs: delete possible duplicate of an autofs entry
Steps to reproduce:
1. Create the following autofs objects
```ldif
dn: ou=auto.master,ou=autofs,dc=ldap,dc=vm
objectClass: automountMap
objectClass: top
ou: auto.master
dn: automountKey=/home,ou=auto.master,ou=autofs,dc=ldap,dc=vm
objectClass: automount
objectClass: top
automountInformation: auto.home
automountKey: /home
dn: ou=auto.home,ou=autofs,dc=ldap,dc=vm
objectClass: automountMap
objectClass: top
ou: auto.home
dn: automountKey=/home1,ou=auto.home,ou=autofs,dc=ldap,dc=vm
objectClass: automount
objectClass: top
automountInformation: home1
automountKey: /home1
```
2. Use e.g. the test tool to fetch the maps:
```
./autofs_test_client auto.master
./autofs_test_client auto.home -n /home1
```
3. Change automountInformation of /home1
```
dn: automountKey=/home1,ou=auto.home,ou=autofs,dc=ldap,dc=vm
objectClass: automount
objectClass: top
automountInformation: home1_1
automountKey: /home1
```
4. Run the test tool again:
```
./autofs_test_client auto.master
./autofs_test_client auto.home -n /home1
> error happens
```
It is important the `get entry by name is called` thus the `-n` parameter.
Resolves:
https://pagure.io/SSSD/sssd/issue/4116
(cherry picked from commit 14b44e721c52207fd17e449cc6ae0a75fbb05369)
---
src/providers/ldap/sdap_async_autofs.c | 93 ++++++++++++++++++++------
1 file changed, 74 insertions(+), 19 deletions(-)
diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c
index 232d0c34a..6f37b1c84 100644
--- a/src/providers/ldap/sdap_async_autofs.c
+++ b/src/providers/ldap/sdap_async_autofs.c
@@ -1337,6 +1337,12 @@ static void sdap_autofs_get_entry_connect_done(struct tevent_req *subreq)
tevent_req_set_callback(subreq, sdap_autofs_get_entry_done, req);
}
+static errno_t sdap_autofs_save_entry(struct sss_domain_info *domain,
+ struct sdap_options *opts,
+ struct sysdb_attrs *newentry,
+ const char *mapname,
+ const char *entryname);
+
static void sdap_autofs_get_entry_done(struct tevent_req *subreq)
{
struct tevent_req *req;
@@ -1365,31 +1371,18 @@ static void sdap_autofs_get_entry_done(struct tevent_req *subreq)
return;
}
- if (reply_count == 0) {
- ret = sysdb_del_autofsentry_by_key(state->id_ctx->be->domain,
- state->mapname, state->entryname);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot delete entry %s:%s\n",
- state->mapname, state->entryname);
- tevent_req_error(req, ret);
- return;
- }
-
- tevent_req_done(req);
- return;
- }
-
- ret = add_autofs_entry(state->id_ctx->be->domain, state->mapname,
- state->opts, reply[0], time(NULL));
+ ret = sdap_autofs_save_entry(state->id_ctx->be->domain,
+ state->opts,
+ reply_count != 0 ? reply[0] : NULL,
+ state->mapname,
+ state->entryname);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Cannot save autofs entry %s:%s [%d]: %s\n",
- state->mapname, state->entryname, ret, strerror(ret));
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
+ return;
}
errno_t sdap_autofs_get_entry_recv(struct tevent_req *req,
@@ -1405,3 +1398,65 @@ errno_t sdap_autofs_get_entry_recv(struct tevent_req *req,
return EOK;
}
+
+static errno_t sdap_autofs_save_entry(struct sss_domain_info *domain,
+ struct sdap_options *opts,
+ struct sysdb_attrs *newentry,
+ const char *mapname,
+ const char *entryname)
+{
+ bool in_transaction = false;
+ errno_t ret;
+ int tret;
+
+ ret = sysdb_transaction_start(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot start sysdb transaction [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ in_transaction = true;
+
+ /* Delete existing entry to cover case where new entry has the same key
+ * but different automountInformation. Because the dn is created from the
+ * combination of key and information it would be possible to end up with
+ * two entries with same key but different information otherwise.
+ */
+ ret = sysdb_del_autofsentry_by_key(domain, mapname, entryname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot delete entry %s:%s\n",
+ mapname, entryname);
+ goto done;
+ }
+
+ if (newentry != NULL) {
+ ret = add_autofs_entry(domain, mapname, opts, newentry, time(NULL));
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot save autofs entry %s:%s [%d]: %s\n",
+ mapname, entryname, ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = sysdb_transaction_commit(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot commit sysdb transaction [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(domain->sysdb);
+ if (tret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot cancel sysdb transaction "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ }
+ }
+
+ return ret;
+}
--
2.20.1