From 1801695a8b17dd0d67a9c34ad55326d3277929ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 6 Mar 2020 12:49:04 +0100
Subject: [PATCH 1/5] cache_req: allow cache_req to return ERR_OFFLINE if all
 dp request failed

---
 src/responder/common/cache_req/cache_req.c         | 13 +++++++++++++
 src/responder/common/cache_req/cache_req.h         |  4 ++++
 src/responder/common/cache_req/cache_req_data.c    | 12 ++++++++++++
 src/responder/common/cache_req/cache_req_private.h |  3 +++
 4 files changed, 32 insertions(+)

diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index afb0e7cdac..0c85384146 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -974,6 +974,13 @@ static void cache_req_search_domains_done(struct tevent_req *subreq)
     case ERR_ID_OUTSIDE_RANGE:
     case ENOENT:
         if (state->check_next == false) {
+            if (state->cr->data->propogate_offline_status && !state->dp_success) {
+                /* Not found and data provider request failed so we were
+                 * unable to fetch the data. */
+                ret = ERR_OFFLINE;
+                goto done;
+            }
+
             /* Not found. */
             ret = ENOENT;
             goto done;
@@ -1002,6 +1009,12 @@ static void cache_req_search_domains_done(struct tevent_req *subreq)
     case EAGAIN:
         break;
     default:
+        if (ret == ENOENT && state->cr->data->propogate_offline_status
+                && !state->dp_success) {
+            /* Not found and data provider request failed so we were
+             * unable to fetch the data. */
+            ret = ERR_OFFLINE;
+        }
         tevent_req_error(req, ret);
         break;
     }
diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
index 72d4abe5ec..d36cb2d3b0 100644
--- a/src/responder/common/cache_req/cache_req.h
+++ b/src/responder/common/cache_req/cache_req.h
@@ -171,6 +171,10 @@ void
 cache_req_data_set_requested_domains(struct cache_req_data *data,
                                      char **requested_domains);
 
+void
+cache_req_data_set_propogate_offline_status(struct cache_req_data *data,
+                                            bool propogate_offline_status);
+
 enum cache_req_type
 cache_req_data_get_type(struct cache_req_data *data);
 
diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
index 14c4ad14f0..fe9f3db298 100644
--- a/src/responder/common/cache_req/cache_req_data.c
+++ b/src/responder/common/cache_req/cache_req_data.c
@@ -455,6 +455,18 @@ cache_req_data_set_requested_domains(struct cache_req_data *data,
     data->requested_domains = requested_domains;
 }
 
