From d17b4d1c63f1b85a14a6fe8b2400e2c29158cd43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 6 Nov 2015 13:32:34 +0100
Subject: [PATCH 02/34] SUDO: move refreshes from sdap_sudo.c to
 sdap_sudo_refresh.c

sdap_sudo.c will contain only initialization and handlers.
---
 src/providers/ldap/sdap_sudo.c         | 642 ---------------------------------
 src/providers/ldap/sdap_sudo.h         |  11 +
 src/providers/ldap/sdap_sudo_refresh.c | 628 ++++++++++++++++++++++++++++++++
 3 files changed, 639 insertions(+), 642 deletions(-)

diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c
index 4885564ecb727e6b41441c9ee91f931bc0300cd3..d9537a8774075ca2bd0074ca5543bafce07c7a57 100644
--- a/src/providers/ldap/sdap_sudo.c
+++ b/src/providers/ldap/sdap_sudo.c
@@ -30,45 +30,6 @@
 #include "providers/ldap/sdap_sudo_cache.h"
 #include "db/sysdb_sudo.h"
 
-struct sdap_sudo_full_refresh_state {
-    struct sdap_sudo_ctx *sudo_ctx;
-    struct sdap_id_ctx *id_ctx;
-    struct sysdb_ctx *sysdb;
-    struct sss_domain_info *domain;
-    int dp_error;
-    int error;
-};
-
-static void sdap_sudo_full_refresh_done(struct tevent_req *subreq);
-
-struct sdap_sudo_rules_refresh_state {
-    struct sdap_id_ctx *id_ctx;
-    size_t num_rules;
-    int dp_error;
-    int error;
-};
-
-static struct tevent_req *sdap_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
-                                                       struct sdap_sudo_ctx *sudo_ctx,
-                                                       struct be_ctx *be_ctx,
-                                                       struct sdap_options *opts,
-                                                       struct sdap_id_conn_cache *conn_cache,
-                                                       char **rules);
-
-static void sdap_sudo_rules_refresh_done(struct tevent_req *subreq);
-
-static int sdap_sudo_rules_refresh_recv(struct tevent_req *req,
-                                        int *dp_error,
-                                        int *error);
-
-struct sdap_sudo_smart_refresh_state {
-    struct tevent_req *subreq;
-    struct sdap_id_ctx *id_ctx;
-    struct sysdb_ctx *sysdb;
-};
-
-static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq);
-
 static void
 sdap_sudo_shutdown(struct be_req *req)
 {
@@ -170,168 +131,6 @@ static void sdap_sudo_get_hostinfo_done(struct tevent_req *req)
     }
 }
 
