Blob Blame History Raw
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