+void
+cache_req_data_set_propogate_offline_status(struct cache_req_data *data,
+                                            bool propogate_offline_status)
+{
+    if (data == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
+        return;
+    }
+
+    data->propogate_offline_status = propogate_offline_status;
+}
+
 enum cache_req_type
 cache_req_data_get_type(struct cache_req_data *data)
 {
diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
index bfca688b92..2d52e7600b 100644
--- a/src/responder/common/cache_req/cache_req_private.h
+++ b/src/responder/common/cache_req/cache_req_private.h
@@ -103,6 +103,9 @@ struct cache_req_data {
 
     /* if set, only search in the listed domains */
     char **requested_domains;
+
+    /* if set, ERR_OFFLINE is returned if data provider is offline */
+    bool propogate_offline_status;
 };
 
 struct tevent_req *

From aaf8c2746c3cc96b8ca568a737ccdd88f3ff7d0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 6 Mar 2020 13:12:46 +0100
Subject: [PATCH 2/5] autofs: return ERR_OFFLINE if we fail to get information
 from backend and cache is empty

Resolves:
https://github.com/SSSD/sssd/issues/3413
---
 .../common/cache_req/plugins/cache_req_autofs_entry_by_name.c   | 2 ++
 .../common/cache_req/plugins/cache_req_autofs_map_by_name.c     | 2 ++
 .../common/cache_req/plugins/cache_req_autofs_map_entries.c     | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
index cb674add69..55c9fc8b0c 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
@@ -142,6 +142,8 @@ cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
+    cache_req_data_set_propogate_offline_status(data, true);
+
     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
                                          cache_refresh_percent,
                                          CACHE_REQ_POSIX_DOM, domain,
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
index 3c08eaf4f8..823eb35951 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
@@ -136,6 +136,8 @@ cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
+    cache_req_data_set_propogate_offline_status(data, true);
+
     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
                                          cache_refresh_percent,
                                          CACHE_REQ_POSIX_DOM, domain,
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
index 1b5645fa0e..3e47b1321d 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
@@ -168,6 +168,8 @@ cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
+    cache_req_data_set_propogate_offline_status(data, true);
+
     return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache,
                                          cache_refresh_percent,
                                          CACHE_REQ_POSIX_DOM, domain,

From 911ad8ede6f92f8d3bae3faf33ab78e4ea824a83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 6 Mar 2020 13:44:56 +0100
Subject: [PATCH 3/5] autofs: translate ERR_OFFLINE to EHOSTDOWN

So we do not publish internal error code.

Resolves:
https://github.com/SSSD/sssd/issues/3413
---
 src/sss_client/common.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 902438c866..d293329397 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -44,6 +44,7 @@
 #define _(STRING) dgettext (PACKAGE, STRING)
 #include "sss_cli.h"
 #include "common_private.h"
+#include "util/util_errors.h"
 
 #if HAVE_PTHREAD
 #include <pthread.h>
@@ -1054,9 +1055,17 @@ int sss_autofs_make_request(enum sss_cli_command cmd,
                             uint8_t **repbuf, size_t *replen,
                             int *errnop)
 {
-    return sss_cli_make_request_with_checks(cmd, rd, SSS_CLI_SOCKET_TIMEOUT,
-                                            repbuf, replen, errnop,
-                                            SSS_AUTOFS_SOCKET_NAME);
+    enum sss_status status;
+
+    status = sss_cli_make_request_with_checks(cmd, rd, SSS_CLI_SOCKET_TIMEOUT,
+                                              repbuf, replen, errnop,
+                                              SSS_AUTOFS_SOCKET_NAME);
+
+    if (*errnop == ERR_OFFLINE) {
+        *errnop = EHOSTDOWN;
+    }
+
+    return status;
 }
 
 int sss_ssh_make_request(enum sss_cli_command cmd,

From 97f150c19217dc9e6fd4d9ec2953716d49e35fec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 22 Sep 2020 11:04:25 +0200
Subject: [PATCH 4/5] autofs: disable fast reply

If the backend is offline when autofs starts and reads auto.master map
we don't want to wait 60 seconds before the offline flag is reset. We
need to allow autofs to retry the call much sooner.

Resolves:
https://github.com/SSSD/sssd/issues/3413
---
 .../common/cache_req/plugins/cache_req_autofs_entry_by_name.c   | 2 +-
 .../common/cache_req/plugins/cache_req_autofs_map_by_name.c     | 2 +-
 .../common/cache_req/plugins/cache_req_autofs_map_entries.c     | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
index 55c9fc8b0c..cd2085187e 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c
@@ -84,7 +84,7 @@ cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx,
 
     return sbus_call_dp_autofs_GetEntry_send(mem_ctx, be_conn->conn,
                                              be_conn->bus_name, SSS_BUS_PATH,
-                                             DP_FAST_REPLY, data->name.name,
+                                             0, data->name.name,
                                              data->autofs_entry_name);
 }
 
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
index 823eb35951..9d9bc3a97e 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c
@@ -81,7 +81,7 @@ cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx,
 
     return sbus_call_dp_autofs_GetMap_send(mem_ctx, be_conn->conn,
                                            be_conn->bus_name, SSS_BUS_PATH,
-                                           DP_FAST_REPLY, data->name.name);
+                                           0, data->name.name);
 }
 
 bool
diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
index 3e47b1321d..ee0156b6af 100644
--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
+++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c
@@ -113,7 +113,7 @@ cache_req_autofs_map_entries_dp_send(TALLOC_CTX *mem_ctx,
 
     return sbus_call_dp_autofs_Enumerate_send(mem_ctx, be_conn->conn,
                                               be_conn->bus_name, SSS_BUS_PATH,
-                                              DP_FAST_REPLY, data->name.name);
+                                              0, data->name.name);
 }
 
 bool

From acf1a0a709bef06c7f0ee672d8321e7904c1e3c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 4 Nov 2020 14:20:10 +0100
Subject: [PATCH 5/5] autofs: correlate errors for different protocol versions

---
 src/sss_client/autofs/autofs_test_client.c | 12 ++++++++
 src/sss_client/autofs/sss_autofs.c         | 34 +++++++++++++++++++---
 src/sss_client/autofs/sss_autofs.exports   |  9 +++---
 src/sss_client/autofs/sss_autofs_private.h |  5 ++++
 4 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/src/sss_client/autofs/autofs_test_client.c b/src/sss_client/autofs/autofs_test_client.c
index c5358233f5..4b285151e0 100644
--- a/src/sss_client/autofs/autofs_test_client.c
+++ b/src/sss_client/autofs/autofs_test_client.c
@@ -45,10 +45,14 @@ int main(int argc, const char *argv[])
     char *value = NULL;
     char *pc_key = NULL;
     int pc_setent = 0;
+    int pc_protocol = 1;
+    unsigned int protocol;
+    unsigned int requested_protocol = 1;
     struct poptOption long_options[] = {
         POPT_AUTOHELP
         { "by-name",  'n', POPT_ARG_STRING, &pc_key, 0, "Request map by name", NULL },
         { "only-setent",  's', POPT_ARG_VAL, &pc_setent, 1, "Run only setent, do not enumerate", NULL },
+        { "protocol",  'p', POPT_ARG_INT, &pc_protocol, 0, "Protocol version", NULL },
         POPT_TABLEEND
     };
     poptContext pc = NULL;