-static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn)
-{
-    unsigned int usn_number;
-    char *endptr = NULL;
-
-    if (srv_opts != NULL && usn != NULL) {
-        talloc_zfree(srv_opts->max_sudo_value);
-        srv_opts->max_sudo_value = talloc_steal(srv_opts, usn);
-
-        usn_number = strtoul(usn, &endptr, 10);
-        if ((endptr == NULL || (*endptr == '\0' && endptr != usn))
-             && (usn_number > srv_opts->last_usn)) {
-             srv_opts->last_usn = usn_number;
-        }
-
-        DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n",
-                                 srv_opts->max_sudo_value);
-    } else {
-        DEBUG(SSSDBG_TRACE_FUNC, "srv_opts is NULL\n");
-    }
-}
-
-static char *sdap_sudo_build_host_filter(TALLOC_CTX *mem_ctx,
-                                         struct sdap_attr_map *map,
-                                         char **hostnames,
-                                         char **ip_addr,
-                                         bool netgroups,
-                                         bool regexp)
-{
-    TALLOC_CTX *tmp_ctx = NULL;
-    char *filter = NULL;
-    int i;
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-        return NULL;
-    }
-
-    filter = talloc_strdup(tmp_ctx, "(|");
-    if (filter == NULL) {
-        goto done;
-    }
-
-    /* sudoHost is not specified */
-    filter = talloc_asprintf_append_buffer(filter, "(!(%s=*))",
-                                           map[SDAP_AT_SUDO_HOST].name);
-    if (filter == NULL) {
-        goto done;
-    }
-
-    /* ALL */
-    filter = talloc_asprintf_append_buffer(filter, "(%s=ALL)",
-                                           map[SDAP_AT_SUDO_HOST].name);
-    if (filter == NULL) {
-        goto done;
-    }
-
-    /* hostnames */
-    if (hostnames != NULL) {
-        for (i = 0; hostnames[i] != NULL; i++) {
-            filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
-                                                   map[SDAP_AT_SUDO_HOST].name,
-                                                   hostnames[i]);
-            if (filter == NULL) {
-                goto done;
-            }
-        }
-    }
-
-    /* ip addresses and networks */
-    if (ip_addr != NULL) {
-        for (i = 0; ip_addr[i] != NULL; i++) {
-            filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
-                                                   map[SDAP_AT_SUDO_HOST].name,
-                                                   ip_addr[i]);
-            if (filter == NULL) {
-                goto done;
-            }
-        }
-    }
-
-    /* sudoHost contains netgroup - will be filtered more by sudo */
-    if (netgroups) {
-        filter = talloc_asprintf_append_buffer(filter, SDAP_SUDO_FILTER_NETGROUP,
-                                               map[SDAP_AT_SUDO_HOST].name,
-                                               "*");
-        if (filter == NULL) {
-            goto done;
-        }
-    }
-
-    /* sudoHost contains regexp - will be filtered more by sudo */
-    /* from sudo match.c :
-     * #define has_meta(s)  (strpbrk(s, "\\?*[]") != NULL)
-     */
-    if (regexp) {
-        filter = talloc_asprintf_append_buffer(filter,
-                                               "(|(%s=*\\\\*)(%s=*?*)(%s=*\\2A*)"
-                                                 "(%s=*[*]*))",
-                                               map[SDAP_AT_SUDO_HOST].name,
-                                               map[SDAP_AT_SUDO_HOST].name,
-                                               map[SDAP_AT_SUDO_HOST].name,
-                                               map[SDAP_AT_SUDO_HOST].name);
-        if (filter == NULL) {
-            goto done;
-        }
-    }
-
-    filter = talloc_strdup_append_buffer(filter, ")");
-    if (filter == NULL) {
-        goto done;
-    }
-
-    talloc_steal(mem_ctx, filter);
-
-done:
-    talloc_free(tmp_ctx);
-
-    return filter;
-}
-
-static char *sdap_sudo_get_filter(TALLOC_CTX *mem_ctx,
-                                  struct sdap_attr_map *map,
-                                  struct sdap_sudo_ctx *sudo_ctx,
-                                  const char *rule_filter)
-{
-    TALLOC_CTX *tmp_ctx = NULL;
-    char *host_filter = NULL;
-    char *filter = NULL;
-
-    if (!sudo_ctx->use_host_filter) {
-        return talloc_strdup(mem_ctx, rule_filter);
-    }
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-        return NULL;
-    }
-
-    host_filter = sdap_sudo_build_host_filter(tmp_ctx, map,
-                                              sudo_ctx->hostnames,
-                                              sudo_ctx->ip_addr,
-                                              sudo_ctx->include_netgroups,
-                                              sudo_ctx->include_regexp);
-    if (host_filter == NULL) {
-        goto done;
-    }
-
-    filter = sdap_get_id_specific_filter(tmp_ctx, rule_filter, host_filter);
-    if (filter == NULL) {
-        goto done;
-    }
-
-    talloc_steal(mem_ctx, filter);
-
-done:
-    talloc_free(tmp_ctx);
-    return filter;
-}
-
 static void sdap_sudo_reply(struct tevent_req *req)
 {
     struct be_req *be_req = NULL;
@@ -412,444 +211,3 @@ void sdap_sudo_handler(struct be_req *be_req)
 fail:
     sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL);
 }
