diff options
author | Pavel Březina <pbrezina@redhat.com> | 2015-11-06 13:32:34 +0100 |
---|---|---|
committer | Lukas Slebodnik <lslebodn@redhat.com> | 2015-12-15 16:26:33 +0100 |
commit | 00fea5c2aaa0277bea522d2f61de75699ee2ed49 (patch) | |
tree | cf5cbb3941b4c33c2edc7b2ba81c2028e55d241e /src/providers | |
parent | a13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92 (diff) | |
download | sssd-00fea5c2aaa0277bea522d2f61de75699ee2ed49.tar.gz sssd-00fea5c2aaa0277bea522d2f61de75699ee2ed49.tar.xz sssd-00fea5c2aaa0277bea522d2f61de75699ee2ed49.zip |
SUDO: move refreshes from sdap_sudo.c to sdap_sudo_refresh.c
sdap_sudo.c will contain only initialization and handlers.
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/providers')
-rw-r--r-- | src/providers/ldap/sdap_sudo.c | 642 | ||||
-rw-r--r-- | src/providers/ldap/sdap_sudo.h | 11 | ||||
-rw-r--r-- | 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 4885564ec..d9537a877 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 51e99f561..466f7f0a4 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 39821840a..617548cf5 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, |