@@ -69,6 +73,14 @@ int main(int argc, const char *argv[])
 
     poptFreeContext(pc);
 
+    requested_protocol = pc_protocol;
+    protocol = _sss_auto_protocol_version(requested_protocol);
+    if (protocol != requested_protocol) {
+        fprintf(stderr, "Unsupported protocol version: %d -> %d\n",
+                requested_protocol, protocol);
+        exit(EXIT_FAILURE);
+    }
+
     ret = _sss_setautomntent(mapname, &ctx);
     if (ret) {
         fprintf(stderr, "setautomntent failed [%d]: %s\n",
diff --git a/src/sss_client/autofs/sss_autofs.c b/src/sss_client/autofs/sss_autofs.c
index 482ff2c400..f0715b97bd 100644
--- a/src/sss_client/autofs/sss_autofs.c
+++ b/src/sss_client/autofs/sss_autofs.c
@@ -33,6 +33,32 @@
 /* How many entries shall _sss_getautomntent_r retrieve at once */
 #define GETAUTOMNTENT_MAX_ENTRIES   512
 
+unsigned int _protocol = 0;
+
+unsigned int _sss_auto_protocol_version(unsigned int requested)
+{
+    switch (requested) {
+    case 0:
+        /* EHOSTDOWN will be translated to ENOENT */
+        _protocol = 0;
+        return 0;
+    default:
+        /* There is no other protocol version at this point. */
+        _protocol = 1;
+        return 1;
+    }
+}
+
+/* Returns correct errno based on autofs version expectations. */
+static errno_t errnop_to_errno(int errnop)
+{
+    if (errnop == EHOSTDOWN && _protocol == 0) {
+        return ENOENT;
+    }
+
+    return errnop;
+}
+
 struct automtent {
     char *mapname;
     size_t cursor;
@@ -93,7 +119,7 @@ _sss_setautomntent(const char *mapname, void **context)
                                   &repbuf, &replen, &errnop);
     if (ret != SSS_STATUS_SUCCESS) {
         free(name);
-        ret = errnop;
+        ret = errnop_to_errno(errnop);
         goto out;
     }
 
@@ -310,7 +336,7 @@ _sss_getautomntent_r(char **key, char **value, void *context)
                                   &repbuf, &replen, &errnop);
     free(data);
     if (ret != SSS_STATUS_SUCCESS) {
-        ret = errnop;
+        ret = errnop_to_errno(errnop);
         goto out;
     }
 
@@ -408,7 +434,7 @@ _sss_getautomntbyname_r(const char *key, char **value, void *context)
                                   &repbuf, &replen, &errnop);
     free(data);
     if (ret != SSS_STATUS_SUCCESS) {
-        ret = errnop;
+        ret = errnop_to_errno(errnop);
         goto out;
     }
 
@@ -467,7 +493,7 @@ _sss_endautomntent(void **context)
     ret = sss_autofs_make_request(SSS_AUTOFS_ENDAUTOMNTENT,
                                   NULL, NULL, NULL, &errnop);
     if (ret != SSS_STATUS_SUCCESS) {
-        ret = errnop;
+        ret = errnop_to_errno(errnop);
         goto out;
     }
 
diff --git a/src/sss_client/autofs/sss_autofs.exports b/src/sss_client/autofs/sss_autofs.exports
index f9ce8f5b2c..ec61f715e4 100644
--- a/src/sss_client/autofs/sss_autofs.exports
+++ b/src/sss_client/autofs/sss_autofs.exports
@@ -2,10 +2,11 @@ EXPORTED {
 
     # public functions
     global:
-                _sss_setautomntent;
-                _sss_getautomntent_r;
-                _sss_getautomntbyname_r;
-                _sss_endautomntent;
+        _sss_auto_protocol_version;
+        _sss_setautomntent;
+        _sss_getautomntent_r;
+        _sss_getautomntbyname_r;
+        _sss_endautomntent;
 
     # everything else is local
     local:
diff --git a/src/sss_client/autofs/sss_autofs_private.h b/src/sss_client/autofs/sss_autofs_private.h
index 6459c1cc7b..7fd49db1dd 100644
--- a/src/sss_client/autofs/sss_autofs_private.h
+++ b/src/sss_client/autofs/sss_autofs_private.h
@@ -21,6 +21,11 @@
 #include <errno.h>
 #include "util/util.h"
 
+/**
+ * Choose an autofs protocol version to be used between autofs and sss_autofs.
+ */
+unsigned int _sss_auto_protocol_version(unsigned int requested);
+
 /**
  * Selects a map for processing.
  */