-
-/* issue full refresh of sudo rules */
-struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
-                                               struct sdap_sudo_ctx *sudo_ctx)
-{
-    struct tevent_req *req = NULL;
-    struct tevent_req *subreq = NULL;
-    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
-    struct sdap_sudo_full_refresh_state *state = NULL;
-    char *ldap_filter = NULL;
-    char *ldap_full_filter = NULL;
-    char *sysdb_filter = NULL;
-    int ret;
-
-    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_full_refresh_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-        return NULL;
-    }
-
-    sudo_ctx->full_refresh_in_progress = true;
-
-    state->sudo_ctx = sudo_ctx;
-    state->id_ctx = id_ctx;
-    state->sysdb = id_ctx->be->domain->sysdb;
-    state->domain = id_ctx->be->domain;
-
-    /* Download all rules from LDAP */
-    ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
-                                  id_ctx->opts->sudorule_map[SDAP_OC_SUDORULE].name);
-    if (ldap_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    ldap_full_filter = sdap_sudo_get_filter(state, id_ctx->opts->sudorule_map,
-                                            sudo_ctx, ldap_filter);
-    if (ldap_full_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    /* Remove all rules from cache */
-    sysdb_filter = talloc_asprintf(state, "(%s=%s)",
-                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC);
-    if (sysdb_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n");
-
-    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
-                                    id_ctx->conn->conn_cache,
-                                    ldap_full_filter, sysdb_filter);
-    if (subreq == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    tevent_req_set_callback(subreq, sdap_sudo_full_refresh_done, req);
-
-    /* free filters */
-    talloc_free(ldap_filter);
-    talloc_free(ldap_full_filter);
-    talloc_free(sysdb_filter);
-
-    return req;
-
-immediately:
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-    tevent_req_post(req, id_ctx->be->ev);
-
-    return req;
-}
-
-static void sdap_sudo_full_refresh_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = NULL;
-    struct sdap_sudo_full_refresh_state *state = NULL;
-    char *highest_usn = NULL;
-    int ret;
-
-    req = tevent_req_callback_data(subreq, struct tevent_req);
-    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
-
-    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error,
-                                 &state->error, &highest_usn, NULL);
-    talloc_zfree(subreq);
-    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
-        goto done;
-    }
-
-    state->sudo_ctx->full_refresh_done = true;
-
-    /* save the time in the sysdb */
-    ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL));
-    if (ret != EOK) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of "
-                                     "a successful full refresh\n");
-        /* this is only a minor error that does not affect the functionality,
-         * therefore there is no need to report it with tevent_req_error()
-         * which would cause problems in the consumers */
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n");
-
-    /* set highest usn */
-    if (highest_usn != NULL) {
-        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
-    }
-
-done:
-    state->sudo_ctx->full_refresh_in_progress = false;
-
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
-int sdap_sudo_full_refresh_recv(struct tevent_req *req,
-                                int *dp_error,
-                                int *error)
-{
-    struct sdap_sudo_full_refresh_state *state = NULL;
-    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *dp_error = state->dp_error;
-    *error = state->error;
-
-    return EOK;
-}
-
-/* issue refresh of specific sudo rules */
-static struct tevent_req *sdap_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
-                                                       struct sdap_sudo_ctx *sudo_ctx,
-                                                       struct be_ctx *be_ctx,
-                                                       struct sdap_options *opts,
-                                                       struct sdap_id_conn_cache *conn_cache,
-                                                       char **rules)
-{
-    struct tevent_req *req = NULL;
-    struct tevent_req *subreq = NULL;
-    struct sdap_sudo_rules_refresh_state *state = NULL;
-    TALLOC_CTX *tmp_ctx = NULL;
-    char *ldap_filter = NULL;
-    char *ldap_full_filter = NULL;
-    char *sysdb_filter = NULL;
-    char *safe_rule = NULL;
-    int ret;
-    int i;
-
-    if (rules == NULL) {
-        return NULL;
-    }
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-        return NULL;
-    }
-
-    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_rules_refresh_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-        return NULL;
-    }
-
-    ldap_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
-    sysdb_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
-
-    /* Download only selected rules from LDAP */
-    /* Remove all selected rules from cache */
-    for (i = 0; rules[i] != NULL; i++) {
-        ret = sss_filter_sanitize(tmp_ctx, rules[i], &safe_rule);
-        if (ret != EOK) {
-            ret = ENOMEM;
-            goto immediately;
-        }
-
-        ldap_filter = talloc_asprintf_append_buffer(ldap_filter, "(%s=%s)",
-                                     opts->sudorule_map[SDAP_AT_SUDO_NAME].name,
-                                     safe_rule);
-        if (ldap_filter == NULL) {
-            ret = ENOMEM;
-            goto immediately;
-        }
-
-        sysdb_filter = talloc_asprintf_append_buffer(sysdb_filter, "(%s=%s)",
-                                                     SYSDB_SUDO_CACHE_AT_CN,
-                                                     safe_rule);
-        if (sysdb_filter == NULL) {
-            ret = ENOMEM;
-            goto immediately;
-        }
-    }
-
-    state->id_ctx = sudo_ctx->id_ctx;
-    state->num_rules = i;
-
-    ldap_filter = talloc_asprintf(tmp_ctx, "(&"SDAP_SUDO_FILTER_CLASS"(|%s))",
-                                  opts->sudorule_map[SDAP_OC_SUDORULE].name,
-                                  ldap_filter);
-    if (ldap_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    ldap_full_filter = sdap_sudo_get_filter(tmp_ctx, opts->sudorule_map,
-                                            sudo_ctx, ldap_filter);
-    if (ldap_full_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    sysdb_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|%s))",
-                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC,
-                                   sysdb_filter);
-    if (sysdb_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    subreq = sdap_sudo_refresh_send(req, be_ctx, opts, conn_cache,
-                                    ldap_full_filter, sysdb_filter);
-    if (subreq == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    tevent_req_set_callback(subreq, sdap_sudo_rules_refresh_done, req);
-
-    ret = EOK;
-immediately:
-    talloc_free(tmp_ctx);
-
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        tevent_req_post(req, be_ctx->ev);
-    }
-
-    return req;
-}
-
-static void sdap_sudo_rules_refresh_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = NULL;
-    struct sdap_sudo_rules_refresh_state *state = NULL;
-    char *highest_usn = NULL;
-    size_t downloaded_rules_num;
-    int ret;
-
-    req = tevent_req_callback_data(subreq, struct tevent_req);
-    state = tevent_req_data(req, struct sdap_sudo_rules_refresh_state);
-
-    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error, &state->error,
-                                 &highest_usn, &downloaded_rules_num);
-    talloc_zfree(subreq);
-    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
-        goto done;
-    }
-
-    /* set highest usn */
-    if (highest_usn != NULL) {
-        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
-    }
-
-    if (downloaded_rules_num != state->num_rules) {
-        state->error = ENOENT;
-    }
-
-done:
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
-static int sdap_sudo_rules_refresh_recv(struct tevent_req *req,
-                                        int *dp_error,
-                                        int *error)
-{
-    struct sdap_sudo_rules_refresh_state *state = NULL;
-    state = tevent_req_data(req, struct sdap_sudo_rules_refresh_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *dp_error = state->dp_error;
-    *error = state->error;
-
-    return EOK;
-}
-
-/* issue smart refresh of sudo rules */
-struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx,
-                                                struct sdap_sudo_ctx *sudo_ctx)
-{
-    struct tevent_req *req = NULL;
-    struct tevent_req *subreq = NULL;
-    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
-    struct sdap_attr_map *map = id_ctx->opts->sudorule_map;
-    struct sdap_server_opts *srv_opts = id_ctx->srv_opts;
-    struct sdap_sudo_smart_refresh_state *state = NULL;
-    char *ldap_filter = NULL;
-    char *ldap_full_filter = NULL;
-    const char *usn;
-    int ret;
-
-    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_smart_refresh_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-        return NULL;
-    }
-
-    if (!sudo_ctx->full_refresh_done
-            && (srv_opts == NULL || srv_opts->max_sudo_value == 0)) {
-        /* Perform full refresh first */
-        DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, "
-                                  "waiting for full refresh!\n");
-        ret = EINVAL;
-        goto immediately;
-    }
-
-    state->id_ctx = id_ctx;
-    state->sysdb = id_ctx->be->domain->sysdb;
-
-    /* Download all rules from LDAP that are newer than usn */
-    usn = srv_opts->max_sudo_value;
-    if (usn != NULL) {
-        ldap_filter = talloc_asprintf(state,
-                                      "(&(objectclass=%s)(%s>=%s)(!(%s=%s)))",
-                                      map[SDAP_OC_SUDORULE].name,
-                                      map[SDAP_AT_SUDO_USN].name, usn,
-                                      map[SDAP_AT_SUDO_USN].name, usn);
-    } else {
-        /* no valid USN value known */
-        ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
-                                      map[SDAP_OC_SUDORULE].name);
-    }
-    if (ldap_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    ldap_full_filter = sdap_sudo_get_filter(state, map, sudo_ctx, ldap_filter);
-    if (ldap_full_filter == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    /* Do not remove any rules that are already in the sysdb
-     * sysdb_filter = NULL; */
-
-    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules "
-                              "(USN > %s)\n", (usn == NULL ? "0" : usn));
-
-    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
-                                    id_ctx->conn->conn_cache,
-                                    ldap_full_filter, NULL);
-    if (subreq == NULL) {
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    state->subreq = subreq;
-    tevent_req_set_callback(subreq, sdap_sudo_smart_refresh_done, req);
-
-    /* free filters */
-    talloc_free(ldap_filter);
-    talloc_free(ldap_full_filter);
-
-    return req;
-
-immediately:
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-    tevent_req_post(req, id_ctx->be->ev);
-
-    return req;
-}
-
-static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = NULL;
-    struct sdap_sudo_smart_refresh_state *state = NULL;
-    char *highest_usn = NULL;
-    int dp_error;
-    int error;
-    int ret;
-
-    req = tevent_req_callback_data(subreq, struct tevent_req);
-    state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state);
-
-    ret = sdap_sudo_refresh_recv(state, subreq, &dp_error, &error,
-                                 &highest_usn, NULL);
-    if (ret != EOK || dp_error != DP_ERR_OK || error != EOK) {
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "Successful smart refresh of sudo rules\n");
-
-    /* set highest usn */
-    if (highest_usn != NULL) {
-        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
-    }
-
-done:
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    tevent_req_done(req);
-}
-
-int sdap_sudo_smart_refresh_recv(struct tevent_req *req,
-                                 int *dp_error,
-                                 int *error)
-{
-    struct sdap_sudo_smart_refresh_state *state = NULL;
-    state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return sdap_sudo_refresh_recv(state, state->subreq, dp_error, error,
-                                  NULL, NULL);
-}
diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h
index 51e99f561b0f195e1b78e6fd8926f5b9b341ee72..466f7f0a4bc2f99b190da53b6deebea0ffa379f3 100644
--- a/src/providers/ldap/sdap_sudo.h
+++ b/src/providers/ldap/sdap_sudo.h
@@ -73,6 +73,17 @@ int sdap_sudo_smart_refresh_recv(struct tevent_req *req,
                                  int *dp_error,
                                  int *error);
 
+struct tevent_req *sdap_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
+                                                struct sdap_sudo_ctx *sudo_ctx,
+                                                struct be_ctx *be_ctx,
+                                                struct sdap_options *opts,
+                                                struct sdap_id_conn_cache *conn_cache,
+                                                char **rules);
+
+int sdap_sudo_rules_refresh_recv(struct tevent_req *req,
+                                 int *dp_error,
+                                 int *error);
+
 errno_t
 sdap_sudo_ptask_setup(struct be_ctx *be_ctx, struct sdap_sudo_ctx *sudo_ctx);
 
diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c
index 39821840a8a550dcc1a6c954dfb53fc73245e9f6..b350569baa68043d979bfa21f86d5af76e404f26 100644
--- a/src/providers/ldap/sdap_sudo_refresh.c
+++ b/src/providers/ldap/sdap_sudo_refresh.c
@@ -27,6 +27,634 @@
 #include "providers/ldap/sdap_sudo.h"
 #include "db/sysdb_sudo.h"
 
+static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn)
+{
+    unsigned int usn_number;
+    char *endptr = NULL;
+
+    if (srv_opts != NULL && usn != NULL) {
+        talloc_zfree(srv_opts->max_sudo_value);
+        srv_opts->max_sudo_value = talloc_steal(srv_opts, usn);
+
+        usn_number = strtoul(usn, &endptr, 10);
+        if ((endptr == NULL || (*endptr == '\0' && endptr != usn))
+             && (usn_number > srv_opts->last_usn)) {
+             srv_opts->last_usn = usn_number;
+        }
+
+        DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n",
+                                 srv_opts->max_sudo_value);
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, "srv_opts is NULL\n");
+    }
+}
+
+static char *sdap_sudo_build_host_filter(TALLOC_CTX *mem_ctx,
+                                         struct sdap_attr_map *map,
+                                         char **hostnames,
+                                         char **ip_addr,
+                                         bool netgroups,
+                                         bool regexp)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    char *filter = NULL;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return NULL;
+    }
+
+    filter = talloc_strdup(tmp_ctx, "(|");
+    if (filter == NULL) {
+        goto done;
+    }
+
+    /* sudoHost is not specified */
+    filter = talloc_asprintf_append_buffer(filter, "(!(%s=*))",
+                                           map[SDAP_AT_SUDO_HOST].name);
+    if (filter == NULL) {
+        goto done;
+    }
+
+    /* ALL */
+    filter = talloc_asprintf_append_buffer(filter, "(%s=ALL)",
+                                           map[SDAP_AT_SUDO_HOST].name);
+    if (filter == NULL) {
+        goto done;
+    }
+
+    /* hostnames */
+    if (hostnames != NULL) {
+        for (i = 0; hostnames[i] != NULL; i++) {
+            filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
+                                                   map[SDAP_AT_SUDO_HOST].name,
+                                                   hostnames[i]);
+            if (filter == NULL) {
+                goto done;
+            }
+        }
+    }
+
+    /* ip addresses and networks */
+    if (ip_addr != NULL) {
+        for (i = 0; ip_addr[i] != NULL; i++) {
+            filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
+                                                   map[SDAP_AT_SUDO_HOST].name,
+                                                   ip_addr[i]);
+            if (filter == NULL) {
+                goto done;
+            }
+        }
+    }
+
+    /* sudoHost contains netgroup - will be filtered more by sudo */
+    if (netgroups) {
+        filter = talloc_asprintf_append_buffer(filter, SDAP_SUDO_FILTER_NETGROUP,
+                                               map[SDAP_AT_SUDO_HOST].name,
+                                               "*");
+        if (filter == NULL) {
+            goto done;
+        }
+    }
+
+    /* sudoHost contains regexp - will be filtered more by sudo */
+    /* from sudo match.c :
+     * #define has_meta(s)  (strpbrk(s, "\\?*[]") != NULL)
+     */
+    if (regexp) {
+        filter = talloc_asprintf_append_buffer(filter,
+                                               "(|(%s=*\\\\*)(%s=*?*)(%s=*\\2A*)"
+                                                 "(%s=*[*]*))",
+                                               map[SDAP_AT_SUDO_HOST].name,
+                                               map[SDAP_AT_SUDO_HOST].name,
+                                               map[SDAP_AT_SUDO_HOST].name,
+                                               map[SDAP_AT_SUDO_HOST].name);
+        if (filter == NULL) {
+            goto done;
+        }
+    }
+
+    filter = talloc_strdup_append_buffer(filter, ")");
+    if (filter == NULL) {
+        goto done;
+    }
+
+    talloc_steal(mem_ctx, filter);
+
+done:
+    talloc_free(tmp_ctx);
+
+    return filter;
+}
+
+static char *sdap_sudo_get_filter(TALLOC_CTX *mem_ctx,
+                                  struct sdap_attr_map *map,
+                                  struct sdap_sudo_ctx *sudo_ctx,
+                                  const char *rule_filter)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    char *host_filter = NULL;
+    char *filter = NULL;
+
+    if (!sudo_ctx->use_host_filter) {
+        return talloc_strdup(mem_ctx, rule_filter);
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return NULL;
+    }
+
+    host_filter = sdap_sudo_build_host_filter(tmp_ctx, map,
+                                              sudo_ctx->hostnames,
+                                              sudo_ctx->ip_addr,
+                                              sudo_ctx->include_netgroups,
+                                              sudo_ctx->include_regexp);
+    if (host_filter == NULL) {
+        goto done;
+    }
+
+    filter = sdap_get_id_specific_filter(tmp_ctx, rule_filter, host_filter);
+    if (filter == NULL) {
+        goto done;
+    }
+
+    talloc_steal(mem_ctx, filter);
+
+done:
+    talloc_free(tmp_ctx);
+    return filter;
+}
+
+struct sdap_sudo_full_refresh_state {
+    struct sdap_sudo_ctx *sudo_ctx;
+    struct sdap_id_ctx *id_ctx;
+    struct sysdb_ctx *sysdb;
+    struct sss_domain_info *domain;
+    int dp_error;
+    int error;
+};
+
+static void sdap_sudo_full_refresh_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
+                                               struct sdap_sudo_ctx *sudo_ctx)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
+    struct sdap_sudo_full_refresh_state *state = NULL;
+    char *ldap_filter = NULL;
+    char *ldap_full_filter = NULL;
+    char *sysdb_filter = NULL;
+    int ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_full_refresh_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+        return NULL;
+    }
+
+    sudo_ctx->full_refresh_in_progress = true;
+
+    state->sudo_ctx = sudo_ctx;
+    state->id_ctx = id_ctx;
+    state->sysdb = id_ctx->be->domain->sysdb;
+    state->domain = id_ctx->be->domain;
+
+    /* Download all rules from LDAP */
+    ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
+                                  id_ctx->opts->sudorule_map[SDAP_OC_SUDORULE].name);
+    if (ldap_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    ldap_full_filter = sdap_sudo_get_filter(state, id_ctx->opts->sudorule_map,
+                                            sudo_ctx, ldap_filter);
+    if (ldap_full_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    /* Remove all rules from cache */
+    sysdb_filter = talloc_asprintf(state, "(%s=%s)",
+                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC);
+    if (sysdb_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n");
+
+    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
+                                    id_ctx->conn->conn_cache,
+                                    ldap_full_filter, sysdb_filter);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    tevent_req_set_callback(subreq, sdap_sudo_full_refresh_done, req);
+
+    /* free filters */
+    talloc_free(ldap_filter);
+    talloc_free(ldap_full_filter);
+    talloc_free(sysdb_filter);
+
+    return req;
+
+immediately:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, id_ctx->be->ev);
+
+    return req;
+}
+
+static void sdap_sudo_full_refresh_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_sudo_full_refresh_state *state = NULL;
+    char *highest_usn = NULL;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
+
+    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error,
+                                 &state->error, &highest_usn, NULL);
+    talloc_zfree(subreq);
+    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
+        goto done;
+    }
+
+    state->sudo_ctx->full_refresh_done = true;
+
+    /* save the time in the sysdb */
+    ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL));
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of "
+                                     "a successful full refresh\n");
+        /* this is only a minor error that does not affect the functionality,
+         * therefore there is no need to report it with tevent_req_error()
+         * which would cause problems in the consumers */
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n");
+
+    /* set highest usn */
+    if (highest_usn != NULL) {
+        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
+    }
+
+done:
+    state->sudo_ctx->full_refresh_in_progress = false;
+
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+int sdap_sudo_full_refresh_recv(struct tevent_req *req,
+                                int *dp_error,
+                                int *error)
+{
+    struct sdap_sudo_full_refresh_state *state = NULL;
+    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *dp_error = state->dp_error;
+    *error = state->error;
+
+    return EOK;
+}
+
+struct sdap_sudo_smart_refresh_state {
+    struct tevent_req *subreq;
+    struct sdap_id_ctx *id_ctx;
+    struct sysdb_ctx *sysdb;
+};
+
+static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx,
+                                                struct sdap_sudo_ctx *sudo_ctx)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
+    struct sdap_attr_map *map = id_ctx->opts->sudorule_map;
+    struct sdap_server_opts *srv_opts = id_ctx->srv_opts;
+    struct sdap_sudo_smart_refresh_state *state = NULL;
+    char *ldap_filter = NULL;
+    char *ldap_full_filter = NULL;
+    const char *usn;
+    int ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_smart_refresh_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+        return NULL;
+    }
+
+    if (!sudo_ctx->full_refresh_done
+            && (srv_opts == NULL || srv_opts->max_sudo_value == 0)) {
+        /* Perform full refresh first */
+        DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, "
+                                  "waiting for full refresh!\n");
+        ret = EINVAL;
+        goto immediately;
+    }
+
+    state->id_ctx = id_ctx;
+    state->sysdb = id_ctx->be->domain->sysdb;
+
+    /* Download all rules from LDAP that are newer than usn */
+    usn = srv_opts->max_sudo_value;
+    if (usn != NULL) {
+        ldap_filter = talloc_asprintf(state,
+                                      "(&(objectclass=%s)(%s>=%s)(!(%s=%s)))",
+                                      map[SDAP_OC_SUDORULE].name,
+                                      map[SDAP_AT_SUDO_USN].name, usn,
+                                      map[SDAP_AT_SUDO_USN].name, usn);
+    } else {
+        /* no valid USN value known */
+        ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
+                                      map[SDAP_OC_SUDORULE].name);
+    }
+    if (ldap_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    ldap_full_filter = sdap_sudo_get_filter(state, map, sudo_ctx, ldap_filter);
+    if (ldap_full_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    /* Do not remove any rules that are already in the sysdb
+     * sysdb_filter = NULL; */
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules "
+                              "(USN > %s)\n", (usn == NULL ? "0" : usn));
+
+    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
+                                    id_ctx->conn->conn_cache,
+                                    ldap_full_filter, NULL);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    state->subreq = subreq;
+    tevent_req_set_callback(subreq, sdap_sudo_smart_refresh_done, req);
+
+    /* free filters */
+    talloc_free(ldap_filter);
+    talloc_free(ldap_full_filter);
+
+    return req;
+
+immediately:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, id_ctx->be->ev);
+
+    return req;
+}
+
+static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_sudo_smart_refresh_state *state = NULL;
+    char *highest_usn = NULL;
+    int dp_error;
+    int error;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state);
+
+    ret = sdap_sudo_refresh_recv(state, subreq, &dp_error, &error,
+                                 &highest_usn, NULL);
+    if (ret != EOK || dp_error != DP_ERR_OK || error != EOK) {
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Successful smart refresh of sudo rules\n");
+
+    /* set highest usn */
+    if (highest_usn != NULL) {
+        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
+    }
+
+done:
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+int sdap_sudo_smart_refresh_recv(struct tevent_req *req,
+                                 int *dp_error,
+                                 int *error)
+{
+    struct sdap_sudo_smart_refresh_state *state = NULL;
+    state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return sdap_sudo_refresh_recv(state, state->subreq, dp_error, error,
+                                  NULL, NULL);
+}
+
+struct sdap_sudo_rules_refresh_state {
+    struct sdap_id_ctx *id_ctx;
+    size_t num_rules;
+    int dp_error;
+    int error;
+};
+
+static void sdap_sudo_rules_refresh_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
+                                                struct sdap_sudo_ctx *sudo_ctx,
+                                                struct be_ctx *be_ctx,
+                                                struct sdap_options *opts,
+                                                struct sdap_id_conn_cache *conn_cache,
+                                                char **rules)
+{
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    struct sdap_sudo_rules_refresh_state *state = NULL;
+    TALLOC_CTX *tmp_ctx = NULL;
+    char *ldap_filter = NULL;
+    char *ldap_full_filter = NULL;
+    char *sysdb_filter = NULL;
+    char *safe_rule = NULL;
+    int ret;
+    int i;
+
+    if (rules == NULL) {
+        return NULL;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return NULL;
+    }
+
+    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_rules_refresh_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+        return NULL;
+    }
+
+    ldap_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
+    sysdb_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
+
+    /* Download only selected rules from LDAP */
+    /* Remove all selected rules from cache */
+    for (i = 0; rules[i] != NULL; i++) {
+        ret = sss_filter_sanitize(tmp_ctx, rules[i], &safe_rule);
+        if (ret != EOK) {
+            ret = ENOMEM;
+            goto immediately;
+        }
+
+        ldap_filter = talloc_asprintf_append_buffer(ldap_filter, "(%s=%s)",
+                                     opts->sudorule_map[SDAP_AT_SUDO_NAME].name,
+                                     safe_rule);
+        if (ldap_filter == NULL) {
+            ret = ENOMEM;
+            goto immediately;
+        }
+
+        sysdb_filter = talloc_asprintf_append_buffer(sysdb_filter, "(%s=%s)",
+                                                     SYSDB_SUDO_CACHE_AT_CN,
+                                                     safe_rule);
+        if (sysdb_filter == NULL) {
+            ret = ENOMEM;
+            goto immediately;
+        }
+    }
+
+    state->id_ctx = sudo_ctx->id_ctx;
+    state->num_rules = i;
+
+    ldap_filter = talloc_asprintf(tmp_ctx, "(&"SDAP_SUDO_FILTER_CLASS"(|%s))",
+                                  opts->sudorule_map[SDAP_OC_SUDORULE].name,
+                                  ldap_filter);
+    if (ldap_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    ldap_full_filter = sdap_sudo_get_filter(tmp_ctx, opts->sudorule_map,
+                                            sudo_ctx, ldap_filter);
+    if (ldap_full_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    sysdb_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|%s))",
+                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC,
+                                   sysdb_filter);
+    if (sysdb_filter == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    subreq = sdap_sudo_refresh_send(req, be_ctx, opts, conn_cache,
+                                    ldap_full_filter, sysdb_filter);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    tevent_req_set_callback(subreq, sdap_sudo_rules_refresh_done, req);
+
+    ret = EOK;
+immediately:
+    talloc_free(tmp_ctx);
+
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        tevent_req_post(req, be_ctx->ev);
+    }
+
+    return req;
+}
+
+static void sdap_sudo_rules_refresh_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_sudo_rules_refresh_state *state = NULL;
+    char *highest_usn = NULL;
+    size_t downloaded_rules_num;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_rules_refresh_state);
+
+    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error, &state->error,
+                                 &highest_usn, &downloaded_rules_num);
+    talloc_zfree(subreq);
+    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
+        goto done;
+    }
+
+    /* set highest usn */
+    if (highest_usn != NULL) {
+        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
+    }
+
+    if (downloaded_rules_num != state->num_rules) {
+        state->error = ENOENT;
+    }
+
+done:
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+int sdap_sudo_rules_refresh_recv(struct tevent_req *req,
+                                 int *dp_error,
+                                 int *error)
+{
+    struct sdap_sudo_rules_refresh_state *state = NULL;
+    state = tevent_req_data(req, struct sdap_sudo_rules_refresh_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *dp_error = state->dp_error;
+    *error = state->error;
+
+    return EOK;
+}
+
 static struct tevent_req *
 sdap_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx,
                                   struct tevent_context *ev,
-- 
2.1.0

