diff --git a/0001-Fix-minor-typos.patch b/0001-Fix-minor-typos.patch new file mode 100644 index 0000000..d2a725e --- /dev/null +++ b/0001-Fix-minor-typos.patch @@ -0,0 +1,122 @@ +From 77e5c3fc26085f18277a70ffbd6351a8130963e7 Mon Sep 17 00:00:00 2001 +From: Yuri Chornoivan +Date: Wed, 26 Jul 2017 16:45:35 +0300 +Subject: [PATCH 01/93] Fix minor typos +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merges: https://pagure.io/SSSD/sssd/pull-request/3456 + +Reviewed-by: Michal Židek +--- + src/config/SSSDConfig/__init__.py.in | 6 +++--- + src/db/sysdb.h | 2 +- + src/man/sss-certmap.5.xml | 2 +- + src/man/sssd-ad.5.xml | 4 ++-- + src/man/sssd.conf.5.xml | 2 +- + src/providers/ad/ad_machine_pw_renewal.c | 2 +- + 6 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index cd844ce2b45beefc3fc48f6ab09dc427c646ac8d..303bc62f42691e3f21aae393a301742f090e6f82 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -92,7 +92,7 @@ option_strings = { + 'offline_failed_login_attempts' : _('How many failed logins attempts are allowed when offline'), + 'offline_failed_login_delay' : _('How long (minutes) to deny login after offline_failed_login_attempts has been reached'), + 'pam_verbosity' : _('What kind of messages are displayed to the user during authentication'), +- 'pam_response_filter' : _('Filter PAM responses send the pam_sss'), ++ 'pam_response_filter' : _('Filter PAM responses sent by the pam_sss'), + 'pam_id_timeout' : _('How many seconds to keep identity information cached for PAM requests'), + 'pam_pwd_expiration_warning' : _('How many days before password expiration a warning should be displayed'), + 'pam_trusted_users' : _('List of trusted uids or user\'s name'), +@@ -100,7 +100,7 @@ option_strings = { + 'pam_account_expired_message' : _('Message printed when user account is expired.'), + 'pam_account_locked_message' : _('Message printed when user account is locked.'), + 'pam_cert_auth' : _('Allow certificate based/Smartcard authentication.'), +- 'pam_cert_db_path' : _('Path to certificate databse with PKCS#11 modules.'), ++ 'pam_cert_db_path' : _('Path to certificate database with PKCS#11 modules.'), + 'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'), + 'pam_app_services' : _('Which PAM services are permitted to contact application domains'), + +@@ -238,7 +238,7 @@ option_strings = { + 'ad_gpo_default_right' : _('Default logon right (or permit/deny) to use for unmapped PAM service names'), + 'ad_site' : _('a particular site to be used by the client'), + 'ad_maximum_machine_account_password_age' : _('Maximum age in days before the machine account password should be renewed'), +- 'ad_machine_account_password_renewal_opts' : _('Option for tuing the machine account renewal task'), ++ 'ad_machine_account_password_renewal_opts' : _('Option for tuning the machine account renewal task'), + + # [provider/krb5] + 'krb5_kdcip' : _('Kerberos server address'), +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 21d6cf4fc90a050e203e1609be5ee267a618dda9..b045684db0c8e6e68842b72b3830481b73cf2cbe 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -819,7 +819,7 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + const char **attributes, + struct ldb_result **res); + +-/* functions that modify the databse ++/* functions that modify the database + * they have to be called within a transaction + * See sysdb_transaction_send()/_recv() */ + +diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml +index bbe68509f2222613a7ed69599519d7fca0506df0..12df6a7936dfe4346a05d7baffe6f44fed8e1879 100644 +--- a/src/man/sss-certmap.5.xml ++++ b/src/man/sss-certmap.5.xml +@@ -359,7 +359,7 @@ + This should be preferred to read user specific data from the + certificate like e.g. an email address and search for it in the LDAP + server. The reason is that the user specific data in LDAP might +- change for various reasons would would break the mapping. On the ++ change for various reasons would break the mapping. On the + other hand it would be hard to break the mapping on purpose for a + specific user. + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index cd25bf7fa34b7c779d17f781db599740198c663c..59c23e68123d7b83c19ed6ba256989ab4e643b6d 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -827,9 +827,9 @@ ad_gpo_map_deny = +my_pam_service + + This option should only be used to test the machine + account renewal task. The option expect 2 integers +- seperated by a colon (':'). The first integer ++ separated by a colon (':'). The first integer + defines the interval in seconds how often the task +- is run. The second specifies the inital timeout in ++ is run. The second specifies the initial timeout in + seconds before the task is run for the first time + after startup. + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 22daf30990845af33e1cbd5316cbd790924d86f0..7c4cd1f2e5c453964def9c04967f9adc232bb776 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1098,7 +1098,7 @@ fallback_homedir = /home/%u + + + A comma separated list of strings which allows to +- remove (filter) data send by the PAM responder to ++ remove (filter) data sent by the PAM responder to + pam_sss PAM module. There are different kind of + responses send to pam_sss e.g. messages displayed to + the user or environment variables which should be +diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c +index fd7666e3578007c42375cf1f8b4b8c267f248ebd..5b6ba26b72ba441e200c4a81e1faef127e216b6b 100644 +--- a/src/providers/ad/ad_machine_pw_renewal.c ++++ b/src/providers/ad/ad_machine_pw_renewal.c +@@ -88,7 +88,7 @@ static errno_t get_adcli_extra_args(const char *ad_domain, + talloc_free(args); + return ENOMEM; + } +- } while (c != 1); /* is is expected that the first element is NULL */ ++ } while (c != 1); /* it is expected that the first element is NULL */ + + renewal_data->extra_args = args; + +-- +2.14.1 + diff --git a/0002-CACHE_REQ-Propagate-num_results-to-cache_req_state.patch b/0002-CACHE_REQ-Propagate-num_results-to-cache_req_state.patch new file mode 100644 index 0000000..08b2854 --- /dev/null +++ b/0002-CACHE_REQ-Propagate-num_results-to-cache_req_state.patch @@ -0,0 +1,54 @@ +From cb89693cf5ccdedf69fa304c6d43d618a7bc18b2 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 24 Mar 2017 16:24:22 +0200 +Subject: [PATCH 02/93] CACHE_REQ: Propagate num_results to cache_req_state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The num_results field in struct cache_req_state was only set in case of +well-known objects, set it also for the regular results for uniformity, +and for later use by session recording code. + +Reviewed-by: Pavel Březina +--- + src/responder/common/cache_req/cache_req.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 7d77eb7dd72a7ccf3d687eee8f746ab84176b487..84a9b1cb0ad22a9d6fcb31bc1ac1d013098e62df 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -614,7 +614,8 @@ done: + static errno_t + cache_req_search_domains_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, +- struct cache_req_result ***_results) ++ struct cache_req_result ***_results, ++ size_t *_num_results) + { + struct cache_req_search_domains_state *state; + +@@ -625,6 +626,9 @@ cache_req_search_domains_recv(TALLOC_CTX *mem_ctx, + if (_results != NULL) { + *_results = talloc_steal(mem_ctx, state->results); + } ++ if (_num_results != NULL) { ++ *_num_results = state->num_results; ++ } + + return EOK; + } +@@ -1010,7 +1014,8 @@ static void cache_req_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct cache_req_state); + +- ret = cache_req_search_domains_recv(state, subreq, &state->results); ++ ret = cache_req_search_domains_recv(state, subreq, ++ &state->results, &state->num_results); + talloc_zfree(subreq); + + if (ret == ENOENT && state->first_iteration) { +-- +2.14.1 + diff --git a/0003-NSS-Move-shell-options-to-common-responder.patch b/0003-NSS-Move-shell-options-to-common-responder.patch new file mode 100644 index 0000000..6299ed8 --- /dev/null +++ b/0003-NSS-Move-shell-options-to-common-responder.patch @@ -0,0 +1,416 @@ +From c31065ecc0793e836066035d0c692b050b5f6f55 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Wed, 29 Mar 2017 16:07:52 +0300 +Subject: [PATCH 03/93] NSS: Move shell options to common responder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move all the shell-related options from the NSS responder context to the +common responder context, so they can be used by other responders for +retrieving original user shell, when it is overrided for session +recording. + +Reviewed-by: Pavel Březina +--- + src/responder/common/responder.h | 7 +++ + src/responder/common/responder_common.c | 100 ++++++++++++++++++++++++++++++++ + src/responder/nss/nss_private.h | 6 -- + src/responder/nss/nss_protocol_pwent.c | 42 +++++++------- + src/responder/nss/nsssrv.c | 99 ------------------------------- + 5 files changed, 128 insertions(+), 126 deletions(-) + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index b0e3e05b9d0f7890fda3a2596b8ffc5a7ec2d205..7a998967f2761b1c813a866f34cf78d549ede1b9 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -139,6 +139,13 @@ struct resp_ctx { + char *default_domain; + char override_space; + ++ char **allowed_shells; ++ char *override_shell; ++ char **vetoed_shells; ++ char **etc_shells; ++ char *shell_fallback; ++ char *default_shell; ++ + uint32_t cache_req_num; + + void *pvt_ctx; +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 74c424c7bae5de3b900261cb9f958ee4414403dd..edf6a34bda9730f32fac503ae88951390da51612 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -50,6 +50,9 @@ + #include + #endif + ++#define SHELL_REALLOC_INCREMENT 5 ++#define SHELL_REALLOC_MAX 50 ++ + static errno_t set_close_on_exec(int fd) + { + int v; +@@ -1062,6 +1065,72 @@ done: + return ret; + } + ++static errno_t sss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells) ++{ ++ int i = 0; ++ char *sh; ++ char **shells = NULL; ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret; ++ int size; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (!tmp_ctx) return ENOMEM; ++ ++ shells = talloc_array(tmp_ctx, char *, SHELL_REALLOC_INCREMENT); ++ if (!shells) { ++ ret = ENOMEM; ++ goto done; ++ } ++ size = SHELL_REALLOC_INCREMENT; ++ ++ setusershell(); ++ while ((sh = getusershell())) { ++ shells[i] = talloc_strdup(shells, sh); ++ if (!shells[i]) { ++ endusershell(); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_FUNC, "Found shell %s in /etc/shells\n", shells[i]); ++ i++; ++ ++ if (i == size) { ++ size += SHELL_REALLOC_INCREMENT; ++ if (size > SHELL_REALLOC_MAX) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Reached maximum number of shells [%d]. " ++ "Users may be denied access. " ++ "Please check /etc/shells for sanity\n", ++ SHELL_REALLOC_MAX); ++ break; ++ } ++ shells = talloc_realloc(NULL, shells, char *, ++ size); ++ if (!shells) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } ++ endusershell(); ++ ++ if (i + 1 < size) { ++ shells = talloc_realloc(NULL, shells, char *, i + 1); ++ if (!shells) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ shells[i] = NULL; ++ ++ *_shells = talloc_move(mem_ctx, &shells); ++ ret = EOK; ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ + int sss_process_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct confdb_ctx *cdb, +@@ -1201,6 +1270,37 @@ int sss_process_init(TALLOC_CTX *mem_ctx, + ret, sss_strerror(ret)); + } + ++ /* Read shell settings */ ++ ret = confdb_get_string(cdb, rctx, CONFDB_NSS_CONF_ENTRY, ++ CONFDB_NSS_OVERRIDE_SHELL, NULL, ++ &rctx->override_shell); ++ if (ret != EOK && ret != ENOENT) goto fail; ++ ++ ret = confdb_get_string_as_list(cdb, rctx, CONFDB_NSS_CONF_ENTRY, ++ CONFDB_NSS_ALLOWED_SHELL, ++ &rctx->allowed_shells); ++ if (ret != EOK && ret != ENOENT) goto fail; ++ ++ ret = confdb_get_string_as_list(cdb, rctx, CONFDB_NSS_CONF_ENTRY, ++ CONFDB_NSS_VETOED_SHELL, ++ &rctx->vetoed_shells); ++ if (ret != EOK && ret != ENOENT) goto fail; ++ ++ ret = sss_get_etc_shells(rctx, &rctx->etc_shells); ++ if (ret != EOK) goto fail; ++ ++ ret = confdb_get_string(cdb, rctx, CONFDB_NSS_CONF_ENTRY, ++ CONFDB_NSS_SHELL_FALLBACK, ++ CONFDB_DEFAULT_SHELL_FALLBACK, ++ &rctx->shell_fallback); ++ if (ret != EOK) goto fail; ++ ++ ret = confdb_get_string(cdb, rctx, CONFDB_NSS_CONF_ENTRY, ++ CONFDB_NSS_DEFAULT_SHELL, ++ NULL, ++ &rctx->default_shell); ++ if (ret != EOK) goto fail; ++ + ret = sss_monitor_init(rctx, rctx->ev, monitor_intf, + svc_name, svc_version, MT_SVC_SERVICE, + rctx, &rctx->last_request_time, +diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h +index 13de83226177bbaa8b8237e3e27b7e72da369194..a0b573d6ecba2d8ba6f55db0adcd7ee29cbec991 100644 +--- a/src/responder/nss/nss_private.h ++++ b/src/responder/nss/nss_private.h +@@ -74,12 +74,6 @@ struct nss_ctx { + char *override_homedir; + char *fallback_homedir; + char *homedir_substr; +- char **allowed_shells; +- char *override_shell; +- char **vetoed_shells; +- char **etc_shells; +- char *shell_fallback; +- char *default_shell; + const char **extra_attributes; + + /* Enumeration. */ +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index b355d4fc90397f51e82545e56940be850f144d49..cb11ea3d493370552fa5a97fd4ffe2108ff34026 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -121,7 +121,7 @@ nss_get_homedir(TALLOC_CTX *mem_ctx, + + static const char * + nss_get_shell_override(struct ldb_message *msg, +- struct nss_ctx *nss_ctx, ++ struct resp_ctx *rctx, + struct sss_domain_info *domain) + { + const char *shell; +@@ -131,8 +131,8 @@ nss_get_shell_override(struct ldb_message *msg, + * the server for the login shell. */ + if (domain->override_shell) { + return domain->override_shell; +- } else if (nss_ctx->override_shell) { +- return nss_ctx->override_shell; ++ } else if (rctx->override_shell) { ++ return rctx->override_shell; + } + + shell = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_SHELL, +@@ -141,56 +141,56 @@ nss_get_shell_override(struct ldb_message *msg, + /* Check whether there is a default shell specified */ + if (domain->default_shell) { + return domain->default_shell; +- } else if (nss_ctx->default_shell) { +- return nss_ctx->default_shell; ++ } else if (rctx->default_shell) { ++ return rctx->default_shell; + } + + return ""; + } + +- if (nss_ctx->allowed_shells == NULL && nss_ctx->vetoed_shells == NULL) { ++ if (rctx->allowed_shells == NULL && rctx->vetoed_shells == NULL) { + return shell; + } + +- if (nss_ctx->vetoed_shells) { +- for (i = 0; nss_ctx->vetoed_shells[i]; i++) { +- if (strcmp(nss_ctx->vetoed_shells[i], shell) == 0) { ++ if (rctx->vetoed_shells) { ++ for (i = 0; rctx->vetoed_shells[i]; i++) { ++ if (strcmp(rctx->vetoed_shells[i], shell) == 0) { + DEBUG(SSSDBG_FUNC_DATA, + "The shell '%s' is vetoed. Using fallback.\n", + shell); +- return nss_ctx->shell_fallback; ++ return rctx->shell_fallback; + } + } + } + +- if (nss_ctx->etc_shells) { +- for (i = 0; nss_ctx->etc_shells[i]; i++) { +- if (strcmp(shell, nss_ctx->etc_shells[i]) == 0) { ++ if (rctx->etc_shells) { ++ for (i = 0; rctx->etc_shells[i]; i++) { ++ if (strcmp(shell, rctx->etc_shells[i]) == 0) { + DEBUG(SSSDBG_TRACE_ALL, + "Shell %s found in /etc/shells\n", shell); + break; + } + } + +- if (nss_ctx->etc_shells[i]) { ++ if (rctx->etc_shells[i]) { + DEBUG(SSSDBG_TRACE_ALL, "Using original shell '%s'\n", shell); + return shell; + } + } + +- if (nss_ctx->allowed_shells) { +- if (strcmp(nss_ctx->allowed_shells[0], "*") == 0) { ++ if (rctx->allowed_shells) { ++ if (strcmp(rctx->allowed_shells[0], "*") == 0) { + DEBUG(SSSDBG_FUNC_DATA, + "The shell '%s' is allowed but does not exist. " + "Using fallback\n", shell); +- return nss_ctx->shell_fallback; ++ return rctx->shell_fallback; + } else { +- for (i = 0; nss_ctx->allowed_shells[i]; i++) { +- if (strcmp(nss_ctx->allowed_shells[i], shell) == 0) { ++ for (i = 0; rctx->allowed_shells[i]; i++) { ++ if (strcmp(rctx->allowed_shells[i], shell) == 0) { + DEBUG(SSSDBG_FUNC_DATA, + "The shell '%s' is allowed but does not exist. " + "Using fallback\n", shell); +- return nss_ctx->shell_fallback; ++ return rctx->shell_fallback; + } + } + } +@@ -239,7 +239,7 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, + gecos = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_GECOS, + NULL); + homedir = nss_get_homedir(mem_ctx, nss_ctx, domain, msg, name, upn, uid); +- shell = nss_get_shell_override(msg, nss_ctx, domain); ++ shell = nss_get_shell_override(msg, nss_ctx->rctx, domain); + + /* Convert to sized strings. */ + ret = sized_output_name(mem_ctx, nss_ctx->rctx, name, domain, _name); +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index 644e94188c0dabdeef6631814ed5e3326cd7d1a1..d67b9fac8d770d113560e41b259e2d5edd219343 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -52,9 +52,6 @@ + #define DEFAULT_PWFIELD "*" + #define DEFAULT_NSS_FD_LIMIT 8192 + +-#define SHELL_REALLOC_INCREMENT 5 +-#define SHELL_REALLOC_MAX 50 +- + static int nss_clear_memcache(struct sbus_request *dbus_req, void *data); + static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req, void *data); + +@@ -150,72 +147,6 @@ static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req, void *da + return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID); + } + +-static errno_t nss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells) +-{ +- int i = 0; +- char *sh; +- char **shells = NULL; +- TALLOC_CTX *tmp_ctx; +- errno_t ret; +- int size; +- +- tmp_ctx = talloc_new(NULL); +- if (!tmp_ctx) return ENOMEM; +- +- shells = talloc_array(tmp_ctx, char *, SHELL_REALLOC_INCREMENT); +- if (!shells) { +- ret = ENOMEM; +- goto done; +- } +- size = SHELL_REALLOC_INCREMENT; +- +- setusershell(); +- while ((sh = getusershell())) { +- shells[i] = talloc_strdup(shells, sh); +- if (!shells[i]) { +- endusershell(); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_FUNC, "Found shell %s in /etc/shells\n", shells[i]); +- i++; +- +- if (i == size) { +- size += SHELL_REALLOC_INCREMENT; +- if (size > SHELL_REALLOC_MAX) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Reached maximum number of shells [%d]. " +- "Users may be denied access. " +- "Please check /etc/shells for sanity\n", +- SHELL_REALLOC_MAX); +- break; +- } +- shells = talloc_realloc(NULL, shells, char *, +- size); +- if (!shells) { +- ret = ENOMEM; +- goto done; +- } +- } +- } +- endusershell(); +- +- if (i + 1 < size) { +- shells = talloc_realloc(NULL, shells, char *, i + 1); +- if (!shells) { +- ret = ENOMEM; +- goto done; +- } +- } +- shells[i] = NULL; +- +- *_shells = talloc_move(mem_ctx, &shells); +- ret = EOK; +-done: +- talloc_zfree(tmp_ctx); +- return ret; +-} +- + static int nss_get_config(struct nss_ctx *nctx, + struct confdb_ctx *cdb) + { +@@ -264,36 +195,6 @@ static int nss_get_config(struct nss_ctx *nctx, + &nctx->fallback_homedir); + if (ret != EOK) goto done; + +- ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, +- CONFDB_NSS_OVERRIDE_SHELL, NULL, +- &nctx->override_shell); +- if (ret != EOK && ret != ENOENT) goto done; +- +- ret = confdb_get_string_as_list(cdb, nctx, CONFDB_NSS_CONF_ENTRY, +- CONFDB_NSS_ALLOWED_SHELL, +- &nctx->allowed_shells); +- if (ret != EOK && ret != ENOENT) goto done; +- +- ret = confdb_get_string_as_list(cdb, nctx, CONFDB_NSS_CONF_ENTRY, +- CONFDB_NSS_VETOED_SHELL, +- &nctx->vetoed_shells); +- if (ret != EOK && ret != ENOENT) goto done; +- +- ret = nss_get_etc_shells(nctx, &nctx->etc_shells); +- if (ret != EOK) goto done; +- +- ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, +- CONFDB_NSS_SHELL_FALLBACK, +- CONFDB_DEFAULT_SHELL_FALLBACK, +- &nctx->shell_fallback); +- if (ret != EOK) goto done; +- +- ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, +- CONFDB_NSS_DEFAULT_SHELL, +- NULL, +- &nctx->default_shell); +- if (ret != EOK) goto done; +- + ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_HOMEDIR_SUBSTRING, + CONFDB_DEFAULT_HOMEDIR_SUBSTRING, +-- +2.14.1 + diff --git a/0004-NSS-Move-nss_get_shell_override-to-responder-utils.patch b/0004-NSS-Move-nss_get_shell_override-to-responder-utils.patch new file mode 100644 index 0000000..eea196d --- /dev/null +++ b/0004-NSS-Move-nss_get_shell_override-to-responder-utils.patch @@ -0,0 +1,233 @@ +From 9759333b3dd404c6787ef0186984c5d4256eb5bb Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Wed, 29 Mar 2017 16:25:19 +0300 +Subject: [PATCH 04/93] NSS: Move nss_get_shell_override to responder utils +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move nss_get_shell_override to common responder utils and rename it to +sss_resp_get_shell_override to make it available to other responders. In +particular let PAM responder use it to provide original shell when it is +overriden for session recording. + +Reviewed-by: Pavel Březina +--- + src/responder/common/responder.h | 5 ++ + src/responder/common/responder_utils.c | 83 +++++++++++++++++++++++++++++++++ + src/responder/nss/nss_protocol_pwent.c | 85 +--------------------------------- + 3 files changed, 89 insertions(+), 84 deletions(-) + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index 7a998967f2761b1c813a866f34cf78d549ede1b9..ba5b73bcc3f3d3bc3cd0cfc19381ef08a046771a 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -404,6 +404,11 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, + + errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx); + ++const char * ++sss_resp_get_shell_override(struct ldb_message *msg, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain); ++ + /** + * Helper functions to format output names + */ +diff --git a/src/responder/common/responder_utils.c b/src/responder/common/responder_utils.c +index 7f5c0573087e9c6c885ae158d0677994fd538e2a..521896088b9af904b4d10021d5755f2591fe91ec 100644 +--- a/src/responder/common/responder_utils.c ++++ b/src/responder/common/responder_utils.c +@@ -399,3 +399,86 @@ int resp_resolve_group_names_recv(TALLOC_CTX *mem_ctx, + *_initgr_named_res = talloc_steal(mem_ctx, state->initgr_named_res); + return EOK; + } ++ ++const char * ++sss_resp_get_shell_override(struct ldb_message *msg, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *domain) ++{ ++ const char *shell; ++ int i; ++ ++ /* Check whether we are unconditionally overriding ++ * the server for the login shell. */ ++ if (domain->override_shell) { ++ return domain->override_shell; ++ } else if (rctx->override_shell) { ++ return rctx->override_shell; ++ } ++ ++ shell = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_SHELL, ++ NULL); ++ if (shell == NULL) { ++ /* Check whether there is a default shell specified */ ++ if (domain->default_shell) { ++ return domain->default_shell; ++ } else if (rctx->default_shell) { ++ return rctx->default_shell; ++ } ++ ++ return ""; ++ } ++ ++ if (rctx->allowed_shells == NULL && rctx->vetoed_shells == NULL) { ++ return shell; ++ } ++ ++ if (rctx->vetoed_shells) { ++ for (i = 0; rctx->vetoed_shells[i]; i++) { ++ if (strcmp(rctx->vetoed_shells[i], shell) == 0) { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "The shell '%s' is vetoed. Using fallback.\n", ++ shell); ++ return rctx->shell_fallback; ++ } ++ } ++ } ++ ++ if (rctx->etc_shells) { ++ for (i = 0; rctx->etc_shells[i]; i++) { ++ if (strcmp(shell, rctx->etc_shells[i]) == 0) { ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Shell %s found in /etc/shells\n", shell); ++ break; ++ } ++ } ++ ++ if (rctx->etc_shells[i]) { ++ DEBUG(SSSDBG_TRACE_ALL, "Using original shell '%s'\n", shell); ++ return shell; ++ } ++ } ++ ++ if (rctx->allowed_shells) { ++ if (strcmp(rctx->allowed_shells[0], "*") == 0) { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "The shell '%s' is allowed but does not exist. " ++ "Using fallback\n", shell); ++ return rctx->shell_fallback; ++ } else { ++ for (i = 0; rctx->allowed_shells[i]; i++) { ++ if (strcmp(rctx->allowed_shells[i], shell) == 0) { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "The shell '%s' is allowed but does not exist. " ++ "Using fallback\n", shell); ++ return rctx->shell_fallback; ++ } ++ } ++ } ++ } ++ ++ DEBUG(SSSDBG_FUNC_DATA, ++ "The shell '%s' is not allowed and does not exist.\n", shell); ++ ++ return NOLOGIN_SHELL; ++} +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index cb11ea3d493370552fa5a97fd4ffe2108ff34026..6c1de3123238514c0c5d0dae43d4c5fa7d5eff5c 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -119,89 +119,6 @@ nss_get_homedir(TALLOC_CTX *mem_ctx, + return homedir; + } + +-static const char * +-nss_get_shell_override(struct ldb_message *msg, +- struct resp_ctx *rctx, +- struct sss_domain_info *domain) +-{ +- const char *shell; +- int i; +- +- /* Check whether we are unconditionally overriding +- * the server for the login shell. */ +- if (domain->override_shell) { +- return domain->override_shell; +- } else if (rctx->override_shell) { +- return rctx->override_shell; +- } +- +- shell = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_SHELL, +- NULL); +- if (shell == NULL) { +- /* Check whether there is a default shell specified */ +- if (domain->default_shell) { +- return domain->default_shell; +- } else if (rctx->default_shell) { +- return rctx->default_shell; +- } +- +- return ""; +- } +- +- if (rctx->allowed_shells == NULL && rctx->vetoed_shells == NULL) { +- return shell; +- } +- +- if (rctx->vetoed_shells) { +- for (i = 0; rctx->vetoed_shells[i]; i++) { +- if (strcmp(rctx->vetoed_shells[i], shell) == 0) { +- DEBUG(SSSDBG_FUNC_DATA, +- "The shell '%s' is vetoed. Using fallback.\n", +- shell); +- return rctx->shell_fallback; +- } +- } +- } +- +- if (rctx->etc_shells) { +- for (i = 0; rctx->etc_shells[i]; i++) { +- if (strcmp(shell, rctx->etc_shells[i]) == 0) { +- DEBUG(SSSDBG_TRACE_ALL, +- "Shell %s found in /etc/shells\n", shell); +- break; +- } +- } +- +- if (rctx->etc_shells[i]) { +- DEBUG(SSSDBG_TRACE_ALL, "Using original shell '%s'\n", shell); +- return shell; +- } +- } +- +- if (rctx->allowed_shells) { +- if (strcmp(rctx->allowed_shells[0], "*") == 0) { +- DEBUG(SSSDBG_FUNC_DATA, +- "The shell '%s' is allowed but does not exist. " +- "Using fallback\n", shell); +- return rctx->shell_fallback; +- } else { +- for (i = 0; rctx->allowed_shells[i]; i++) { +- if (strcmp(rctx->allowed_shells[i], shell) == 0) { +- DEBUG(SSSDBG_FUNC_DATA, +- "The shell '%s' is allowed but does not exist. " +- "Using fallback\n", shell); +- return rctx->shell_fallback; +- } +- } +- } +- } +- +- DEBUG(SSSDBG_FUNC_DATA, +- "The shell '%s' is not allowed and does not exist.\n", shell); +- +- return NOLOGIN_SHELL; +-} +- + static errno_t + nss_get_pwent(TALLOC_CTX *mem_ctx, + struct nss_ctx *nss_ctx, +@@ -239,7 +156,7 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, + gecos = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_GECOS, + NULL); + homedir = nss_get_homedir(mem_ctx, nss_ctx, domain, msg, name, upn, uid); +- shell = nss_get_shell_override(msg, nss_ctx->rctx, domain); ++ shell = sss_resp_get_shell_override(msg, nss_ctx->rctx, domain); + + /* Convert to sized strings. */ + ret = sized_output_name(mem_ctx, nss_ctx->rctx, name, domain, _name); +-- +2.14.1 + diff --git a/0005-CONFIG-Add-session_recording-section.patch b/0005-CONFIG-Add-session_recording-section.patch new file mode 100644 index 0000000..20b2372 --- /dev/null +++ b/0005-CONFIG-Add-session_recording-section.patch @@ -0,0 +1,113 @@ +From 555f43b491f40e0237b8677565a748b929092bee Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Tue, 20 Dec 2016 10:16:47 +0200 +Subject: [PATCH 05/93] CONFIG: Add session_recording section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add information on "session_recording" config section, having three +options: "scope", "users", and "groups". + +The section is intended for disabling session recording ("scope = none", +default), enabling session recording for all users ("scope = all"), and +enabling it for some specific users and/or groups ("scope = some", +"users = ", "groups = "). + +Reviewed-by: Pavel Březina +--- + src/confdb/confdb.h | 6 ++++++ + src/config/SSSDConfigTest.py | 6 ++++-- + src/config/cfg_rules.ini | 10 ++++++++++ + src/config/etc/sssd.api.conf | 6 ++++++ + 4 files changed, 26 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 2ba1bc47ee11f699726cefaf7c3335d2a8afee49..3773358374064c68b2ae254fd18f43ca4c43d834 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -162,6 +162,12 @@ + #define CONFDB_IFP_USER_ATTR_LIST "user_attributes" + #define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit" + ++/* Session Recording */ ++#define CONFDB_SESSION_RECORDING_CONF_ENTRY "config/session_recording" ++#define CONFDB_SESSION_RECORDING_SCOPE "scope" ++#define CONFDB_SESSION_RECORDING_USERS "users" ++#define CONFDB_SESSION_RECORDING_GROUPS "groups" ++ + /* Domains */ + #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s" + #define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config" +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 4f87c52579aebc204671796cc8f3ca13146d3159..5f3ff3958d033dded386850a8653db9872fe4718 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -1417,7 +1417,8 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): + 'ssh', + 'pac', + 'ifp', +- 'secrets'] ++ 'secrets', ++ 'session_recording'] + for section in control_list: + self.assertTrue(sssdconfig.has_section(section), + "Section [%s] missing" % +@@ -1511,7 +1512,8 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): + 'ssh', + 'pac', + 'ifp', +- 'secrets'] ++ 'secrets', ++ 'session_recording'] + service_list = sssdconfig.list_services() + for service in control_list: + self.assertTrue(service in service_list, +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 4643467718bb99b608c89b3762f08fb9779dae4b..4537d0fe87d7084cdff5e591451298393b7f632f 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -10,6 +10,7 @@ section = pac + section = ifp + section = secrets + section = kcm ++section = session_recording + section_re = ^secrets/users/[0-9]\+$ + section_re = ^domain/[^/\@]\+$ + section_re = ^domain/[^/\@]\+/[^/\@]\+$ +@@ -294,6 +295,15 @@ option = socket_path + option = ccache_storage + option = responder_idle_timeout + ++# Session recording ++[rule/allowed_session_recording_options] ++validator = ini_allowed_options ++section_re = ^session_recording$ ++ ++option = scope ++option = users ++option = groups ++ + [rule/allowed_domain_options] + validator = ini_allowed_options + section_re = ^\(domain\|application\)/[^/]\+$ +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 48d3b53f611621711e3be3c50f909f9fc61408f4..ef910f0dfc96241feca6db241219783d774891ef 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -121,6 +121,12 @@ cacert = str, None, false + cert = str, None, false + key = str, None, false + ++[session_recording] ++# Session recording service ++scope = str, None, false ++users = list, str, false ++groups = list, str, false ++ + [provider] + #Available provider types + id_provider = str, None, true +-- +2.14.1 + diff --git a/0006-BUILD-Support-configuring-session-recording-shell.patch b/0006-BUILD-Support-configuring-session-recording-shell.patch new file mode 100644 index 0000000..0034c1d --- /dev/null +++ b/0006-BUILD-Support-configuring-session-recording-shell.patch @@ -0,0 +1,59 @@ +From d802eba25e7c1304e5036684261bcf41540532d8 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Thu, 11 Aug 2016 14:15:55 +0300 +Subject: [PATCH 06/93] BUILD: Support configuring session recording shell +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for specifying the shell used for recording user sessions, +at configure time. + +Reviewed-by: Pavel Březina +--- + configure.ac | 1 + + src/conf_macros.m4 | 16 ++++++++++++++++ + 2 files changed, 17 insertions(+) + +diff --git a/configure.ac b/configure.ac +index e8fe1d47e1803cc570295cf6512a3363e63c51c5..7037927b5f7045b29d3774c85758e00e35e6def6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -139,6 +139,7 @@ WITH_SEMANAGE + WITH_AD_GPO_DEFAULT + WITH_GPO_CACHE_PATH + WITH_NOLOGIN_SHELL ++WITH_SESSION_RECORDING_SHELL + WITH_APP_LIBS + WITH_SUDO + WITH_SUDO_LIB_PATH +diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 +index 420997229cb3c244afd8fb21b074e43a21de0eda..2fa7ae9c4dec1007924f44a8d043909e378a6dd3 100644 +--- a/src/conf_macros.m4 ++++ b/src/conf_macros.m4 +@@ -592,6 +592,22 @@ AC_DEFUN([WITH_NOLOGIN_SHELL], + AC_DEFINE_UNQUOTED(NOLOGIN_SHELL, "$nologin_shell", [The shell used to deny access to users]) + ]) + ++AC_DEFUN([WITH_SESSION_RECORDING_SHELL], ++ [ AC_ARG_WITH([session-recording-shell], ++ [AC_HELP_STRING([--with-session-recording-shell=PATH], ++ [The shell used to record user sessions [/usr/bin/tlog-rec-session]] ++ ) ++ ] ++ ) ++ session_recording_shell="/usr/bin/tlog-rec-session" ++ if test x"$with_session_recording_shell" != x; then ++ session_recording_shell=$with_session_recording_shell ++ fi ++ AC_SUBST(session_recording_shell) ++ AC_DEFINE_UNQUOTED(SESSION_RECORDING_SHELL, "$session_recording_shell", ++ [The shell used to record user sessions]) ++ ]) ++ + AC_ARG_ENABLE([all-experimental-features], + [AS_HELP_STRING([--enable-all-experimental-features], + [build all experimental features])], +-- +2.14.1 + diff --git a/0007-UTIL-Add-session-recording-conf-management-module.patch b/0007-UTIL-Add-session-recording-conf-management-module.patch new file mode 100644 index 0000000..07c3899 --- /dev/null +++ b/0007-UTIL-Add-session-recording-conf-management-module.patch @@ -0,0 +1,236 @@ +From 99b96048b79b0228c3f7c431ea12010f7bd5b362 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 17 Mar 2017 12:41:02 +0200 +Subject: [PATCH 07/93] UTIL: Add session recording conf management module +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add an util module for loading session recording configuration. +To be used by responders and data provider. + +Reviewed-by: Pavel Březina +--- + Makefile.am | 1 + + src/util/session_recording.c | 113 +++++++++++++++++++++++++++++++++++++++++++ + src/util/session_recording.h | 76 +++++++++++++++++++++++++++++ + 3 files changed, 190 insertions(+) + create mode 100644 src/util/session_recording.c + create mode 100644 src/util/session_recording.h + +diff --git a/Makefile.am b/Makefile.am +index 7f6c47c5b77f0a7348045565284525233a17e58a..e57d40fb7b1f6fa8fd2662864bcc231e5015e9d7 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -653,6 +653,7 @@ dist_noinst_HEADERS = \ + src/util/io.h \ + src/util/util_errors.h \ + src/util/safe-format-string.h \ ++ src/util/session_recording.h \ + src/util/strtonum.h \ + src/util/sss_cli_cmd.h \ + src/util/sss_ptr_hash.h \ +diff --git a/src/util/session_recording.c b/src/util/session_recording.c +new file mode 100644 +index 0000000000000000000000000000000000000000..fa480c47881ba934ab01fa9acaa67ac3892ec51a +--- /dev/null ++++ b/src/util/session_recording.c +@@ -0,0 +1,113 @@ ++/* ++ SSSD ++ ++ Session recording utilities ++ ++ Authors: ++ Nikolai Kondrashov ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "util/session_recording.h" ++#include "util/debug.h" ++#include ++#include ++#include ++#include ++#include ++ ++errno_t session_recording_conf_load(TALLOC_CTX *mem_ctx, ++ struct confdb_ctx *cdb, ++ struct session_recording_conf *pconf) ++{ ++ int ret; ++ char *str; ++ struct stat s; ++ ++ if (cdb == NULL || pconf == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ /* Read session_recording/scope option */ ++ ret = confdb_get_string(cdb, mem_ctx, CONFDB_SESSION_RECORDING_CONF_ENTRY, ++ CONFDB_SESSION_RECORDING_SCOPE, "none", &str); ++ if (ret != EOK) goto done; ++ if (strcasecmp(str, "none") == 0) { ++ pconf->scope = SESSION_RECORDING_SCOPE_NONE; ++ } else if (strcasecmp(str, "some") == 0) { ++ pconf->scope = SESSION_RECORDING_SCOPE_SOME; ++ } else if (strcasecmp(str, "all") == 0) { ++ pconf->scope = SESSION_RECORDING_SCOPE_ALL; ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unknown value for session recording scope: %s\n", ++ str); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ /* If session recording is enabled at all */ ++ if (pconf->scope != SESSION_RECORDING_SCOPE_NONE) { ++ /* Check that the shell exists and is executable */ ++ ret = stat(SESSION_RECORDING_SHELL, &s); ++ if (ret != 0) { ++ switch (errno) { ++ case ENOENT: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Session recording shell \"%s\" not found\n", ++ SESSION_RECORDING_SHELL); ++ ret = EINVAL; ++ goto done; ++ case EOK: ++ if ((s.st_mode & 0111) != 0111) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Session recording shell \"%s\" is not executable\n", ++ SESSION_RECORDING_SHELL); ++ ret = EINVAL; ++ goto done; ++ } ++ break; ++ default: ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed checking for session recording shell " ++ "\"%s\": %s\n", ++ SESSION_RECORDING_SHELL, strerror(errno)); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ } ++ ++ /* Read session_recording/users option */ ++ ret = confdb_get_string_as_list(cdb, mem_ctx, ++ CONFDB_SESSION_RECORDING_CONF_ENTRY, ++ CONFDB_SESSION_RECORDING_USERS, ++ &pconf->users); ++ if (ret != EOK && ret != ENOENT) goto done; ++ ++ /* Read session_recording/groups option */ ++ ret = confdb_get_string_as_list(cdb, mem_ctx, ++ CONFDB_SESSION_RECORDING_CONF_ENTRY, ++ CONFDB_SESSION_RECORDING_GROUPS, ++ &pconf->groups); ++ if (ret != EOK && ret != ENOENT) goto done; ++ ++ ret = EOK; ++done: ++ return ret; ++} +diff --git a/src/util/session_recording.h b/src/util/session_recording.h +new file mode 100644 +index 0000000000000000000000000000000000000000..69fb1a8bc48743ef135d8ee0f64ee758f246f9aa +--- /dev/null ++++ b/src/util/session_recording.h +@@ -0,0 +1,76 @@ ++/* ++ SSSD ++ ++ Session recording utilities ++ ++ Authors: ++ Nikolai Kondrashov ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef __SESSION_RECORDING_H__ ++#define __SESSION_RECORDING_H__ ++ ++#include "confdb/confdb.h" ++#include "util/util_errors.h" ++ ++/** Scope of users/groups whose session should be recorded */ ++enum session_recording_scope { ++ SESSION_RECORDING_SCOPE_NONE, /**< None, no users/groups */ ++ SESSION_RECORDING_SCOPE_SOME, /**< Some users/groups specified elsewhere */ ++ SESSION_RECORDING_SCOPE_ALL /**< All users/groups */ ++}; ++ ++/** Session recording configuration (from "session_recording" section) */ ++struct session_recording_conf { ++ /** ++ * Session recording scope: ++ * whether to record nobody, everyone, or some users/groups ++ */ ++ enum session_recording_scope scope; ++ /** ++ * NULL-terminated list of users whose session should be recorded. ++ * Can be NULL, meaning empty list. Only applicable if scope is "some". ++ */ ++ char **users; ++ /** ++ * NULL-terminated list of groups, members of which should have their ++ * sessions recorded. Can be NULL, meaning empty list. Only applicable if ++ * scope is "some" ++ */ ++ char **groups; ++}; ++ ++/** ++ * Load session recording configuration from configuration database. ++ * ++ * @param mem_ctx Memory context to allocate data with. ++ * @param cdb The configuration database connection object to retrieve ++ * data from. ++ * @param pconf Location for the loaded session recording configuration. ++ * ++ * @return Status code: ++ * ENOMEM - memory allocation failed, ++ * EINVAL - configuration was invalid, ++ * EIO - an I/O error occurred while communicating with the ConfDB. ++ */ ++extern errno_t session_recording_conf_load( ++ TALLOC_CTX *mem_ctx, ++ struct confdb_ctx *cdb, ++ struct session_recording_conf *pconf); ++ ++#endif /* __SESSION_RECORDING_H__ */ +-- +2.14.1 + diff --git a/0008-RESPONDER-Add-session-recording-conf-loading.patch b/0008-RESPONDER-Add-session-recording-conf-loading.patch new file mode 100644 index 0000000..e57a85e --- /dev/null +++ b/0008-RESPONDER-Add-session-recording-conf-loading.patch @@ -0,0 +1,112 @@ +From 29dd456102dc995aa59a56483363087071bb84d6 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Thu, 12 Jan 2017 19:10:25 +0200 +Subject: [PATCH 08/93] RESPONDER: Add session recording conf loading +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add session recording configuration loading to the common responder +initialization. To be used for substituting the user shell when +session recording is enabled. + +Reviewed-by: Pavel Březina +--- + Makefile.am | 3 +++ + src/responder/common/responder.h | 3 +++ + src/responder/common/responder_common.c | 9 +++++++++ + src/tests/cwrap/Makefile.am | 2 ++ + 4 files changed, 17 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index e57d40fb7b1f6fa8fd2662864bcc231e5015e9d7..a1cb848e060111a1a19a558db57a2e0e55cea771 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -574,6 +574,7 @@ SSSD_RESPONDER_OBJ = \ + src/responder/common/data_provider/rdp_client.c \ + src/monitor/monitor_iface_generated.c \ + src/providers/data_provider_req.c \ ++ src/util/session_recording.c \ + $(SSSD_RESPONDER_IFACE_OBJ) \ + $(SSSD_CACHE_REQ_OBJ) \ + $(NULL) +@@ -2215,6 +2216,7 @@ responder_socket_access_tests_SOURCES = \ + src/responder/common/cache_req/cache_req_domain.c \ + src/responder/common/data_provider/rdp_message.c \ + src/responder/common/data_provider/rdp_client.c \ ++ src/util/session_recording.c \ + $(SSSD_RESPONDER_IFACE_OBJ) \ + $(NULL) + responder_socket_access_tests_CFLAGS = \ +@@ -2303,6 +2305,7 @@ TEST_MOCK_RESP_OBJ = \ + src/responder/common/data_provider/rdp_message.c \ + src/responder/common/data_provider/rdp_client.c \ + src/responder/common/responder_utils.c \ ++ src/util/session_recording.c \ + $(SSSD_CACHE_REQ_OBJ) \ + $(SSSD_RESPONDER_IFACE_OBJ) \ + $(NULL) +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index ba5b73bcc3f3d3bc3cd0cfc19381ef08a046771a..a97476ca745a731e10574265bcc00cd733532984 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -38,6 +38,7 @@ + #include "responder/common/negcache.h" + #include "sss_client/sss_cli.h" + #include "responder/common/cache_req/cache_req_domain.h" ++#include "util/session_recording.h" + + extern hash_table_t *dp_requests; + +@@ -146,6 +147,8 @@ struct resp_ctx { + char *shell_fallback; + char *default_shell; + ++ struct session_recording_conf sr_conf; ++ + uint32_t cache_req_num; + + void *pvt_ctx; +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index edf6a34bda9730f32fac503ae88951390da51612..6b4d2d9e5936c79944b6f883e9fe46fd03ff32f6 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1301,6 +1301,15 @@ int sss_process_init(TALLOC_CTX *mem_ctx, + &rctx->default_shell); + if (ret != EOK) goto fail; + ++ /* Read session_recording section */ ++ ret = session_recording_conf_load(rctx, rctx->cdb, &rctx->sr_conf); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed loading session recording configuration: %s\n", ++ strerror(ret)); ++ goto fail; ++ } ++ + ret = sss_monitor_init(rctx, rctx->ev, monitor_intf, + svc_name, svc_version, MT_SVC_SERVICE, + rctx, &rctx->last_request_time, +diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am +index c99ebde5f0fc18d1283392cbb307434579d5d811..6c499cb94a5945b789d36ab98aa6a67459df52ce 100644 +--- a/src/tests/cwrap/Makefile.am ++++ b/src/tests/cwrap/Makefile.am +@@ -86,6 +86,7 @@ SSSD_RESPONDER_OBJ = \ + ../../../src/responder/common/data_provider/rdp_client.c \ + ../../../src/monitor/monitor_iface_generated.c \ + ../../../src/providers/data_provider_req.c \ ++ ../../../src/util/session_recording.c \ + $(SSSD_RESPONDER_IFACE_OBJ) \ + $(SSSD_CACHE_REQ_OBJ) \ + $(NULL) +@@ -180,6 +181,7 @@ responder_common_tests_SOURCES =\ + ../../../src/responder/common/responder_packet.c \ + ../../../src/responder/common/responder_cmd.c \ + ../../../src/tests/cmocka/common_mock_resp_dp.c \ ++ ../../../src/util/session_recording.c \ + $(SSSD_CACHE_REQ_OBJ) \ + $(NULL) + responder_common_tests_CFLAGS = \ +-- +2.14.1 + diff --git a/0009-DP-Add-session-recording-conf-loading.patch b/0009-DP-Add-session-recording-conf-loading.patch new file mode 100644 index 0000000..9c4c48f --- /dev/null +++ b/0009-DP-Add-session-recording-conf-loading.patch @@ -0,0 +1,74 @@ +From 5ea60d18ddb8eaff25d274c22c7db7df57b6ec4d Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 17 Mar 2017 12:33:53 +0200 +Subject: [PATCH 09/93] DP: Add session recording conf loading +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add session recording configuration loading to the data provider +initialization. To be used for matching users and groups with session +recording enabled. + +Reviewed-by: Pavel Březina +--- + Makefile.am | 1 + + src/providers/backend.h | 2 ++ + src/providers/data_provider_be.c | 9 +++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index a1cb848e060111a1a19a558db57a2e0e55cea771..9e6a43110ebbcbd310af2b5efc2b5d00cb21d24e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1572,6 +1572,7 @@ sssd_be_SOURCES = \ + src/providers/data_provider/dp_target_subdomains.c \ + src/providers/data_provider/dp_target_id.c \ + src/providers/data_provider/dp_target_auth.c \ ++ src/util/session_recording.c \ + $(SSSD_FAILOVER_OBJ) + sssd_be_LDADD = \ + $(LIBADD_DL) \ +diff --git a/src/providers/backend.h b/src/providers/backend.h +index 30541366033ad621bf59ac67a264a87cc29c2df4..42e80373d0413a994e9cacb897de261ff9d10c91 100644 +--- a/src/providers/backend.h ++++ b/src/providers/backend.h +@@ -27,6 +27,7 @@ + #include "providers/be_refresh.h" + #include "providers/data_provider/dp.h" + #include "util/child_common.h" ++#include "util/session_recording.h" + #include "db/sysdb.h" + + /* a special token, if used in place of the hostname, denotes that real +@@ -83,6 +84,7 @@ struct be_ctx { + const char *conf_path; + uid_t uid; + gid_t gid; ++ struct session_recording_conf sr_conf; + struct be_failover_ctx *be_fo; + struct be_resolv_ctx *be_res; + +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 0ccbb6e33a363d0a88f3f99b83cc270458d98852..dbf78aa19bd20b470f1304a13fdb5923895f9664 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -428,6 +428,15 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + ++ /* Read session_recording section */ ++ ret = session_recording_conf_load(be_ctx, cdb, &be_ctx->sr_conf); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed loading session recording configuration: %s\n", ++ strerror(ret)); ++ goto done; ++ } ++ + /* Initialize be_refresh periodic task. */ + be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx); + if (be_ctx->refresh_ctx == NULL) { +-- +2.14.1 + diff --git a/0010-SYSDB-Add-sessionRecording-attribute-macro.patch b/0010-SYSDB-Add-sessionRecording-attribute-macro.patch new file mode 100644 index 0000000..01a9e3f --- /dev/null +++ b/0010-SYSDB-Add-sessionRecording-attribute-macro.patch @@ -0,0 +1,40 @@ +From 90fb7d3e61423ff1375e9f552f4b58e5173ad3d1 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 17 Mar 2017 12:35:51 +0200 +Subject: [PATCH 10/93] SYSDB: Add sessionRecording attribute macro +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a macro for sessionRecording attribute to sysdb.h. +To be used for storing a boolean attribute signifying if session +recording is enabled for the user. + +Reviewed-by: Pavel Březina +--- + src/db/sysdb.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index b045684db0c8e6e68842b72b3830481b73cf2cbe..f4cad577b97e737613e11d063fe7a8664faed624 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -186,6 +186,7 @@ + #define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN" + #define SYSDB_USE_DOMAIN_RESOLUTION_ORDER "useDomainResolutionOrder" + #define SYSDB_DOMAIN_RESOLUTION_ORDER "domainResolutionOrder" ++#define SYSDB_SESSION_RECORDING "sessionRecording" + + #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" + +@@ -238,6 +239,7 @@ + SYSDB_OVERRIDE_DN, \ + SYSDB_OVERRIDE_OBJECT_DN, \ + SYSDB_DEFAULT_OVERRIDE_NAME, \ ++ SYSDB_SESSION_RECORDING, \ + SYSDB_UUID, \ + SYSDB_ORIG_DN, \ + NULL} +-- +2.14.1 + diff --git a/0011-DP-Load-override_space-into-be_ctx.patch b/0011-DP-Load-override_space-into-be_ctx.patch new file mode 100644 index 0000000..773d88a --- /dev/null +++ b/0011-DP-Load-override_space-into-be_ctx.patch @@ -0,0 +1,73 @@ +From bac0c0df377de4469c8f9310179eef04c7b091fa Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 24 Mar 2017 16:42:21 +0200 +Subject: [PATCH 11/93] DP: Load override_space into be_ctx +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add loading and storing the override_space configuration option to data +provider. That will be needed for formatting output user and group names +for matching against session recording configuration. + +Reviewed-by: Pavel Březina +--- + src/providers/backend.h | 1 + + src/providers/data_provider_be.c | 22 ++++++++++++++++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/providers/backend.h b/src/providers/backend.h +index 42e80373d0413a994e9cacb897de261ff9d10c91..f6c74f8568bc776cbd670a7dfc95e6e1522a88be 100644 +--- a/src/providers/backend.h ++++ b/src/providers/backend.h +@@ -84,6 +84,7 @@ struct be_ctx { + const char *conf_path; + uid_t uid; + gid_t gid; ++ char override_space; + struct session_recording_conf sr_conf; + struct be_failover_ctx *be_fo; + struct be_resolv_ctx *be_res; +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index dbf78aa19bd20b470f1304a13fdb5923895f9664..376bdba7f0d3b55ecf84abae6280dac9b743b44c 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -377,6 +377,7 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, + uint32_t refresh_interval; + struct tevent_signal *tes; + struct be_ctx *be_ctx; ++ char *str = NULL; + errno_t ret; + + be_ctx = talloc_zero(mem_ctx, struct be_ctx); +@@ -428,6 +429,27 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + ++ /* Read the global override_space option, for output name formatting */ ++ ret = confdb_get_string(cdb, be_ctx, CONFDB_MONITOR_CONF_ENTRY, ++ CONFDB_MONITOR_OVERRIDE_SPACE, NULL, ++ &str); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannnot get the space substitution character [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ ++ if (str != NULL) { ++ if (strlen(str) > 1) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Option %s is longer than 1 character " ++ "only the first character %c will be used\n", ++ CONFDB_MONITOR_OVERRIDE_SPACE, str[0]); ++ } ++ ++ be_ctx->override_space = str[0]; ++ } ++ + /* Read session_recording section */ + ret = session_recording_conf_load(be_ctx, cdb, &be_ctx->sr_conf); + if (ret != EOK) { +-- +2.14.1 + diff --git a/0012-DP-Update-viewname-for-all-providers.patch b/0012-DP-Update-viewname-for-all-providers.patch new file mode 100644 index 0000000..bd4e34f --- /dev/null +++ b/0012-DP-Update-viewname-for-all-providers.patch @@ -0,0 +1,37 @@ +From 200787df74510f6edc9387cf9c33f133ccfc0ae3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 21 Apr 2017 13:24:10 +0200 +Subject: [PATCH 12/93] DP: Update viewname for all providers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Call sysdb_master_domain_update for backend domain upon initialization +to make view information available for later use by session recording +code, which will need to access overridden user and group names. + +Reviewed-by: Pavel Březina +--- + src/providers/data_provider_be.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 376bdba7f0d3b55ecf84abae6280dac9b743b44c..a1509cfd29b70e5b2286e6aef2a17700fb8077c1 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -410,6 +410,12 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = sysdb_master_domain_update(be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to update master domain information!\n"); ++ goto done; ++ } ++ + ret = sss_monitor_init(be_ctx, be_ctx->ev, &monitor_be_methods, + be_ctx->identity, DATA_PROVIDER_VERSION, + MT_SVC_PROVIDER, be_ctx, NULL, +-- +2.14.1 + diff --git a/0013-DP-Overlay-sessionRecording-attribute-on-initgr.patch b/0013-DP-Overlay-sessionRecording-attribute-on-initgr.patch new file mode 100644 index 0000000..b9cfe19 --- /dev/null +++ b/0013-DP-Overlay-sessionRecording-attribute-on-initgr.patch @@ -0,0 +1,358 @@ +From 24b3a7b91a54b5b55cfddb52b3d5ac565afdcff1 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Fri, 17 Mar 2017 12:34:58 +0200 +Subject: [PATCH 13/93] DP: Overlay sessionRecording attribute on initgr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add sessionRecording attribute to user entries on initgr request in data +provider, specifying if the user name or groups match the ones with +session recording enabled. + +Reviewed-by: Pavel Březina +--- + src/providers/data_provider/dp_target_id.c | 265 +++++++++++++++++++++++++---- + 1 file changed, 231 insertions(+), 34 deletions(-) + +diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c +index 2088f9529cab83794ac793c7fd5a320f479dbf11..820a6574cb3a224cce4b7d8286af306f234454a3 100644 +--- a/src/providers/data_provider/dp_target_id.c ++++ b/src/providers/data_provider/dp_target_id.c +@@ -73,15 +73,20 @@ static bool check_and_parse_filter(struct dp_id_data *data, + } + + struct dp_initgr_ctx { +- const char *username; + const char *domain; ++ struct sss_domain_info *domain_info; ++ const char *filter_value; ++ const char *username; + uint32_t gnum; + uint32_t *groups; + }; + +-static struct dp_initgr_ctx *create_initgr_ctx(TALLOC_CTX *mem_ctx, +- const char *domain, +- struct ldb_result *res) ++static struct dp_initgr_ctx *create_initgr_ctx( ++ TALLOC_CTX *mem_ctx, ++ const char *domain, ++ struct sss_domain_info *domain_info, ++ const char *filter_value, ++ struct ldb_result *res) + { + struct dp_initgr_ctx *ctx; + const char *username; +@@ -93,38 +98,53 @@ static struct dp_initgr_ctx *create_initgr_ctx(TALLOC_CTX *mem_ctx, + return NULL; + } + +- username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); +- if (username == NULL) { +- ret = EINVAL; +- goto done; +- } +- +- ctx->username = talloc_strdup(ctx, username); +- if (ctx->username == NULL) { +- ret = ENOMEM; +- goto done; +- } +- ++ /* Copy domain name */ + ctx->domain = talloc_strdup(ctx, domain); + if (ctx->domain == NULL) { + ret = ENOMEM; + goto done; + } + +- ctx->groups = talloc_array(mem_ctx, uint32_t, res->count); +- if (ctx->groups == NULL) { ++ /* Copy filter value */ ++ ctx->filter_value = talloc_strdup(ctx, filter_value); ++ if (ctx->filter_value == NULL) { + ret = ENOMEM; + goto done; + } + +- /* The first GID is the primary so it might be duplicated +- * later in the list. */ +- for (ctx->gnum = 0, i = 0; i < res->count; i++) { +- ctx->groups[ctx->gnum] = ldb_msg_find_attr_as_uint(res->msgs[i], +- SYSDB_GIDNUM, 0); +- /* If 0 it may be a non-posix group, so we skip it. */ +- if (ctx->groups[ctx->gnum] != 0) { +- ctx->gnum++; ++ /* Reference domain info */ ++ ctx->domain_info = domain_info; ++ ++ /* If we had the data in sysdb */ ++ if (res != NULL) { ++ /* Copy original username */ ++ username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); ++ if (username == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ctx->username = talloc_strdup(ctx, username); ++ if (ctx->username == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Copy group IDs */ ++ ctx->groups = talloc_array(mem_ctx, uint32_t, res->count); ++ if (ctx->groups == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* The first GID is the primary so it might be duplicated ++ * later in the list. */ ++ for (ctx->gnum = 0, i = 0; i < res->count; i++) { ++ ctx->groups[ctx->gnum] = ldb_msg_find_attr_as_uint(res->msgs[i], ++ SYSDB_GIDNUM, 0); ++ /* If 0 it may be a non-posix group, so we skip it. */ ++ if (ctx->groups[ctx->gnum] != 0) { ++ ctx->gnum++; ++ } + } + } + +@@ -139,16 +159,21 @@ done: + return ctx; + } + +-static void dp_req_initgr_pp(const char *req_name, +- struct data_provider *provider, +- struct dp_initgr_ctx *ctx, +- struct dp_reply_std *reply) ++static void dp_req_initgr_pp_nss_notify(const char *req_name, ++ struct data_provider *provider, ++ struct dp_initgr_ctx *ctx) + { + struct dp_client *dp_cli; + DBusMessage *msg; + dbus_bool_t dbret; + int num; + ++ /* If user didn't exist in the cache previously */ ++ if (ctx->username == NULL) { ++ /* There is no point in contacting NSS responder */ ++ return; ++ } ++ + dp_cli = provider->clients[DPC_NSS]; + if (dp_cli == NULL) { + return; +@@ -185,6 +210,178 @@ static void dp_req_initgr_pp(const char *req_name, + return; + } + ++static void dp_req_initgr_pp_sr_overlay(struct data_provider *provider, ++ struct dp_initgr_ctx *ctx) ++{ ++ bool enabled = false; ++ struct be_ctx *be = provider->be_ctx; ++ struct ldb_result *res; ++ struct ldb_message *msg; ++ const char *name; ++ char *output_name; ++ char **conf_user; ++ char **conf_group; ++ size_t i; ++ TALLOC_CTX *tmp_ctx = NULL; ++ errno_t ret; ++ struct ldb_message_element el = { 0, SYSDB_SESSION_RECORDING, 0, NULL }; ++ struct sysdb_attrs del_attrs = { 1, &el }; ++ struct sysdb_attrs *add_attrs; ++ ++ /* If selective session recording is not enabled */ ++ if (be->sr_conf.scope != SESSION_RECORDING_SCOPE_SOME) { ++ goto done; ++ } ++ ++ /* Allocate temporary talloc context */ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed creating temporary talloc context\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Get updated initgroups data with overrides */ ++ ret = sysdb_initgroups_with_views(tmp_ctx, ctx->domain_info, ++ ctx->filter_value, &res); ++ if (ret == ENOENT || (ret == EOK && res->count == 0)) { ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get initgroups: %s\n", ++ sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Delete sessionRecording attribute so we know when we failed */ ++ ret = sysdb_set_entry_attr(ctx->domain_info->sysdb, res->msgs[0]->dn, ++ &del_attrs, SYSDB_MOD_DEL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed removing %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Format output username */ ++ name = sss_get_name_from_msg(ctx->domain_info, res->msgs[0]); ++ ret = sss_output_fqname(tmp_ctx, ctx->domain_info, name, ++ be->override_space, &output_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed formatting output username from \"%s\": %s\n", ++ name, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* For each user name in session recording config */ ++ conf_user = be->sr_conf.users; ++ if (conf_user != NULL) { ++ for (; *conf_user != NULL && !enabled; conf_user++) { ++ /* If it matches the requested user name */ ++ if (strcmp(*conf_user, output_name) == 0) { ++ enabled = true; ++ } ++ } ++ } ++ ++ /* If we have groups in config and are not yet enabled */ ++ if (be->sr_conf.groups != NULL && ++ be->sr_conf.groups[0] != NULL && ++ !enabled) { ++ /* For each group in response */ ++ for (i = 0; i < res->count && !enabled; i++) { ++ /* Get the group msg */ ++ if (i == 0) { ++ gid_t gid; ++ struct ldb_result *group_res; ++ ++ /* Get the primary group */ ++ gid = sss_view_ldb_msg_find_attr_as_uint64(ctx->domain_info, ++ res->msgs[i], ++ SYSDB_GIDNUM, 0); ++ if (gid == 0) { ++ continue; ++ } ++ ret = sysdb_getgrgid_with_views(tmp_ctx, ctx->domain_info, ++ gid, &group_res); ++ if (ret == ENOENT) { ++ continue; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed retrieving group #%llu: %s\n", ++ (unsigned long long)gid, sss_strerror(ret)); ++ goto done; ++ } else if (group_res->count == 0) { ++ continue; ++ } ++ msg = group_res->msgs[0]; ++ } else { ++ msg = res->msgs[i]; ++ } ++ /* Get the group's output name */ ++ name = sss_get_name_from_msg(ctx->domain_info, msg); ++ if (name == NULL) { ++ continue; ++ } ++ ret = sss_output_fqname(tmp_ctx, ctx->domain_info, ++ name, be->override_space, ++ &output_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed formatting output group name from \"%s\": %s\n", ++ name, sss_strerror(ret)); ++ goto done; ++ } ++ /* For each group in configuration */ ++ for (conf_group = be->sr_conf.groups; ++ *conf_group != NULL && !enabled; ++ conf_group++) { ++ if (strcmp(*conf_group, output_name) == 0) { ++ enabled = true; ++ } ++ } ++ } ++ } ++ ++ /* Set sessionRecording attribute to enabled value */ ++ add_attrs = sysdb_new_attrs(tmp_ctx); ++ if (add_attrs == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed creating attributes\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = sysdb_attrs_add_bool(add_attrs, SYSDB_SESSION_RECORDING, enabled); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed setting %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, sss_strerror(ret)); ++ goto done; ++ } ++ ret = sysdb_set_entry_attr(ctx->domain_info->sysdb, res->msgs[0]->dn, ++ add_attrs, SYSDB_MOD_ADD); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed storing %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++} ++ ++static void dp_req_initgr_pp(const char *req_name, ++ struct data_provider *provider, ++ struct dp_initgr_ctx *ctx, ++ struct dp_reply_std *reply) ++{ ++ (void)reply; ++ dp_req_initgr_pp_nss_notify(req_name, provider, ctx); ++ dp_req_initgr_pp_sr_overlay(provider, ctx); ++} ++ + static errno_t dp_initgroups(struct sbus_request *sbus_req, + struct dp_client *dp_cli, + const char *key, +@@ -194,7 +391,7 @@ static errno_t dp_initgroups(struct sbus_request *sbus_req, + struct be_ctx *be_ctx; + struct sss_domain_info *domain; + struct dp_initgr_ctx *ctx; +- struct ldb_result *res; ++ struct ldb_result *res = NULL; + errno_t ret; + + be_ctx = dp_client_be(dp_cli); +@@ -210,15 +407,15 @@ static errno_t dp_initgroups(struct sbus_request *sbus_req, + + ret = sysdb_initgroups(sbus_req, domain, data->filter_value, &res); + if (ret == ENOENT || (ret == EOK && res->count == 0)) { +- /* There is no point in contacting NSS responder. Proceed as usual. */ +- return EAGAIN; ++ talloc_zfree(res); + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get initgroups [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + +- ctx = create_initgr_ctx(sbus_req, data->domain, res); ++ ctx = create_initgr_ctx(sbus_req, data->domain, domain, ++ data->filter_value, res); + if (ctx == NULL) { + ret = ENOMEM; + goto done; +-- +2.14.1 + diff --git a/0014-CACHE_REQ-Pull-sessionRecording-attrs-from-initgr.patch b/0014-CACHE_REQ-Pull-sessionRecording-attrs-from-initgr.patch new file mode 100644 index 0000000..9da0b7a --- /dev/null +++ b/0014-CACHE_REQ-Pull-sessionRecording-attrs-from-initgr.patch @@ -0,0 +1,500 @@ +From 382a972a80ac571cdbf70d88571f6de49fe1cd23 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Tue, 21 Mar 2017 11:30:20 +0200 +Subject: [PATCH 14/93] CACHE_REQ: Pull sessionRecording attrs from initgr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After entires are retrieved by cache_req for user info requests (except +initgr), overlay them with sessionRecording attribute retrieved from an +initgr request made additionally for each entry. + +Do not do additional initgr requests with selective session recording +enabled, if we don't have any group names to match against in session +recording configuration. Only do user name matches instead. + +Reviewed-by: Pavel Březina +--- + Makefile.am | 1 + + src/responder/common/cache_req/cache_req.c | 51 +++- + src/responder/common/cache_req/cache_req_private.h | 10 + + .../common/cache_req/cache_req_sr_overlay.c | 326 +++++++++++++++++++++ + src/tests/cwrap/Makefile.am | 1 + + 5 files changed, 383 insertions(+), 6 deletions(-) + create mode 100644 src/responder/common/cache_req/cache_req_sr_overlay.c + +diff --git a/Makefile.am b/Makefile.am +index 9e6a43110ebbcbd310af2b5efc2b5d00cb21d24e..e7d69d2f0ffdf6f966d2f430174c0159fceb9118 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -530,6 +530,7 @@ SSSD_CACHE_REQ_OBJ = \ + src/responder/common/cache_req/cache_req_search.c \ + src/responder/common/cache_req/cache_req_data.c \ + src/responder/common/cache_req/cache_req_domain.c \ ++ src/responder/common/cache_req/cache_req_sr_overlay.c \ + src/responder/common/cache_req/plugins/cache_req_common.c \ + src/responder/common/cache_req/plugins/cache_req_enum_users.c \ + src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 84a9b1cb0ad22a9d6fcb31bc1ac1d013098e62df..2f2c3e97f8b6f2d3d42727d10a98c4890c073af2 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -26,6 +26,7 @@ + #include "util/util.h" + #include "responder/common/responder.h" + #include "responder/common/cache_req/cache_req_private.h" ++#include "responder/common/cache_req/cache_req_private.h" + #include "responder/common/cache_req/cache_req_plugin.h" + + static const struct cache_req_plugin * +@@ -721,6 +722,8 @@ cache_req_search_domains(struct tevent_req *req, + bool bypass_cache, + bool bypass_dp); + ++static void cache_req_process_result(struct tevent_req *subreq); ++ + static void cache_req_done(struct tevent_req *subreq); + + struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, +@@ -1001,11 +1004,11 @@ cache_req_search_domains(struct tevent_req *req, + return ENOMEM; + } + +- tevent_req_set_callback(subreq, cache_req_done, req); ++ tevent_req_set_callback(subreq, cache_req_process_result, req); + return EAGAIN; + } + +-static void cache_req_done(struct tevent_req *subreq) ++static void cache_req_process_result(struct tevent_req *subreq) + { + struct cache_req_state *state; + struct tevent_req *req; +@@ -1040,11 +1043,23 @@ static void cache_req_done(struct tevent_req *subreq) + } + } + ++ /* Overlay each result with session recording flag */ ++ if (ret == EOK) { ++ subreq = cache_req_sr_overlay_send(state, state->ev, state->cr, ++ state->results, ++ state->num_results); ++ if (subreq == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed creating a session recording " ++ "overlay request\n"); ++ ret = ENOMEM; ++ } else { ++ tevent_req_set_callback(subreq, cache_req_done, req); ++ ret = EAGAIN; ++ } ++ } ++ + switch (ret) { +- case EOK: +- CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Success\n"); +- tevent_req_done(req); +- break; + case EAGAIN: + break; + case ENOENT: +@@ -1061,6 +1076,30 @@ static void cache_req_done(struct tevent_req *subreq) + return; + } + ++static void cache_req_done(struct tevent_req *subreq) ++{ ++ struct cache_req_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_state); ++ ret = cache_req_sr_overlay_recv(subreq); ++ talloc_zfree(subreq); ++ ++ switch (ret) { ++ case EOK: ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Finished: Success\n"); ++ tevent_req_done(req); ++ break; ++ default: ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, ++ "Finished: Error %d: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ break; ++ } ++} ++ + errno_t cache_req_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct cache_req_result ***_results) +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index c0ee5f969f2a171b8a6eb396b3d14b593d157b76..9b706ff7d678f543effb77089857a7e8a42a9c51 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -152,6 +152,16 @@ cache_req_create_result_from_msg(TALLOC_CTX *mem_ctx, + const char *lookup_name, + const char *well_known_domain); + ++struct tevent_req * ++cache_req_sr_overlay_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr, ++ struct cache_req_result **results, ++ size_t num_results); ++ ++errno_t ++cache_req_sr_overlay_recv(struct tevent_req *req); ++ + /* Plug-in common. */ + + struct cache_req_result * +diff --git a/src/responder/common/cache_req/cache_req_sr_overlay.c b/src/responder/common/cache_req/cache_req_sr_overlay.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4d1111b04938032447e112258873827ddfbe9b2b +--- /dev/null ++++ b/src/responder/common/cache_req/cache_req_sr_overlay.c +@@ -0,0 +1,326 @@ ++/* ++ Authors: ++ Nikolai Kondrashov ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "responder/common/cache_req/cache_req_private.h" ++ ++struct cache_req_sr_overlay_state { ++ /* Input data */ ++ struct tevent_context *ev; ++ struct cache_req *cr; ++ struct cache_req_result **results; ++ size_t num_results; ++ /* Work data */ ++ size_t res_idx; ++ size_t msg_idx; ++}; ++ ++static errno_t cache_req_sr_overlay_match_users( ++ struct cache_req_sr_overlay_state *state); ++ ++static errno_t cache_req_sr_overlay_match_users( ++ struct cache_req_sr_overlay_state *state); ++ ++static struct tevent_req *cache_req_sr_overlay_match_all_step_send( ++ struct cache_req_sr_overlay_state *state); ++ ++static void cache_req_sr_overlay_match_all_step_done( ++ struct tevent_req *subreq); ++ ++struct tevent_req *cache_req_sr_overlay_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr, ++ struct cache_req_result **results, ++ size_t num_results) ++{ ++ errno_t ret = EOK; ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct cache_req_sr_overlay_state *state; ++ struct resp_ctx *rctx = cr->rctx; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct cache_req_sr_overlay_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->cr = cr; ++ state->results = results; ++ state->num_results = num_results; ++ ++ /* If session recording is selective */ ++ if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME) { ++ /* If it's a request for a user/users */ ++ switch (cr->data->type) { ++ case CACHE_REQ_USER_BY_NAME: ++ case CACHE_REQ_USER_BY_UPN: ++ case CACHE_REQ_USER_BY_ID: ++ case CACHE_REQ_ENUM_USERS: ++ /* If we have group names to match against */ ++ if (rctx->sr_conf.groups != NULL && ++ rctx->sr_conf.groups[0] != NULL) { ++ /* Pull and match group and user names for each user entry */ ++ subreq = cache_req_sr_overlay_match_all_step_send(state); ++ if (subreq == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed allocating a session recording " ++ "user overlay request\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ tevent_req_set_callback( ++ subreq, cache_req_sr_overlay_match_all_step_done, req); ++ ret = EAGAIN; ++ } else { ++ /* Only match user names for each user entry */ ++ ret = cache_req_sr_overlay_match_users(state); ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++done: ++ if (ret != EAGAIN) { ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ } ++ ++ return req; ++} ++ ++static errno_t cache_req_sr_overlay_match_users( ++ struct cache_req_sr_overlay_state *state) ++{ ++ struct cache_req *cr; ++ struct resp_ctx *rctx; ++ errno_t ret; ++ int lret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct cache_req_result *result; ++ struct ldb_message *msg; ++ const char *name; ++ char *output_name; ++ char **conf_user; ++ bool enabled; ++ char *enabled_str; ++ ++ cr = state->cr; ++ rctx = cr->rctx; ++ ++ /* Create per-message talloc context */ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Failed creating temporary talloc context\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* For each result */ ++ for (state->res_idx = 0; ++ state->res_idx < state->num_results; ++ state->res_idx++) { ++ result = state->results[state->res_idx]; ++ ++ /* For each message */ ++ for (state->msg_idx = 0; ++ state->msg_idx < result->count; ++ state->msg_idx++) { ++ msg = result->msgs[state->msg_idx]; ++ ++ /* Format output username */ ++ name = sss_get_name_from_msg(result->domain, msg); ++ ret = sss_output_fqname(tmp_ctx, result->domain, name, ++ rctx->override_space, ++ &output_name); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Failed formatting output username from %s: %s\n", ++ name, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* For each user name in session recording config */ ++ enabled = false; ++ conf_user = rctx->sr_conf.users; ++ if (conf_user != NULL) { ++ for (; *conf_user != NULL; conf_user++) { ++ /* If it matches the requested user name */ ++ if (strcmp(*conf_user, output_name) == 0) { ++ enabled = true; ++ break; ++ } ++ } ++ } ++ ++ /* Set sessionRecording attribute to enabled value */ ++ ldb_msg_remove_attr(msg, SYSDB_SESSION_RECORDING); ++ enabled_str = talloc_strdup(tmp_ctx, enabled ? "TRUE" : "FALSE"); ++ if (enabled_str == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Failed to allocate a %s attribute value\n", ++ SYSDB_SESSION_RECORDING); ++ ret = ENOMEM; ++ goto done; ++ } ++ lret = ldb_msg_add_string(msg, SYSDB_SESSION_RECORDING, enabled_str); ++ if (lret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(lret); ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Failed adding %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, sss_strerror(ret)); ++ goto done; ++ } ++ talloc_steal(msg, enabled_str); ++ ++ /* Free per-message allocations */ ++ talloc_free_children(tmp_ctx); ++ } ++ } ++ ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static struct tevent_req *cache_req_sr_overlay_match_all_step_send( ++ struct cache_req_sr_overlay_state *state) ++{ ++ struct cache_req *cr = state->cr; ++ struct cache_req_result *result = ++ state->results[state->res_idx]; ++ const char *name; ++ ++ name = ldb_msg_find_attr_as_string(result->msgs[state->msg_idx], ++ SYSDB_NAME, NULL); ++ return cache_req_initgr_by_name_send(state, state->ev, cr->rctx, cr->ncache, ++ cr->midpoint, CACHE_REQ_ANY_DOM, ++ NULL, name); ++} ++ ++static void cache_req_sr_overlay_match_all_step_done( ++ struct tevent_req *subreq) ++{ ++ int lret; ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct tevent_req *req; ++ struct cache_req_sr_overlay_state *state; ++ struct cache_req_result *result; ++ struct ldb_message *msg; ++ const char *enabled; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_sr_overlay_state); ++ msg = state->results[state->res_idx]-> ++ msgs[state->msg_idx]; ++ ++ /* Create temporary allocation context */ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed creating temporary talloc context\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Get initgroups result */ ++ ret = cache_req_initgr_by_name_recv(tmp_ctx, subreq, &result); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed retrieving initgr request results: %s\n", ++ sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Overwrite sessionRecording attribute */ ++ ldb_msg_remove_attr(msg, SYSDB_SESSION_RECORDING); ++ enabled = ldb_msg_find_attr_as_string(result->msgs[0], ++ SYSDB_SESSION_RECORDING, NULL); ++ if (enabled != NULL) { ++ char *enabled_copy; ++ enabled_copy = talloc_strdup(tmp_ctx, enabled); ++ if (enabled_copy == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed to allocate a copy of %s attribute\n", ++ SYSDB_SESSION_RECORDING); ++ ret = ENOMEM; ++ goto done; ++ } ++ lret = ldb_msg_add_string(msg, SYSDB_SESSION_RECORDING, enabled_copy); ++ if (lret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(lret); ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed adding %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, sss_strerror(ret)); ++ goto done; ++ } ++ talloc_steal(msg, enabled_copy); ++ } ++ ++ /* Move onto next entry, if any */ ++ state->msg_idx++; ++ if (state->msg_idx >= ++ state->results[state->res_idx]->count) { ++ state->res_idx++; ++ if (state->res_idx >= state->num_results) { ++ ret = EOK; ++ goto done; ++ } ++ state->msg_idx = 0; ++ } ++ ++ /* Schedule next entry overlay */ ++ subreq = cache_req_sr_overlay_match_all_step_send(state); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->cr, ++ "Failed allocating a session recording " ++ "user overlay request\n"); ++ goto done; ++ } ++ tevent_req_set_callback(subreq, ++ cache_req_sr_overlay_match_all_step_done, req); ++ ret = EAGAIN; ++ ++done: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ talloc_free(tmp_ctx); ++} ++ ++errno_t cache_req_sr_overlay_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} +diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am +index 6c499cb94a5945b789d36ab98aa6a67459df52ce..a559abe9e163ee162fa6db4d688daf2cc4c40c2d 100644 +--- a/src/tests/cwrap/Makefile.am ++++ b/src/tests/cwrap/Makefile.am +@@ -42,6 +42,7 @@ SSSD_CACHE_REQ_OBJ = \ + ../../../src/responder/common/cache_req/cache_req_search.c \ + ../../../src/responder/common/cache_req/cache_req_data.c \ + ../../../src/responder/common/cache_req/cache_req_domain.c \ ++ ../../../src/responder/common/cache_req/cache_req_sr_overlay.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_common.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_enum_users.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ +-- +2.14.1 + diff --git a/0015-NSS-Substitute-session-recording-shell.patch b/0015-NSS-Substitute-session-recording-shell.patch new file mode 100644 index 0000000..800414b --- /dev/null +++ b/0015-NSS-Substitute-session-recording-shell.patch @@ -0,0 +1,87 @@ +From 836dae913497e150bd0ec11eee1e256e4fcc0bb7 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Tue, 21 Mar 2017 11:45:37 +0200 +Subject: [PATCH 15/93] NSS: Substitute session recording shell +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Substitute the configured session recording shell when unconditional +session recording is enabled (scope = all), or when selective session +recording is enabled (scope = some), and the user has the +sessionRecording attribute set to true. + +Reviewed-by: Pavel Březina +--- + src/responder/nss/nss_protocol_pwent.c | 48 +++++++++++++++++++++++++++++++++- + 1 file changed, 47 insertions(+), 1 deletion(-) + +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index 6c1de3123238514c0c5d0dae43d4c5fa7d5eff5c..db5c071e2ff172a2267c08c9817fecfbcc7cabc3 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -119,6 +119,46 @@ nss_get_homedir(TALLOC_CTX *mem_ctx, + return homedir; + } + ++static errno_t ++nss_get_shell(struct nss_ctx *nss_ctx, ++ struct sss_domain_info *domain, ++ struct ldb_message *msg, ++ const char *name, ++ uint32_t uid, ++ const char **_shell) ++{ ++ const char *shell = NULL; ++ ++ if (nss_ctx->rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) { ++ shell = SESSION_RECORDING_SHELL; ++ } else if (nss_ctx->rctx->sr_conf.scope == ++ SESSION_RECORDING_SCOPE_SOME) { ++ const char *sr_enabled; ++ sr_enabled = ldb_msg_find_attr_as_string( ++ msg, SYSDB_SESSION_RECORDING, NULL); ++ if (sr_enabled == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "%s attribute not found for %s[%u]! Skipping\n", ++ SYSDB_SESSION_RECORDING, name, uid); ++ return EINVAL; ++ } else if (strcmp(sr_enabled, "TRUE") == 0) { ++ shell = SESSION_RECORDING_SHELL; ++ } else if (strcmp(sr_enabled, "FALSE") != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Skipping %s[%u] " ++ "because its %s attribute value is invalid: %s\n", ++ name, uid, SYSDB_SESSION_RECORDING, sr_enabled); ++ return EINVAL; ++ } ++ } ++ if (shell == NULL) { ++ shell = sss_resp_get_shell_override(msg, nss_ctx->rctx, domain); ++ } ++ ++ *_shell = shell; ++ return EOK; ++} ++ + static errno_t + nss_get_pwent(TALLOC_CTX *mem_ctx, + struct nss_ctx *nss_ctx, +@@ -156,7 +196,13 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, + gecos = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_GECOS, + NULL); + homedir = nss_get_homedir(mem_ctx, nss_ctx, domain, msg, name, upn, uid); +- shell = sss_resp_get_shell_override(msg, nss_ctx->rctx, domain); ++ ret = nss_get_shell(nss_ctx, domain, msg, name, uid, &shell); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "failed retrieving shell for %s[%u], skipping [%d]: %s\n", ++ name, uid, ret, sss_strerror(ret)); ++ return ret; ++ } + + /* Convert to sized strings. */ + ret = sized_output_name(mem_ctx, nss_ctx->rctx, name, domain, _name); +-- +2.14.1 + diff --git a/0016-PAM-Export-original-shell-to-tlog-rec-session.patch b/0016-PAM-Export-original-shell-to-tlog-rec-session.patch new file mode 100644 index 0000000..790a232 --- /dev/null +++ b/0016-PAM-Export-original-shell-to-tlog-rec-session.patch @@ -0,0 +1,135 @@ +From 49d24ba630544632e29ed397627c97352523165d Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Wed, 29 Mar 2017 16:47:41 +0300 +Subject: [PATCH 16/93] PAM: Export original shell to tlog-rec-session +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add exporting of original user shell (as returned by NSS) as an +environment variable for use by tlog-rec-session, when session recording +is enabled for the user. This lets tlog-rec-session start the actual +user shell, after tlog-rec-session is started in its place. + +Reviewed-by: Pavel Březina +--- + src/responder/pam/pamsrv_cmd.c | 96 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 1c31b180f437dec84316076681fca031912f5563..7081aacfd579d381a621991960f0cd63a860d909 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -682,6 +682,90 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd); + static void pam_handle_cached_login(struct pam_auth_req *preq, int ret, + time_t expire_date, time_t delayed_until, bool cached_auth); + ++/* ++ * Add a request to add a variable to the PAM user environment, containing the ++ * actual (not overridden) user shell, in case session recording is enabled. ++ */ ++static int pam_reply_sr_export_shell(struct pam_auth_req *preq, ++ const char *var_name) ++{ ++ int ret; ++ TALLOC_CTX *ctx = NULL; ++ bool enabled; ++ const char *enabled_str; ++ const char *shell; ++ char *buf; ++ ++ /* Create temporary talloc context */ ++ ctx = talloc_new(NULL); ++ if (ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Check if session recording is enabled */ ++ if (preq->cctx->rctx->sr_conf.scope == ++ SESSION_RECORDING_SCOPE_NONE) { ++ enabled = false; ++ } else if (preq->cctx->rctx->sr_conf.scope == ++ SESSION_RECORDING_SCOPE_ALL) { ++ enabled = true; ++ } else { ++ enabled_str = ldb_msg_find_attr_as_string(preq->user_obj, ++ SYSDB_SESSION_RECORDING, NULL); ++ if (enabled_str == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "%s attribute not found\n", SYSDB_SESSION_RECORDING); ++ ret = ENOENT; ++ goto done; ++ } else if (strcmp(enabled_str, "TRUE") == 0) { ++ enabled = true; ++ } else if (strcmp(enabled_str, "FALSE") == 0) { ++ enabled = false; ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, "invalid value of %s attribute: %s\n", ++ SYSDB_SESSION_RECORDING, enabled_str); ++ ret = ENOENT; ++ goto done; ++ } ++ } ++ ++ /* Export original shell if recording is enabled and so it's overridden */ ++ if (enabled) { ++ /* Extract the shell */ ++ shell = sss_resp_get_shell_override(preq->user_obj, ++ preq->cctx->rctx, preq->domain); ++ if (shell == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "user has no shell\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ /* Format environment entry */ ++ buf = talloc_asprintf(ctx, "%s=%s", var_name, shell); ++ if (buf == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Add request to add the entry to user environment */ ++ ret = pam_add_response(preq->pd, SSS_PAM_ENV_ITEM, ++ strlen(buf) + 1, (uint8_t *)buf); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(ctx); ++ return ret; ++} ++ + static void pam_reply(struct pam_auth_req *preq) + { + struct cli_ctx *cctx; +@@ -918,6 +1002,18 @@ static void pam_reply(struct pam_auth_req *preq) + } + } + ++ /* ++ * Export non-overridden shell to tlog-rec-session when opening the session ++ */ ++ if (pd->cmd == SSS_PAM_OPEN_SESSION && pd->pam_status == PAM_SUCCESS) { ++ ret = pam_reply_sr_export_shell(preq, "TLOG_REC_SESSION_SHELL"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "failed to export the shell to tlog-rec-session.\n"); ++ goto done; ++ } ++ } ++ + resp_c = 0; + resp_size = 0; + resp = pd->resp_list; +-- +2.14.1 + diff --git a/0017-INTG-Add-session-recording-tests.patch b/0017-INTG-Add-session-recording-tests.patch new file mode 100644 index 0000000..3a93314 --- /dev/null +++ b/0017-INTG-Add-session-recording-tests.patch @@ -0,0 +1,1059 @@ +From 53a4219e2f51cd0443931aa931505bf0b4bf5a45 Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Thu, 11 Aug 2016 14:18:38 +0300 +Subject: [PATCH 17/93] INTG: Add session recording tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add basic tests for all base combinations of session recording +configuration options. + +Reviewed-by: Pavel Březina +--- + contrib/ci/configure.sh | 1 + + src/tests/intg/Makefile.am | 2 + + src/tests/intg/config.py.m4 | 29 +- + src/tests/intg/test_session_recording.py | 961 +++++++++++++++++++++++++++++++ + 4 files changed, 979 insertions(+), 14 deletions(-) + create mode 100644 src/tests/intg/test_session_recording.py + +diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh +index 9d18d0c187561a2dc3bc47d3e8913626e7ff3046..4a219da7577ea6aab5c8f14679b9e603c6c35be3 100644 +--- a/contrib/ci/configure.sh ++++ b/contrib/ci/configure.sh +@@ -29,6 +29,7 @@ declare -a CONFIGURE_ARG_LIST=( + "--enable-ldb-version-check" + "--with-syslog=journald" + "--enable-systemtap" ++ "--with-session-recording-shell=/bin/false" + ) + + +diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am +index 8566106e9017a8d3c9e7a3898a3a886e2966e346..abf6237fcf45d75bc7b9dba835e33413cf2a48da 100644 +--- a/src/tests/intg/Makefile.am ++++ b/src/tests/intg/Makefile.am +@@ -18,6 +18,7 @@ dist_noinst_DATA = \ + test_enumeration.py \ + test_ldap.py \ + test_memory_cache.py \ ++ test_session_recording.py \ + test_ts_cache.py \ + test_netgroup.py \ + secrets.py \ +@@ -42,6 +43,7 @@ config.py: config.py.m4 + -D "libexecpath=\`$(libexecdir)'" \ + -D "runstatedir=\`$(runstatedir)'" \ + -D "abs_builddir=\`$(abs_builddir)'" \ ++ -D "session_recording_shell=\`$(session_recording_shell)'" \ + $< > $@ + + root: +diff --git a/src/tests/intg/config.py.m4 b/src/tests/intg/config.py.m4 +index 841aae01f9f67f3a06656a580b84dfaa0a877c0f..bfbbf030fe5c6431ad3eec6c71d05e9138c82163 100644 +--- a/src/tests/intg/config.py.m4 ++++ b/src/tests/intg/config.py.m4 +@@ -2,17 +2,18 @@ + Build configuration variables. + """ + +-PREFIX = "prefix" +-SYSCONFDIR = "sysconfdir" +-NSS_MODULE_DIR = PREFIX + "/lib" +-SSSDCONFDIR = SYSCONFDIR + "/sssd" +-CONF_PATH = SSSDCONFDIR + "/sssd.conf" +-DB_PATH = "dbpath" +-PID_PATH = "pidpath" +-PIDFILE_PATH = PID_PATH + "/sssd.pid" +-LOG_PATH = "logpath" +-MCACHE_PATH = "mcpath" +-SECDB_PATH = "secdbpath" +-LIBEXEC_PATH = "libexecpath" +-RUNSTATEDIR = "runstatedir" +-ABS_BUILDDIR = "abs_builddir" ++PREFIX = "prefix" ++SYSCONFDIR = "sysconfdir" ++NSS_MODULE_DIR = PREFIX + "/lib" ++SSSDCONFDIR = SYSCONFDIR + "/sssd" ++CONF_PATH = SSSDCONFDIR + "/sssd.conf" ++DB_PATH = "dbpath" ++PID_PATH = "pidpath" ++PIDFILE_PATH = PID_PATH + "/sssd.pid" ++LOG_PATH = "logpath" ++MCACHE_PATH = "mcpath" ++SECDB_PATH = "secdbpath" ++LIBEXEC_PATH = "libexecpath" ++RUNSTATEDIR = "runstatedir" ++ABS_BUILDDIR = "abs_builddir" ++SESSION_RECORDING_SHELL = "session_recording_shell" +diff --git a/src/tests/intg/test_session_recording.py b/src/tests/intg/test_session_recording.py +new file mode 100644 +index 0000000000000000000000000000000000000000..56a056a156b5effe8b8afb7b5607cb60038eec4c +--- /dev/null ++++ b/src/tests/intg/test_session_recording.py +@@ -0,0 +1,961 @@ ++# ++# Session Recording tests ++# ++# Copyright (c) 2016 Red Hat, Inc. ++# Author: Nikolai Kondrashov ++# ++# This is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; version 2 only ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++import os ++import stat ++import ent ++import config ++import signal ++import subprocess ++import time ++import ldap ++import pytest ++import ds_openldap ++import ldap_ent ++from util import * ++ ++LDAP_BASE_DN = "dc=example,dc=com" ++INTERACTIVE_TIMEOUT = 4 ++ ++ ++def stop_sssd(): ++ """Stop sssd""" ++ pid_file = open(config.PIDFILE_PATH, "r") ++ pid = int(pid_file.read()) ++ os.kill(pid, signal.SIGTERM) ++ while True: ++ try: ++ os.kill(pid, signal.SIGCONT) ++ except: ++ break ++ time.sleep(1) ++ ++ ++def start_sssd(): ++ """Start sssd""" ++ if subprocess.call(["sssd", "-D", "-f"]) != 0: ++ raise Exception("sssd start failed") ++ ++ ++def restart_sssd(): ++ """Restart sssd""" ++ stop_sssd() ++ start_sssd() ++ ++ ++@pytest.fixture(scope="module") ++def ds_inst(request): ++ """LDAP server instance fixture""" ++ ds_inst = ds_openldap.DSOpenLDAP( ++ config.PREFIX, 10389, LDAP_BASE_DN, ++ "cn=admin", "Secret123" ++ ) ++ ++ try: ++ ds_inst.setup() ++ except: ++ ds_inst.teardown() ++ raise ++ request.addfinalizer(lambda: ds_inst.teardown()) ++ return ds_inst ++ ++ ++@pytest.fixture(scope="module") ++def ldap_conn(request, ds_inst): ++ """LDAP server connection fixture""" ++ ldap_conn = ds_inst.bind() ++ ldap_conn.ds_inst = ds_inst ++ request.addfinalizer(lambda: ldap_conn.unbind_s()) ++ return ldap_conn ++ ++ ++def create_ldap_entries(ldap_conn, ent_list=None): ++ """Add LDAP entries from ent_list""" ++ if ent_list is not None: ++ for entry in ent_list: ++ ldap_conn.add_s(entry[0], entry[1]) ++ ++ ++def cleanup_ldap_entries(ldap_conn, ent_list=None): ++ """Remove LDAP entries added by create_ldap_entries""" ++ if ent_list is None: ++ for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"): ++ for entry in ldap_conn.search_s("ou=" + ou + "," + ++ ldap_conn.ds_inst.base_dn, ++ ldap.SCOPE_ONELEVEL, ++ attrlist=[]): ++ ldap_conn.delete_s(entry[0]) ++ else: ++ for entry in ent_list: ++ ldap_conn.delete_s(entry[0]) ++ ++ ++def create_ldap_cleanup(request, ldap_conn, ent_list=None): ++ """Add teardown for removing all user/group LDAP entries""" ++ request.addfinalizer(lambda: cleanup_ldap_entries(ldap_conn, ent_list)) ++ ++ ++def create_ldap_fixture(request, ldap_conn, ent_list=None): ++ """Add LDAP entries and add teardown for removing them""" ++ create_ldap_entries(ldap_conn, ent_list) ++ create_ldap_cleanup(request, ldap_conn, ent_list) ++ ++ ++SCHEMA_RFC2307 = "rfc2307" ++SCHEMA_RFC2307_BIS = "rfc2307bis" ++ ++ ++def format_basic_conf(ldap_conn, schema): ++ """ ++ Format a basic SSSD configuration. ++ ++ The files domain is defined but not enabled in order to avoid enumerating ++ users from the files domain that would otherwise by implicitly enabled. ++ """ ++ schema_conf = "ldap_schema = " + schema + "\n" ++ if schema == SCHEMA_RFC2307_BIS: ++ schema_conf += "ldap_group_object_class = groupOfNames\n" ++ return unindent("""\ ++ [sssd] ++ debug_level = 0xffff ++ domains = LDAP ++ services = nss, pam ++ ++ [nss] ++ debug_level = 0xffff ++ memcache_timeout = 0 ++ ++ [pam] ++ debug_level = 0xffff ++ ++ [domain/files] ++ id_provider = files ++ ++ [domain/LDAP] ++ ldap_auth_disable_tls_never_use_in_production = true ++ debug_level = 0xffff ++ enumerate = true ++ {schema_conf} ++ id_provider = ldap ++ auth_provider = ldap ++ ldap_uri = {ldap_conn.ds_inst.ldap_url} ++ ldap_search_base = {ldap_conn.ds_inst.base_dn} ++ """).format(**locals()) ++ ++ ++def create_conf_file(contents): ++ """Create sssd.conf with specified contents""" ++ conf = open(config.CONF_PATH, "w") ++ conf.write(contents) ++ conf.close() ++ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR) ++ ++ ++def cleanup_conf_file(): ++ """Remove sssd.conf, if it exists""" ++ if os.path.lexists(config.CONF_PATH): ++ os.unlink(config.CONF_PATH) ++ ++ ++def create_conf_cleanup(request): ++ """Add teardown for removing sssd.conf""" ++ request.addfinalizer(cleanup_conf_file) ++ ++ ++def create_conf_fixture(request, contents): ++ """ ++ Create sssd.conf with specified contents and add teardown for removing it. ++ """ ++ create_conf_file(contents) ++ create_conf_cleanup(request) ++ ++ ++def create_sssd_process(): ++ """Start the SSSD process""" ++ if subprocess.call(["sssd", "-D", "-f"]) != 0: ++ raise Exception("sssd start failed") ++ ++ ++def cleanup_sssd_process(): ++ """Stop the SSSD process and remove its state""" ++ try: ++ pid_file = open(config.PIDFILE_PATH, "r") ++ pid = int(pid_file.read()) ++ os.kill(pid, signal.SIGTERM) ++ while True: ++ try: ++ os.kill(pid, signal.SIGCONT) ++ except: ++ break ++ time.sleep(1) ++ except: ++ pass ++ for path in os.listdir(config.DB_PATH): ++ os.unlink(config.DB_PATH + "/" + path) ++ for path in os.listdir(config.MCACHE_PATH): ++ os.unlink(config.MCACHE_PATH + "/" + path) ++ ++ ++def create_sssd_cleanup(request): ++ """Add teardown for stopping SSSD and removing its state""" ++ request.addfinalizer(cleanup_sssd_process) ++ ++ ++def create_sssd_fixture(request): ++ """Start SSSD and add teardown for stopping it and removing its state""" ++ create_sssd_process() ++ create_sssd_cleanup(request) ++ ++ ++@pytest.fixture ++def users_and_groups(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001, loginShell="/bin/sh1") ++ ent_list.add_user("user2", 1002, 2002, loginShell="/bin/sh2") ++ ent_list.add_user("user3", 1003, 2003, loginShell="/bin/sh3") ++ # User without primary group ++ ent_list.add_user("user4", 1004, 2004, loginShell="/bin/sh4") ++ ent_list.add_group("group1", 2001) ++ ent_list.add_group("group2", 2002) ++ ent_list.add_group("group3", 2003) ++ ent_list.add_group("empty_group", 2010) ++ ent_list.add_group("one_user_group", 2011, ["user1"]) ++ ent_list.add_group("two_user_group", 2012, ["user1", "user2"]) ++ ent_list.add_group("three_user_group", 2013, ["user1", "user2", "user3"]) ++ # Supplementary group for a user without primary group ++ ent_list.add_group("groupless_user_group", 2014, ["user4"]) ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ ++@pytest.fixture ++def none(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "none". ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = none ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_none(none): ++ """Test "none" scope""" ++ ent.assert_passwd( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell="/bin/sh1"), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def all(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "all". ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = all ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_all_nam(all): ++ """Test "all" scope with getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ user3=dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ user4=dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ )) ++ ++ ++def test_all_uid(all): ++ """Test "all" scope with getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ 1003:dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ 1004:dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ }) ++ ++ ++def test_all_ent(all): ++ """Test "all" scope with getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_empty(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", but no users or groups listed. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_some_empty(some_empty): ++ """Test "some" scope with no users or groups""" ++ ent.assert_passwd( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell="/bin/sh1"), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_users(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", and some users listed. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ users = user1, user2 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_some_users_nam(some_users): ++ """Test "some" scope with user list and getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_users_uid(some_users): ++ """Test "some" scope with user list and getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_users_ent(some_users): ++ """Test "some" scope with user list and getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_users_overridden(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying two users with ++ overridden names, but one listed with the original name. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ users = overridden_user1, user2 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ subprocess.check_call(["sss_override", "user-add", "user1", ++ "-n", "overridden_user1"]) ++ subprocess.check_call(["sss_override", "user-add", "user2", ++ "-n", "overridden_user2"]) ++ restart_sssd() ++ ++ ++def test_some_users_overridden_nam(some_users_overridden): ++ """ ++ Test "some" scope with user list containing some ++ overridden users, requested with getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ overridden_user1=dict(name="overridden_user1", uid=1001, ++ shell=config.SESSION_RECORDING_SHELL), ++ overridden_user2=dict(name="overridden_user2", uid=1002, ++ shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_users_overridden_uid(some_users_overridden): ++ """ ++ Test "some" scope with user list containing some ++ overridden users, requested with getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="overridden_user1", uid=1001, ++ shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="overridden_user2", uid=1002, ++ shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_users_overridden_ent(some_users_overridden): ++ """ ++ Test "some" scope with user list containing some ++ overridden users, requested with getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="overridden_user1", uid=1001, ++ shell=config.SESSION_RECORDING_SHELL), ++ dict(name="overridden_user2", uid=1002, ++ shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_groups1(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying a single-user supplementary group, ++ and a two-user supplementary group intersecting with the first one. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = one_user_group, two_user_group ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++@pytest.fixture ++def some_groups2(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying a three-user supplementary group. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = three_user_group ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++@pytest.fixture ++def some_groups3(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying a group with a user with ++ non-existent primary group. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = groupless_user_group ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++@pytest.fixture ++def some_groups4(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying two primary groups. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = group1, group3 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_some_groups1_nam(some_groups1): ++ """Test "some" scope with group list and getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups1_uid(some_groups1): ++ """Test "some" scope with group list and getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups1_ent(some_groups1): ++ """Test "some" scope with group list and getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++def test_some_groups2_nam(some_groups2): ++ """Test "some" scope with group list and getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ user3=dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups2_uid(some_groups2): ++ """Test "some" scope with group list and getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ 1003:dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups2_ent(some_groups2): ++ """Test "some" scope with group list and getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++def test_some_groups3_nam(some_groups3): ++ """Test "some" scope with group list and getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell="/bin/sh1"), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ )) ++ ++ ++def test_some_groups3_uid(some_groups3): ++ """Test "some" scope with group list and getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell="/bin/sh1"), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ }) ++ ++ ++def test_some_groups3_ent(some_groups3): ++ """Test "some" scope with group list and getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell="/bin/sh1"), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL), ++ ) ++ ) ++ ++ ++def test_some_groups4_nam(some_groups4): ++ """Test "some" scope with group list and getpwnam""" ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups4_uid(some_groups4): ++ """Test "some" scope with group list and getpwuid""" ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups4_ent(some_groups4): ++ """Test "some" scope with group list and getpwent""" ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_groups_overridden1(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying two primary groups with ++ overridden names, but one listed with the original name. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = overridden_group1, group2 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ subprocess.check_call(["sss_override", "group-add", "group1", ++ "-n", "overridden_group1"]) ++ subprocess.check_call(["sss_override", "group-add", "group2", ++ "-n", "overridden_group2"]) ++ restart_sssd() ++ ++ ++def test_some_groups_overridden1_nam(some_groups_overridden1): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups_overridden1_uid(some_groups_overridden1): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups_overridden1_ent(some_groups_overridden1): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_groups_overridden2(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", specifying two supplementary groups with ++ overridden names, but one listed with the original name. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = one_user_group_overridden, two_user_group ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ subprocess.check_call(["sss_override", "group-add", "one_user_group", ++ "-n", "one_user_group_overridden"]) ++ subprocess.check_call(["sss_override", "group-add", "two_user_group", ++ "-n", "two_user_group_overridden"]) ++ restart_sssd() ++ ++ ++def test_some_groups_overridden2_nam(some_groups_overridden2): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups_overridden2_uid(some_groups_overridden2): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups_overridden2_ent(some_groups_overridden2): ++ """ ++ Test "some" scope with group list containing some ++ overridden groups, and users requested with getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_groups_overridden3(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", having two primary groups with ++ IDs swapped via overriding, but only one of them listed. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = group2 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ subprocess.check_call(["sss_override", "group-add", "group1", ++ "-g", "2002"]) ++ subprocess.check_call(["sss_override", "group-add", "group2", ++ "-g", "2001"]) ++ restart_sssd() ++ ++ ++def test_some_groups_overridden3_nam(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups_overridden3_uid(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups_overridden3_ent(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_groups_overridden4(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", two users with GIDs swapped via overridding, ++ and one of their primary groups listed. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ groups = group2 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ subprocess.check_call(["sss_override", "user-add", "user1", ++ "-g", "2002"]) ++ subprocess.check_call(["sss_override", "user-add", "user2", ++ "-g", "2001"]) ++ restart_sssd() ++ ++ ++def test_some_groups_overridden4_nam(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell="/bin/sh3"), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_groups_overridden4_uid(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell="/bin/sh3"), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_groups_overridden4_ent(some_groups_overridden3): ++ """ ++ Test "some" scope with group list containing some ++ overridden group, and users requested with getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell="/bin/sh3"), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) ++ ++ ++@pytest.fixture ++def some_users_and_groups(request, ldap_conn, users_and_groups): ++ """ ++ Fixture with scope "some", listing some users and groups. ++ """ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ ++ unindent("""\ ++ [session_recording] ++ scope = some ++ users = user3 ++ groups = one_user_group ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ ++def test_some_users_and_groups_nam(some_users_and_groups): ++ """ ++ Test "some" scope with user and group lists and getpwnam. ++ """ ++ ent.assert_each_passwd_by_name(dict( ++ user1=dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ user2=dict(name="user2", uid=1002, shell="/bin/sh2"), ++ user3=dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ user4=dict(name="user4", uid=1004, shell="/bin/sh4"), ++ )) ++ ++ ++def test_some_users_and_groups_uid(some_users_and_groups): ++ """ ++ Test "some" scope with user and group lists and getpwuid. ++ """ ++ ent.assert_each_passwd_by_uid({ ++ 1001:dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ 1002:dict(name="user2", uid=1002, shell="/bin/sh2"), ++ 1003:dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ 1004:dict(name="user4", uid=1004, shell="/bin/sh4"), ++ }) ++ ++ ++def test_some_users_and_groups_ent(some_users_and_groups): ++ """ ++ Test "some" scope with user and group lists and getpwent. ++ """ ++ ent.assert_passwd_list( ++ ent.contains_only( ++ dict(name="user1", uid=1001, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user2", uid=1002, shell="/bin/sh2"), ++ dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), ++ dict(name="user4", uid=1004, shell="/bin/sh4"), ++ ) ++ ) +-- +2.14.1 + diff --git a/0018-MAN-Describe-session-recording-configuration.patch b/0018-MAN-Describe-session-recording-configuration.patch new file mode 100644 index 0000000..64f42f7 --- /dev/null +++ b/0018-MAN-Describe-session-recording-configuration.patch @@ -0,0 +1,352 @@ +From 27c30eb5f046d6c43276b139706110906cdacb9b Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Thu, 27 Apr 2017 17:53:47 +0300 +Subject: [PATCH 18/93] MAN: Describe session recording configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +--- + contrib/sssd.spec.in | 1 + + src/man/Makefile.am | 2 +- + src/man/include/seealso.xml | 4 + + src/man/po/po4a.cfg | 1 + + src/man/sssd-session-recording.5.xml | 162 +++++++++++++++++++++++++++++++++++ + src/man/sssd.conf.5.xml | 99 +++++++++++++++++++++ + 6 files changed, 268 insertions(+), 1 deletion(-) + create mode 100644 src/man/sssd-session-recording.5.xml + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index cb1a09c42b9c71f91e7ef318c165953cfbe71525..74affd39f39908510394970ab8dadae87b4a7aaf 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -990,6 +990,7 @@ done + %{_mandir}/man5/sssd-files.5* + %{_mandir}/man5/sssd-simple.5* + %{_mandir}/man5/sssd-sudo.5* ++%{_mandir}/man5/sssd-session-recording.5* + %if (0%{?with_secrets} == 1) + %{_mandir}/man5/sssd-secrets.5* + %endif +diff --git a/src/man/Makefile.am b/src/man/Makefile.am +index 3a063614f085691652db32d76315375466e0d3de..0e35ac277658e76ca8346a077a6931bc5c95ae23 100644 +--- a/src/man/Makefile.am ++++ b/src/man/Makefile.am +@@ -65,7 +65,7 @@ man_MANS = \ + sssd-krb5.5 sssd-simple.5 sss-certmap.5 \ + sssd_krb5_locator_plugin.8 sss_groupshow.8 \ + pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \ +- sss_override.8 idmap_sss.8 sssctl.8 \ ++ sss_override.8 idmap_sss.8 sssctl.8 sssd-session-recording.5 \ + $(NULL) + + if BUILD_SAMBA +diff --git a/src/man/include/seealso.xml b/src/man/include/seealso.xml +index 2e9c646c475887bce3612472975ade375edbd819..9b9a72ce257a9487f445bd40e7658259f091a01f 100644 +--- a/src/man/include/seealso.xml ++++ b/src/man/include/seealso.xml +@@ -34,6 +34,10 @@ + 5 + , + ++ ++ sssd-session-recording ++ 5 ++ , + + sss_cache8 + , +diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg +index f325b1afaf081aa99f12baee1809d81de390abaa..e9492cfe1525b2f5e1f2a18b7703afd15b5f8fde 100644 +--- a/src/man/po/po4a.cfg ++++ b/src/man/po/po4a.cfg +@@ -31,6 +31,7 @@ + [type:docbook] sssctl.8.xml $lang:$(builddir)/$lang/sssctl.8.xml + [type:docbook] sssd-files.5.xml $lang:$(builddir)/$lang/sssd-files.5.xml + [type:docbook] sssd-secrets.5.xml $lang:$(builddir)/$lang/sssd-secrets.5.xml ++[type:docbook] sssd-session-recording.5.xml $lang:$(builddir)/$lang/sssd-session-recording.5.xml + [type:docbook] sssd-kcm.8.xml $lang:$(builddir)/$lang/sssd-kcm.8.xml + [type:docbook] include/service_discovery.xml $lang:$(builddir)/$lang/include/service_discovery.xml opt:"-k 0" + [type:docbook] include/upstream.xml $lang:$(builddir)/$lang/include/upstream.xml opt:"-k 0" +diff --git a/src/man/sssd-session-recording.5.xml b/src/man/sssd-session-recording.5.xml +new file mode 100644 +index 0000000000000000000000000000000000000000..b53d4e1439a384132bb5a6d4f559dd7b17711a68 +--- /dev/null ++++ b/src/man/sssd-session-recording.5.xml +@@ -0,0 +1,162 @@ ++ ++ ++ ++SSSD Manual pages ++ ++ ++ ++ ++ sssd-sudo ++ 5 ++ File Formats and Conventions ++ ++ ++ ++ sssd-session-recording ++ Configuring session recording with SSSD ++ ++ ++ ++ DESCRIPTION ++ ++ This manual page describes how to configure ++ ++ sssd ++ 8 ++ to work with ++ ++ tlog-rec-session ++ 8 ++ , a part of tlog package, to implement user session ++ recording on text terminals. ++ For a detailed configuration syntax reference, refer to the ++ FILE FORMAT section of the ++ ++ sssd.conf ++ 5 ++ manual page. ++ ++ ++ SSSD can be set up to enable recording of everything specific ++ users see or type during their sessions on text terminals. E.g. ++ when users log in on the console, or via SSH. SSSD itself doesn't ++ record anything, but makes sure tlog-rec-session is started upon ++ user login, so it can record according to its configuration. ++ ++ ++ For users with session recording enabled, SSSD replaces the user ++ shell with tlog-rec-session in NSS responses, and adds a variable ++ specifying the original shell to the user environment, upon PAM ++ session setup. This way tlog-rec-session can be started in place ++ of the user shell, and know which actual shell to start, once it ++ set up the recording. ++ ++ ++ ++ ++ CONFIGURATION OPTIONS ++ ++ These options can be used to configure the session recording. ++ ++ ++ ++ scope (string) ++ ++ ++ One of the following strings specifying the scope ++ of session recording: ++ ++ ++ "none" ++ ++ ++ No users are recorded. ++ ++ ++ ++ ++ "some" ++ ++ ++ Users/groups specified by ++ users ++ and ++ groups ++ options are recorded. ++ ++ ++ ++ ++ "all" ++ ++ ++ All users are recorded. ++ ++ ++ ++ ++ ++ ++ Default: "none" ++ ++ ++ ++ ++ users (string) ++ ++ ++ A comma-separated list of users which should have ++ session recording enabled. Matches user names as ++ returned by NSS. I.e. after the possible space ++ replacement, case changes, etc. ++ ++ ++ Default: Empty. Matches no users. ++ ++ ++ ++ ++ groups (string) ++ ++ ++ A comma-separated list of groups, members of which ++ should have session recording enabled. Matches ++ group names as returned by NSS. I.e. after the ++ possible space replacement, case changes, etc. ++ ++ ++ NOTE: using this option (having it set to ++ anything) has a considerable performance cost, ++ because each uncached request for a user requires ++ retrieving and matching the groups the user is ++ member of. ++ ++ ++ Default: Empty. Matches no groups. ++ ++ ++ ++ ++ ++ ++ ++ EXAMPLE ++ ++ The following snippet of sssd.conf enables session recording for ++ users "contractor1" and "contractor2", and group "students". ++ ++ ++ ++[session_recording] ++scope = some ++users = contractor1, contractor2 ++groups = students ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7c4cd1f2e5c453964def9c04967f9adc232bb776..b9eaf5eddb5c39125f7ce1c7a988c374378bbb32 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1518,6 +1518,105 @@ pam_account_locked_message = Account locked, please contact help desk. + + + ++ ++ Session recording configuration options ++ ++ Session recording works in conjunction with ++ ++ tlog-rec-session ++ 8 ++ , a part of tlog package, to log what users see ++ and type when they log in on a text terminal. ++ See also ++ ++ sssd-session-recording ++ 5 ++ . ++ ++ ++ These options can be used to configure session recording. ++ ++ ++ ++ scope (string) ++ ++ ++ One of the following strings specifying the scope ++ of session recording: ++ ++ ++ "none" ++ ++ ++ No users are recorded. ++ ++ ++ ++ ++ "some" ++ ++ ++ Users/groups specified by ++ users ++ and ++ groups ++ options are recorded. ++ ++ ++ ++ ++ "all" ++ ++ ++ All users are recorded. ++ ++ ++ ++ ++ ++ ++ Default: "none" ++ ++ ++ ++ ++ users (string) ++ ++ ++ A comma-separated list of users which should have ++ session recording enabled. Matches user names as ++ returned by NSS. I.e. after the possible space ++ replacement, case changes, etc. ++ ++ ++ Default: Empty. Matches no users. ++ ++ ++ ++ ++ groups (string) ++ ++ ++ A comma-separated list of groups, members of which ++ should have session recording enabled. Matches ++ group names as returned by NSS. I.e. after the ++ possible space replacement, case changes, etc. ++ ++ ++ NOTE: using this option (having it set to ++ anything) has a considerable performance cost, ++ because each uncached request for a user requires ++ retrieving and matching the groups the user is ++ member of. ++ ++ ++ Default: Empty. Matches no groups. ++ ++ ++ ++ ++ ++ + + + +-- +2.14.1 + diff --git a/0019-SPEC-Use-language-file-for-sssd-kcm.patch b/0019-SPEC-Use-language-file-for-sssd-kcm.patch new file mode 100644 index 0000000..07d2d6a --- /dev/null +++ b/0019-SPEC-Use-language-file-for-sssd-kcm.patch @@ -0,0 +1,29 @@ +From 7ecf21b359167fc76355940b511dbc4475954939 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 25 Jul 2017 15:12:35 +0200 +Subject: [PATCH 19/93] SPEC: Use language file for sssd-kcm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + contrib/sssd.spec.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 74affd39f39908510394970ab8dadae87b4a7aaf..c65d4e66178e6b1ccec7835f4518a9fbe2a6336a 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -1263,7 +1263,7 @@ done + %{_libdir}/pkgconfig/sss_certmap.pc + + %if (0%{?with_kcm} == 1) +-%files kcm ++%files kcm -f sssd_kcm.lang + %{_libexecdir}/%{servicename}/sssd_kcm + %dir %{_datadir}/sssd-kcm + %{_datadir}/sssd-kcm/kcm_default_ccache +-- +2.14.1 + diff --git a/0020-MAN-Don-t-tell-the-user-to-autostart-sssd-kcm.servic.patch b/0020-MAN-Don-t-tell-the-user-to-autostart-sssd-kcm.servic.patch new file mode 100644 index 0000000..aac7cff --- /dev/null +++ b/0020-MAN-Don-t-tell-the-user-to-autostart-sssd-kcm.servic.patch @@ -0,0 +1,37 @@ +From 47f73fbf39b75b1a6c816206c384f83f78535677 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 25 Jul 2017 10:44:30 +0200 +Subject: [PATCH 20/93] MAN: Don't tell the user to autostart sssd-kcm.service; + it's socket-enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Lukáš Slebodník +--- + src/man/sssd-kcm.8.xml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml +index db50ed8b49294057da99b01655a4b158f2908dcb..78d3551d442f01adfab224b4f25a1217496eea57 100644 +--- a/src/man/sssd-kcm.8.xml ++++ b/src/man/sssd-kcm.8.xml +@@ -112,7 +112,6 @@ + + systemctl start sssd-kcm.socket + systemctl enable sssd-kcm.socket +-systemctl enable sssd-kcm.service + + Please note your distribution may already configure the units + for you. +@@ -131,7 +130,6 @@ systemctl enable sssd-kcm.service + + systemctl start sssd-secrets.socket + systemctl enable sssd-secrets.socket +-systemctl enable sssd-secrets.service + + Your distribution should already set the dependencies between the services. + +-- +2.14.1 + diff --git a/0021-CACHE_REQ-Fix-warning-may-be-used-uninitialized.patch b/0021-CACHE_REQ-Fix-warning-may-be-used-uninitialized.patch new file mode 100644 index 0000000..17dba39 --- /dev/null +++ b/0021-CACHE_REQ-Fix-warning-may-be-used-uninitialized.patch @@ -0,0 +1,32 @@ +From 9d90396775715de66e735dd55826e35f311450af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 31 Jul 2017 09:21:31 +0200 +Subject: [PATCH 21/93] CACHE_REQ: Fix warning may be used uninitialized +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Setting ret as EOK in case everything goes well. + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Nikolai Kondrashov +--- + src/responder/common/cache_req/cache_req_sr_overlay.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_sr_overlay.c b/src/responder/common/cache_req/cache_req_sr_overlay.c +index 4d1111b04938032447e112258873827ddfbe9b2b..6193f7b000ecc2ee29c462325691d11d67bcfa65 100644 +--- a/src/responder/common/cache_req/cache_req_sr_overlay.c ++++ b/src/responder/common/cache_req/cache_req_sr_overlay.c +@@ -204,6 +204,8 @@ static errno_t cache_req_sr_overlay_match_users( + } + } + ++ ret = EOK; ++ + done: + talloc_zfree(tmp_ctx); + return ret; +-- +2.14.1 + diff --git a/0022-INTG-Add-with-session-recording-bin-false-to-intgche.patch b/0022-INTG-Add-with-session-recording-bin-false-to-intgche.patch new file mode 100644 index 0000000..488542c --- /dev/null +++ b/0022-INTG-Add-with-session-recording-bin-false-to-intgche.patch @@ -0,0 +1,50 @@ +From 1b3425d8cbc5697f7321ba364e38ef4c5ed9f2b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 1 Aug 2017 09:22:38 +0200 +Subject: [PATCH 22/93] INTG: Add --with-session-recording=/bin/false to + intgcheck's configure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's ensure that running `make intgcheck-*` doesn't fail when done +locally. + +As --with-session-recording=/bin/false is now set in the Makefile.am, +there's no need to set it in contrib/ci/configure.sh. Thus, the option +has been removed from there. + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 1 + + contrib/ci/configure.sh | 1 - + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index e7d69d2f0ffdf6f966d2f430174c0159fceb9118..62e0baf76df2a99329f7f9c77b2e9267b7dfca91 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3538,6 +3538,7 @@ intgcheck-prepare: + --with-ldb-lib-dir="$$prefix"/lib/ldb \ + --enable-intgcheck-reqs \ + --without-semanage \ ++ --with-session-recording-shell=/bin/false \ + $(INTGCHECK_CONFIGURE_FLAGS) \ + CFLAGS="$$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \ + $(MAKE) $(AM_MAKEFLAGS) ; \ +diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh +index 4a219da7577ea6aab5c8f14679b9e603c6c35be3..9d18d0c187561a2dc3bc47d3e8913626e7ff3046 100644 +--- a/contrib/ci/configure.sh ++++ b/contrib/ci/configure.sh +@@ -29,7 +29,6 @@ declare -a CONFIGURE_ARG_LIST=( + "--enable-ldb-version-check" + "--with-syslog=journald" + "--enable-systemtap" +- "--with-session-recording-shell=/bin/false" + ) + + +-- +2.14.1 + diff --git a/0023-Moving-headers-used-by-both-server-and-client-to-spe.patch b/0023-Moving-headers-used-by-both-server-and-client-to-spe.patch new file mode 100644 index 0000000..012ff08 --- /dev/null +++ b/0023-Moving-headers-used-by-both-server-and-client-to-spe.patch @@ -0,0 +1,350 @@ +From 3996e391054a1c02ab62e1541ae21a8204bd5d0a Mon Sep 17 00:00:00 2001 +From: AmitKumar +Date: Sun, 23 Jul 2017 05:19:27 +0530 +Subject: [PATCH 23/93] Moving headers used by both server and client to + special folder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These are the header files which are used by both client and server: +src/util/io.h +src/util/murmurhash3.h +src/util/util_safealign.h + +This patch is about moving these header files to special folder +(src/shared). It will be easier to identify these headers when looking +for them in the src tree. +util_safalign.h is renamed as safalign.h because util_ namespace is +appropriate when this file belonged to the util's folder which is no +longer the case. + +Resolves: +https://pagure.io/SSSD/sssd/issue/1898 + +Reviewed-by: Fabiano Fidêncio +--- + Makefile.am | 6 +++--- + src/lib/idmap/sss_idmap.c | 2 +- + src/providers/ldap/sdap_idmap.c | 2 +- + src/python/pysss_murmur.c | 2 +- + src/{util => shared}/io.h | 5 ----- + src/{util => shared}/murmurhash3.h | 4 ---- + src/{util/util_safealign.h => shared/safealign.h} | 12 +++--------- + src/sss_client/nss_mc_common.c | 2 +- + src/sss_client/nss_mc_group.c | 2 +- + src/sss_client/nss_mc_initgr.c | 2 +- + src/sss_client/sss_cli.h | 2 +- + src/tests/cmocka/test_inotify.c | 2 +- + src/tests/cmocka/test_io.c | 2 +- + src/tests/util-tests.c | 2 +- + src/util/io.c | 2 +- + src/util/mmap_cache.h | 2 +- + src/util/murmurhash3.c | 2 +- + src/util/util.h | 4 ++-- + 18 files changed, 21 insertions(+), 36 deletions(-) + rename src/{util => shared}/io.h (85%) + rename src/{util => shared}/murmurhash3.h (77%) + rename src/{util/util_safealign.h => shared/safealign.h} (95%) + +diff --git a/Makefile.am b/Makefile.am +index 62e0baf76df2a99329f7f9c77b2e9267b7dfca91..faa2fbabab1ac727edbb1b5bdcbbebebc4a9fbf2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -652,7 +652,6 @@ dist_noinst_HEADERS = \ + src/util/dlinklist.h \ + src/util/debug.h \ + src/util/util.h \ +- src/util/io.h \ + src/util/util_errors.h \ + src/util/safe-format-string.h \ + src/util/session_recording.h \ +@@ -673,13 +672,11 @@ dist_noinst_HEADERS = \ + src/util/refcount.h \ + src/util/find_uid.h \ + src/util/user_info_msg.h \ +- src/util/murmurhash3.h \ + src/util/mmap_cache.h \ + src/util/atomic_io.h \ + src/util/auth_utils.h \ + src/util/authtok.h \ + src/util/authtok-utils.h \ +- src/util/util_safealign.h \ + src/util/util_sss_idmap.h \ + src/util/util_creds.h \ + src/util/inotify.h \ +@@ -849,6 +846,9 @@ dist_noinst_HEADERS = \ + src/tools/common/sss_colondb.h \ + src/tools/sssctl/sssctl.h \ + src/util/probes.h \ ++ src/shared/io.h \ ++ src/shared/murmurhash3.h \ ++ src/shared/safealign.h \ + $(NULL) + + +diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c +index 51338c58777d402fbdf93b8dea4d155f95117233..56ba904bce01d08f822b1ca019439c73087b85c9 100644 +--- a/src/lib/idmap/sss_idmap.c ++++ b/src/lib/idmap/sss_idmap.c +@@ -29,7 +29,7 @@ + + #include "lib/idmap/sss_idmap.h" + #include "lib/idmap/sss_idmap_private.h" +-#include "util/murmurhash3.h" ++#include "shared/murmurhash3.h" + + #define SID_FMT "%s-%d" + #define SID_STR_MAX_LEN 1024 +diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c +index 0fda815224b5ce278e6fae4a5264f82cd1ea4a9d..f5ac511c71e28d0db20f440df09c470a4dcc9c4d 100644 +--- a/src/providers/ldap/sdap_idmap.c ++++ b/src/providers/ldap/sdap_idmap.c +@@ -20,9 +20,9 @@ + along with this program. If not, see . + */ + ++#include "shared/murmurhash3.h" + #include "util/util.h" + #include "util/dlinklist.h" +-#include "util/murmurhash3.h" + #include "providers/ldap/sdap_idmap.h" + #include "util/util_sss_idmap.h" + +diff --git a/src/python/pysss_murmur.c b/src/python/pysss_murmur.c +index a7519e85672028f631ac333950b850c26c610347..060d29df35a97c38fe7b03a655be25d255f6a896 100644 +--- a/src/python/pysss_murmur.c ++++ b/src/python/pysss_murmur.c +@@ -23,7 +23,7 @@ + #include + + #include "util/sss_python.h" +-#include "util/murmurhash3.h" ++#include "shared/murmurhash3.h" + + PyDoc_STRVAR(murmurhash3_doc, + "murmurhash3(key, key_len, seed) -> 32bit integer hash\n\ +diff --git a/src/util/io.h b/src/shared/io.h +similarity index 85% +rename from src/util/io.h +rename to src/shared/io.h +index 8d10ed9c2c6b66b7488cc0c8c5ced83f40ef434b..5a545b60818195d43ebbfe20611a1a2520b98195 100644 +--- a/src/util/io.h ++++ b/src/shared/io.h +@@ -22,11 +22,6 @@ + #ifndef _UTIL_IO_H_ + #define _UTIL_IO_H_ + +-/* CAUTION: +- * This file is also used in sss_client (pam, nss). Therefore it have to be +- * minimalist and cannot include DEBUG macros or header file util.h. +- */ +- + int sss_open_cloexec(const char *pathname, int flags, int *ret); + int sss_openat_cloexec(int dir_fd, const char *pathname, int flags, int *ret); + +diff --git a/src/util/murmurhash3.h b/src/shared/murmurhash3.h +similarity index 77% +rename from src/util/murmurhash3.h +rename to src/shared/murmurhash3.h +index 6910e596be10c9adef90177559ad3e6efe9f18de..3cea68ed3e5e4e891fa742e25f7d89a8eaea8fb3 100644 +--- a/src/util/murmurhash3.h ++++ b/src/shared/murmurhash3.h +@@ -11,10 +11,6 @@ + + #include + +-/* CAUTION: +- * This file is also used in sss_client (pam, nss). Therefore it have to be +- * minimalist and cannot include DEBUG macros or header file util.h. +- */ + uint32_t murmurhash3(const char *key, int len, uint32_t seed); + + #endif /* _UTIL_MURMURHASH3_H_ */ +diff --git a/src/util/util_safealign.h b/src/shared/safealign.h +similarity index 95% +rename from src/util/util_safealign.h +rename to src/shared/safealign.h +index 57f04a17d4a38300b959c1593d756b351ebd89e8..cffc1c5d3591454ae17ad62f2e2f73db80b6dae8 100644 +--- a/src/util/util_safealign.h ++++ b/src/shared/safealign.h +@@ -20,14 +20,8 @@ + along with this program. If not, see . + */ + +-/* CAUTION: +- * This file is also used in sss_client (pam, nss). Therefore it has to be +- * minimalist and cannot include DEBUG macros or header file util.h. +- */ +- +- +-#ifndef _UTIL_SAFEALIGN_H +-#define _UTIL_SAFEALIGN_H ++#ifndef _SAFEALIGN_H ++#define _SAFEALIGN_H + + #include + #include +@@ -144,4 +138,4 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) + #define SAFEALIGN_SET_UINT16 SAFEALIGN_SETMEM_UINT16 + #define SAFEALIGN_SET_STRING SAFEALIGN_SETMEM_STRING + +-#endif /* _UTIL_SAFEALIGN_H */ ++#endif /* _SAFEALIGN_H */ +diff --git a/src/sss_client/nss_mc_common.c b/src/sss_client/nss_mc_common.c +index 6cff2e1b9f640ee81850be86f458597bdb3a6bfb..696d6724630bc36c61da3682af60eddda3f5a964 100644 +--- a/src/sss_client/nss_mc_common.c ++++ b/src/sss_client/nss_mc_common.c +@@ -32,7 +32,7 @@ + #include + #include "nss_mc.h" + #include "sss_cli.h" +-#include "util/io.h" ++#include "shared/io.h" + + /* FIXME: hook up to library destructor to avoid leaks */ + /* FIXME: temporarily open passwd file on our own, later we will probably +diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c +index aacf59d9fd8b81ea895f4660de08f3e44f0ce645..ce88d42fdaf4f19e78fc43e187bc28651cdc3c4e 100644 +--- a/src/sss_client/nss_mc_group.c ++++ b/src/sss_client/nss_mc_group.c +@@ -27,7 +27,7 @@ + #include + #include + #include "nss_mc.h" +-#include "util/util_safealign.h" ++#include "shared/safealign.h" + + struct sss_cli_mc_ctx gr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0, + NULL, 0, 0 }; +diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c +index 74143d9fb3c674c3116d7f4cf0b4c03d993743a2..a77088d849ad3601cb3edb55fc5ea4ae4c52fe38 100644 +--- a/src/sss_client/nss_mc_initgr.c ++++ b/src/sss_client/nss_mc_initgr.c +@@ -30,7 +30,7 @@ + #include + #include + #include "nss_mc.h" +-#include "util/util_safealign.h" ++#include "shared/safealign.h" + + struct sss_cli_mc_ctx initgr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0, + NULL, 0, 0 }; +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index d4198407f2f86c6594aee6a2a43775e429692df0..038406deca1c03376d00495b16b94a39f4f4d39e 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -32,7 +32,7 @@ + #include + #include + +-#include "util/util_safealign.h" ++#include "shared/safealign.h" + + #ifndef HAVE_ERRNO_T + #define HAVE_ERRNO_T +diff --git a/src/tests/cmocka/test_inotify.c b/src/tests/cmocka/test_inotify.c +index 1f8561df1d1254a1535151f09986a49338d8e846..43e36e8cec058dcfca3f3ea6959e6ca9470c9d0a 100644 +--- a/src/tests/cmocka/test_inotify.c ++++ b/src/tests/cmocka/test_inotify.c +@@ -26,7 +26,7 @@ + #include + + #include "limits.h" +-#include "util/io.h" ++#include "shared/io.h" + #include "util/inotify.h" + #include "util/util.h" + #include "tests/common.h" +diff --git a/src/tests/cmocka/test_io.c b/src/tests/cmocka/test_io.c +index 8d29a05cde98f2d9c42b78d0064224e707855a18..20475a01e322f5d42e43dcb75a333d08cbc15fe1 100644 +--- a/src/tests/cmocka/test_io.c ++++ b/src/tests/cmocka/test_io.c +@@ -36,7 +36,7 @@ + #include + + #include "limits.h" +-#include "util/io.h" ++#include "shared/io.h" + #include "util/util.h" + #include "tests/common.h" + +diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c +index a1b3fddce733ae03e2fca20733c3cb6cd20d68ac..d9f2b91c6bfbca5fccb8e2169cdc89fc6a32fbf8 100644 +--- a/src/tests/util-tests.c ++++ b/src/tests/util-tests.c +@@ -34,7 +34,7 @@ + + #include "util/util.h" + #include "util/sss_utf8.h" +-#include "util/murmurhash3.h" ++#include "shared/murmurhash3.h" + #include "tests/common_check.h" + + #define FILENAME_TEMPLATE "tests-atomicio-XXXXXX" +diff --git a/src/util/io.c b/src/util/io.c +index 42e7563c91461d13d9158e72ed03d2a588e0aa36..4d442b47aefd1745a3d523c7ff1324aab947264a 100644 +--- a/src/util/io.c ++++ b/src/util/io.c +@@ -28,7 +28,7 @@ + #include + #include + +-#include "util/io.h" ++#include "shared/io.h" + + /* CAUTION: + * This file have to be minimalist and cannot include DEBUG macros +diff --git a/src/util/mmap_cache.h b/src/util/mmap_cache.h +index 22c1ae62d1ff0c816c23bd8b26140990d692134c..63e096027f5ba9b5eceff77b0ed1e42cd852f8b9 100644 +--- a/src/util/mmap_cache.h ++++ b/src/util/mmap_cache.h +@@ -22,7 +22,7 @@ + #ifndef _MMAP_CACHE_H_ + #define _MMAP_CACHE_H_ + +-#include "util/murmurhash3.h" ++#include "shared/murmurhash3.h" + + + /* NOTE: all the code here assumes that writing a uint32_t nto mmapped +diff --git a/src/util/murmurhash3.c b/src/util/murmurhash3.c +index 061e64e990aa4d91d4a300e116d2fb1193e33392..f8db9d2ee3699b60d1c4111b4b345644d8e60a13 100644 +--- a/src/util/murmurhash3.c ++++ b/src/util/murmurhash3.c +@@ -11,7 +11,7 @@ + #include + + #include "config.h" +-#include "util/murmurhash3.h" ++#include "shared/murmurhash3.h" + #include "util/sss_endian.h" + + static uint32_t rotl(uint32_t x, int8_t r) +diff --git a/src/util/util.h b/src/util/util.h +index 934fae37dffff1e477772d6ac7bc90f45ed4c043..81d5e9b67495dcaafd0194bce700a0d2ae32b72e 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -39,9 +39,10 @@ + #include + + #include "confdb/confdb.h" ++#include "shared/io.h" ++#include "shared/safealign.h" + #include "util/atomic_io.h" + #include "util/util_errors.h" +-#include "util/util_safealign.h" + #include "util/sss_format.h" + #include "util/debug.h" + +@@ -591,7 +592,6 @@ errno_t get_dom_names(TALLOC_CTX *mem_ctx, + /* from util_lock.c */ + errno_t sss_br_lock_file(int fd, size_t start, size_t len, + int num_tries, useconds_t wait); +-#include "io.h" + + #ifdef HAVE_PAC_RESPONDER + #define BUILD_WITH_PAC_RESPONDER true +-- +2.14.1 + diff --git a/0501-libwbclient-sssd-update-interface-to-version-0.14.patch b/0024-libwbclient-sssd-update-interface-to-version-0.14.patch similarity index 87% rename from 0501-libwbclient-sssd-update-interface-to-version-0.14.patch rename to 0024-libwbclient-sssd-update-interface-to-version-0.14.patch index 0e36604..73968a8 100644 --- a/0501-libwbclient-sssd-update-interface-to-version-0.14.patch +++ b/0024-libwbclient-sssd-update-interface-to-version-0.14.patch @@ -1,9 +1,14 @@ -From 213dac21410f3c7aaeac660c5fc9c09bd1ab3d59 Mon Sep 17 00:00:00 2001 +From d1b2a3394e496f749151ccd5aca29507ca69214b Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 7 Jul 2017 11:15:20 +0200 -Subject: [PATCH] libwbclient-sssd: update interface to version 0.14 +Subject: [PATCH 24/93] libwbclient-sssd: update interface to version 0.14 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit The main change is a new member of the wbcAuthErrorInfo struct. + +Reviewed-by: Fabiano Fidêncio --- src/conf_macros.m4 | 4 ++-- src/sss_client/libwbclient/wbclient.exports | 3 +++ @@ -11,10 +16,10 @@ The main change is a new member of the wbcAuthErrorInfo struct. 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 -index 420997229cb3c244afd8fb21b074e43a21de0eda..bd33d3aee194c23ceac01b3729ba3152d9de9f89 100644 +index 2fa7ae9c4dec1007924f44a8d043909e378a6dd3..323830b4246cb94cba74042f0169f78b09087f17 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 -@@ -727,10 +727,10 @@ AC_DEFUN([WITH_LIBWBCLIENT], +@@ -743,10 +743,10 @@ AC_DEFUN([WITH_LIBWBCLIENT], if test x"$with_libwbclient" = xyes; then AC_DEFINE(BUILD_LIBWBCLIENT, 1, [whether to build SSSD implementation of libwbclient]) @@ -82,5 +87,5 @@ index 50ba7f84304df5f24a31cbbad857f22d1c70964d..f2fe8fe60e2ff55399e408056ccfbbff /** -- -2.13.2 +2.14.1 diff --git a/0025-IFP-Do-not-fail-when-a-GHOST-group-is-not-found.patch b/0025-IFP-Do-not-fail-when-a-GHOST-group-is-not-found.patch new file mode 100644 index 0000000..0b29fb1 --- /dev/null +++ b/0025-IFP-Do-not-fail-when-a-GHOST-group-is-not-found.patch @@ -0,0 +1,41 @@ +From d84e841ede0a372a879531b2b7df6905e363b4ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C4=8Cech?= +Date: Wed, 15 Mar 2017 14:23:31 +0100 +Subject: [PATCH 25/93] IFP: Do not fail when a GHOST group is not found +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Usually is okay that there are no ghost attributes for a group as it +basically just means that the group either has no members or all members +have been previously fully resolved. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3315 + +Reviewed-by: Michal Židek +--- + src/responder/ifp/ifp_groups.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index c568c62009cd4b777919dea048fd381a91bd3460..f03c3e4b3720068db4c8266d65ea03a82a7beb62 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -607,12 +607,7 @@ static void resolv_ghosts_group_done(struct tevent_req *subreq) + } + + el = ldb_msg_find_element(group, SYSDB_GHOST); +- if (el == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- if (el->num_values == 0) { ++ if (el == NULL || el->num_values == 0) { + ret = EOK; + goto done; + } +-- +2.14.1 + diff --git a/0026-SHARED-Return-warning-back-about-minimal-header-file.patch b/0026-SHARED-Return-warning-back-about-minimal-header-file.patch new file mode 100644 index 0000000..859aada --- /dev/null +++ b/0026-SHARED-Return-warning-back-about-minimal-header-file.patch @@ -0,0 +1,94 @@ +From eec0b39ed884814c124bfec2060b779023f8b200 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 3 Aug 2017 14:29:52 +0200 +Subject: [PATCH 26/93] SHARED: Return warning back about minimal header files + +The warning still make a sense and should be there. +Patch also fixes header guards due t changed location. + +Related to: +https://pagure.io/SSSD/sssd/issue/1898 + +Reviewed-by: Jakub Hrozek +--- + src/shared/io.h | 11 ++++++++--- + src/shared/murmurhash3.h | 11 ++++++++--- + src/shared/safealign.h | 11 ++++++++--- + 3 files changed, 24 insertions(+), 9 deletions(-) + +diff --git a/src/shared/io.h b/src/shared/io.h +index 5a545b60818195d43ebbfe20611a1a2520b98195..26caa52872e2fc8d4ecd1be242e0c41f786abd2b 100644 +--- a/src/shared/io.h ++++ b/src/shared/io.h +@@ -19,10 +19,15 @@ + along with this program. If not, see . + */ + +-#ifndef _UTIL_IO_H_ +-#define _UTIL_IO_H_ ++#ifndef _SHARED_IO_H_ ++#define _SHARED_IO_H_ ++ ++/* CAUTION: ++ * This file is also used in sss_client (pam, nss). Therefore it have to be ++ * minimalist and cannot include DEBUG macros or header file util.h. ++ */ + + int sss_open_cloexec(const char *pathname, int flags, int *ret); + int sss_openat_cloexec(int dir_fd, const char *pathname, int flags, int *ret); + +-#endif /* _UTIL_IO_H_ */ ++#endif /* _SHARED_IO_H_ */ +diff --git a/src/shared/murmurhash3.h b/src/shared/murmurhash3.h +index 3cea68ed3e5e4e891fa742e25f7d89a8eaea8fb3..27671831c4795aa32f2f1c64ec23f8d226d51223 100644 +--- a/src/shared/murmurhash3.h ++++ b/src/shared/murmurhash3.h +@@ -6,11 +6,16 @@ + * clients can be both 64 or 32 bit at the same time. + */ + +-#ifndef _UTIL_MURMURHASH3_H_ +-#define _UTIL_MURMURHASH3_H_ ++#ifndef _SHARED_MURMURHASH3_H_ ++#define _SHARED_MURMURHASH3_H_ ++ ++/* CAUTION: ++ * This file is also used in sss_client (pam, nss). Therefore it have to be ++ * minimalist and cannot include DEBUG macros or header file util.h. ++ */ + + #include + + uint32_t murmurhash3(const char *key, int len, uint32_t seed); + +-#endif /* _UTIL_MURMURHASH3_H_ */ ++#endif /* _SHARED_MURMURHASH3_H_ */ +diff --git a/src/shared/safealign.h b/src/shared/safealign.h +index cffc1c5d3591454ae17ad62f2e2f73db80b6dae8..2316ed14245c4469171f9eb4a42e70fc6b3fd8a8 100644 +--- a/src/shared/safealign.h ++++ b/src/shared/safealign.h +@@ -20,8 +20,13 @@ + along with this program. If not, see . + */ + +-#ifndef _SAFEALIGN_H +-#define _SAFEALIGN_H ++#ifndef _SHARED_SAFEALIGN_H ++#define _SHARED_SAFEALIGN_H ++ ++/* CAUTION: ++ * This file is also used in sss_client (pam, nss). Therefore it have to be ++ * minimalist and cannot include DEBUG macros or header file util.h. ++ */ + + #include + #include +@@ -138,4 +143,4 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) + #define SAFEALIGN_SET_UINT16 SAFEALIGN_SETMEM_UINT16 + #define SAFEALIGN_SET_STRING SAFEALIGN_SETMEM_STRING + +-#endif /* _SAFEALIGN_H */ ++#endif /* _SHARED_SAFEALIGN_H */ +-- +2.14.1 + diff --git a/0027-intg-Disable-add_remove-tests.patch b/0027-intg-Disable-add_remove-tests.patch new file mode 100644 index 0000000..be7807b --- /dev/null +++ b/0027-intg-Disable-add_remove-tests.patch @@ -0,0 +1,74 @@ +From a24e735d33b788fec32acba70f30709eff44ebdf Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 10 Aug 2017 15:18:43 +0200 +Subject: [PATCH 27/93] intg: Disable add_remove tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +add_remove fails quite often in enumeration test. The reason of failures +is not obvious and will take some time to investigate it. +Failures blocks testing of other patches therefore its better to disable +tests. (pytest run functions/methods which start with "test") + +Temporary workaround for: +https://pagure.io/SSSD/sssd/issue/3463 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Nikolai Kondrashov +--- + src/tests/intg/test_enumeration.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py +index 47772dea288434c5b213eeba9b4eac904423d707..fdb8d376879f756957f8f25fd28b37d7178aeff5 100644 +--- a/src/tests/intg/test_enumeration.py ++++ b/src/tests/intg/test_enumeration.py +@@ -403,7 +403,7 @@ def user_and_groups_rfc2307_bis(request, ldap_conn): + return None + + +-def test_add_remove_user(ldap_conn, blank_rfc2307): ++def _test_add_remove_user(ldap_conn, blank_rfc2307): + """Test user addition and removal are reflected by SSSD""" + e = ldap_ent.user(ldap_conn.ds_inst.base_dn, "user", 2001, 2000) + time.sleep(INTERACTIVE_TIMEOUT/2) +@@ -418,7 +418,7 @@ def test_add_remove_user(ldap_conn, blank_rfc2307): + ent.assert_passwd(ent.contains_only()) + + +-def test_add_remove_group_rfc2307(ldap_conn, blank_rfc2307): ++def _test_add_remove_group_rfc2307(ldap_conn, blank_rfc2307): + """Test RFC2307 group addition and removal are reflected by SSSD""" + e = ldap_ent.group(ldap_conn.ds_inst.base_dn, "group", 2001) + time.sleep(INTERACTIVE_TIMEOUT/2) +@@ -433,7 +433,7 @@ def test_add_remove_group_rfc2307(ldap_conn, blank_rfc2307): + ent.assert_group(ent.contains_only()) + + +-def test_add_remove_group_rfc2307_bis(ldap_conn, blank_rfc2307_bis): ++def _test_add_remove_group_rfc2307_bis(ldap_conn, blank_rfc2307_bis): + """Test RFC2307bis group addition and removal are reflected by SSSD""" + e = ldap_ent.group_bis(ldap_conn.ds_inst.base_dn, "group", 2001) + time.sleep(INTERACTIVE_TIMEOUT/2) +@@ -448,7 +448,7 @@ def test_add_remove_group_rfc2307_bis(ldap_conn, blank_rfc2307_bis): + ent.assert_group(ent.contains_only()) + + +-def test_add_remove_membership_rfc2307(ldap_conn, user_and_group_rfc2307): ++def _test_add_remove_membership_rfc2307(ldap_conn, user_and_group_rfc2307): + """Test user membership addition and removal are reflected by SSSD""" + time.sleep(INTERACTIVE_TIMEOUT/2) + # Add user to group +@@ -464,7 +464,7 @@ def test_add_remove_membership_rfc2307(ldap_conn, user_and_group_rfc2307): + ent.assert_group_by_name("group", dict(mem=ent.contains_only())) + + +-def test_add_remove_membership_rfc2307_bis(ldap_conn, ++def _test_add_remove_membership_rfc2307_bis(ldap_conn, + user_and_groups_rfc2307_bis): + """ + Test user and group membership addition and removal are reflected by SSSD, +-- +2.14.1 + diff --git a/0028-UTIL-Set-udp_preference_limit-0-in-krb5-snippet.patch b/0028-UTIL-Set-udp_preference_limit-0-in-krb5-snippet.patch new file mode 100644 index 0000000..ca12238 --- /dev/null +++ b/0028-UTIL-Set-udp_preference_limit-0-in-krb5-snippet.patch @@ -0,0 +1,198 @@ +From 6bd6571dfe97fb9c6ce9040c3fcfb4965f95eda1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C4=8Cech?= +Date: Tue, 28 Mar 2017 14:35:22 +0200 +Subject: [PATCH 28/93] UTIL: Set udp_preference_limit=0 in krb5 snippet +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We add udp_preference_limit = 0 to krb5 snippet if ad provider is +used. This option enable TCP connection before UDP, when sending +a message to the KDC. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3254 + +Signed-off-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Robbie Harwood +--- + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/ipa/ipa_subdomains.c | 2 +- + src/tests/cmocka/test_utils.c | 12 ++++----- + src/util/domain_info_utils.c | 54 +++++++++++++++++++++++++++++--------- + src/util/util.h | 3 ++- + 5 files changed, 51 insertions(+), 22 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 749c5b42f16d81aecdecf1961541fb34eb0732b9..280aa54c23bf61e60d23ea91bd44a39f9f43d155 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -702,7 +702,7 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) + "will not be created.\n"); + } + +- ret = sss_write_krb5_conf_snippet(path, canonicalize); ++ ret = sss_write_krb5_conf_snippet(path, canonicalize, true); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n"); + /* Just continue */ +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index e052f98477b65c5e9778d889333bd9101763db23..7f8bcdbad3e8375c8d56a51a7ac615b29ee0457d 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -117,7 +117,7 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) + ret = sss_write_krb5_conf_snippet( + dp_opt_get_string(ctx->ipa_id_ctx->ipa_options->basic, + IPA_KRB5_CONFD_PATH), +- canonicalize); ++ canonicalize, false); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n"); + /* Just continue */ +diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c +index 25508b172287c455d706baff9c3068f95a3ee403..7cbb395dab6c1336716518daac1d700fcaa7b789 100644 +--- a/src/tests/cmocka/test_utils.c ++++ b/src/tests/cmocka/test_utils.c +@@ -1350,16 +1350,16 @@ void test_sss_write_krb5_conf_snippet(void **state) + char *file; + char *file_krb5_libdefaults; + +- ret = sss_write_krb5_conf_snippet(NULL, false); ++ ret = sss_write_krb5_conf_snippet(NULL, false, false); + assert_int_equal(ret, EINVAL); + +- ret = sss_write_krb5_conf_snippet("abc", false); ++ ret = sss_write_krb5_conf_snippet("abc", false, false); + assert_int_equal(ret, EINVAL); + +- ret = sss_write_krb5_conf_snippet("", false); ++ ret = sss_write_krb5_conf_snippet("", false, false); + assert_int_equal(ret, EOK); + +- ret = sss_write_krb5_conf_snippet("none", false); ++ ret = sss_write_krb5_conf_snippet("none", false, false); + assert_int_equal(ret, EOK); + + cwd = getcwd(buf, PATH_MAX); +@@ -1375,11 +1375,11 @@ void test_sss_write_krb5_conf_snippet(void **state) + "%s/%s/krb5_libdefaults", cwd, TESTS_PATH); + assert_true(ret > 0); + +- ret = sss_write_krb5_conf_snippet(path, true); ++ ret = sss_write_krb5_conf_snippet(path, true, true); + assert_int_equal(ret, EOK); + + /* Check if writing a second time will work as well */ +- ret = sss_write_krb5_conf_snippet(path, true); ++ ret = sss_write_krb5_conf_snippet(path, true, true); + assert_int_equal(ret, EOK); + + #ifdef HAVE_KRB5_LOCALAUTH_PLUGIN +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 1aacfa2832890a8c3914336aa53d350577ec29f8..3a3f5130a32e2c5fe4b81819bf2de697a4474111 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -734,15 +734,14 @@ done: + #endif + } + +-#define KRB5_LIBDEFAUTLS_CONFIG \ +-"[libdefaults]\n" \ +-" canonicalize = true\n" +- +-static errno_t sss_write_krb5_libdefaults_snippet(const char *path) ++static errno_t sss_write_krb5_libdefaults_snippet(const char *path, ++ bool canonicalize, ++ bool udp_limit) + { + int ret; + TALLOC_CTX *tmp_ctx = NULL; + const char *file_name; ++ char *file_contents; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -760,7 +759,37 @@ static errno_t sss_write_krb5_libdefaults_snippet(const char *path) + DEBUG(SSSDBG_FUNC_DATA, "File for KRB5 kibdefaults configuration is [%s]\n", + file_name); + +- ret = sss_write_krb5_snippet_common(file_name, KRB5_LIBDEFAUTLS_CONFIG); ++ file_contents = talloc_strdup(tmp_ctx, "[libdefaults]\n"); ++ if (file_contents == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "talloc_asprintf failed while creating the content\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (canonicalize == true) { ++ file_contents = talloc_asprintf_append(file_contents, ++ " canonicalize = true\n"); ++ if (file_contents == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "talloc_asprintf failed while appending to the content\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ if (udp_limit == true) { ++ file_contents = talloc_asprintf_append(file_contents, ++ " udp_preference_limit = 0\n"); ++ if (file_contents == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "talloc_asprintf failed while appending to the content\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = sss_write_krb5_snippet_common(file_name, file_contents); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_write_krb5_snippet_common failed.\n"); + goto done; +@@ -772,7 +801,8 @@ done: + return ret; + } + +-errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize) ++errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize, ++ bool udp_limit) + { + errno_t ret; + errno_t err; +@@ -794,12 +824,10 @@ errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize) + goto done; + } + +- if (canonicalize) { +- ret = sss_write_krb5_libdefaults_snippet(path); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_write_krb5_libdefaults_snippet failed.\n"); +- goto done; +- } ++ ret = sss_write_krb5_libdefaults_snippet(path, canonicalize, udp_limit); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_write_krb5_libdefaults_snippet failed.\n"); ++ goto done; + } + + ret = EOK; +diff --git a/src/util/util.h b/src/util/util.h +index 81d5e9b67495dcaafd0194bce700a0d2ae32b72e..9b64dead88f05f16b00e73d59b2af06dcd485ff7 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -582,7 +582,8 @@ errno_t sss_get_domain_mappings_content(TALLOC_CTX *mem_ctx, + + errno_t sss_write_domain_mappings(struct sss_domain_info *domain); + +-errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize); ++errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize, ++ bool udp_limit); + + errno_t get_dom_names(TALLOC_CTX *mem_ctx, + struct sss_domain_info *start_dom, +-- +2.14.1 + diff --git a/0029-Fix-minor-typos.patch b/0029-Fix-minor-typos.patch new file mode 100644 index 0000000..6630cdb --- /dev/null +++ b/0029-Fix-minor-typos.patch @@ -0,0 +1,54 @@ +From 1afc796952755f9cc96ea0b93989cd93214103a2 Mon Sep 17 00:00:00 2001 +From: Yuri Chornoivan +Date: Mon, 31 Jul 2017 12:52:51 +0000 +Subject: [PATCH 29/93] Fix minor typos +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merges: https://pagure.io/SSSD/sssd/pull-request/3456 + +Reviewed-by: Michal Židek +--- + src/config/SSSDConfig/__init__.py.in | 4 ++-- + src/tools/sssctl/sssctl_user_checks.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 303bc62f42691e3f21aae393a301742f090e6f82..0e0c3be6d0c6531daddd3927c53156d28a657d2b 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -92,7 +92,7 @@ option_strings = { + 'offline_failed_login_attempts' : _('How many failed logins attempts are allowed when offline'), + 'offline_failed_login_delay' : _('How long (minutes) to deny login after offline_failed_login_attempts has been reached'), + 'pam_verbosity' : _('What kind of messages are displayed to the user during authentication'), +- 'pam_response_filter' : _('Filter PAM responses sent by the pam_sss'), ++ 'pam_response_filter' : _('Filter PAM responses sent to the pam_sss'), + 'pam_id_timeout' : _('How many seconds to keep identity information cached for PAM requests'), + 'pam_pwd_expiration_warning' : _('How many days before password expiration a warning should be displayed'), + 'pam_trusted_users' : _('List of trusted uids or user\'s name'), +@@ -138,7 +138,7 @@ option_strings = { + 'username': _('The username to use when authenticating to a Custodia server using basic_auth'), + 'password': _('The password to use when authenticating to a Custodia server using basic_auth'), + 'verify_peer': _('If true peer\'s certificate is verified if proxy_url uses https protocol'), +- 'verify_host': _('If false peer\'s certificate may contain different hostname then proxy_url when https protocol is used'), ++ 'verify_host': _('If false peer\'s certificate may contain different hostname than proxy_url when https protocol is used'), + 'capath': _('Path to directory where certificate authority certificates are stored'), + 'cacert': _('Path to file containing server\'s CA certificate'), + 'cert': _('Path to file containing client\'s certificate'), +diff --git a/src/tools/sssctl/sssctl_user_checks.c b/src/tools/sssctl/sssctl_user_checks.c +index d5cd8a1b42e84aa96df95ed39905c864a38212b7..8e2acad65a35a99e84b0401a2e6e8ded62682c2e 100644 +--- a/src/tools/sssctl/sssctl_user_checks.c ++++ b/src/tools/sssctl/sssctl_user_checks.c +@@ -234,7 +234,7 @@ errno_t sssctl_user_checks(struct sss_cmdline *cmdline, + + ret = get_ifp_user(user); + if (ret != 0) { +- fprintf(stderr, _("InforPipe User lookup with [%s] failed.\n"), ++ fprintf(stderr, _("InfoPipe User lookup with [%s] failed.\n"), + user); + } + } +-- +2.14.1 + diff --git a/0030-Fix-minor-typos-in-docs.patch b/0030-Fix-minor-typos-in-docs.patch new file mode 100644 index 0000000..fd90783 --- /dev/null +++ b/0030-Fix-minor-typos-in-docs.patch @@ -0,0 +1,192 @@ +From ba2fb2c7b74a5247737da051b38e7889b7b44d5d Mon Sep 17 00:00:00 2001 +From: Yuri Chornoivan +Date: Mon, 31 Jul 2017 17:51:28 +0000 +Subject: [PATCH 30/93] Fix minor typos in docs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merges: https://pagure.io/SSSD/sssd/pull-request/3456 + +Reviewed-by: Michal Židek +--- + src/man/idmap_sss.8.xml | 2 +- + src/man/sss-certmap.5.xml | 22 +++++++++++----------- + src/man/sssd-ad.5.xml | 2 +- + src/man/sssd-ldap.5.xml | 2 +- + src/man/sssd.conf.5.xml | 10 +++++----- + 5 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/src/man/idmap_sss.8.xml b/src/man/idmap_sss.8.xml +index 0b73966e5952705a0f340ac169775c30153c392d..b819304fb43490c7c6dd3040e675b9e14e80574a 100644 +--- a/src/man/idmap_sss.8.xml ++++ b/src/man/idmap_sss.8.xml +@@ -13,7 +13,7 @@ + + + idmap_sss +- SSSSD's idmap_sss Backend for Winbind ++ SSSD's idmap_sss Backend for Winbind + + + +diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml +index 12df6a7936dfe4346a05d7baffe6f44fed8e1879..9b70c1b27e6f76142cc7a04b3494dad5f47454b6 100644 +--- a/src/man/sss-certmap.5.xml ++++ b/src/man/sss-certmap.5.xml +@@ -42,7 +42,7 @@ + + PRIORITY + +- The rules are process by priority while the number '0' (zero) ++ The rules are processed by priority while the number '0' (zero) + indicates the highest priority. The higher the number the lower is + the priority. A missing value indicates the lowest priority. + +@@ -110,8 +110,8 @@ + + + This option can be used to specify which key usage +- values the certificate should have. The following value +- can be used in a comma separate list: ++ values the certificate should have. The following values ++ can be used in a comma separated list: + + digitalSignature + nonRepudiation +@@ -345,7 +345,7 @@ + relevance here). Because of this the mapping rule is based on LDAP + search filter syntax with templates to add certificate content to + the filter. It is expected that the filter will only contain the +- specific data needed for the mapping an that the caller will embed ++ specific data needed for the mapping and that the caller will embed + it in another filter to do the actual search. Because of this the + filter string should start and stop with '(' and ')' respectively. + +@@ -365,7 +365,7 @@ + + + The templates to add certificate data to the search filter are based +- on Python-style formatting strings. They consists of a keyword in ++ on Python-style formatting strings. They consist of a keyword in + curly braces with an optional sub-component specifier separated by a + '.' or an optional conversion/formatting option separated by a '!'. + Allowed values are: +@@ -444,7 +444,7 @@ + + This template will add the Kerberos principal which is + taken either from the SAN used by pkinit or the one used +- by AD. The 'short_name' component represent the first ++ by AD. The 'short_name' component represents the first + part of the principal before the '@' sign. + + +@@ -457,8 +457,8 @@ + + + This template will add the Kerberos principal which is +- given by then SAN used by pkinit. The 'short_name' +- component represent the first part of the principal ++ given by the SAN used by pkinit. The 'short_name' ++ component represents the first part of the principal + before the '@' sign. + + +@@ -471,7 +471,7 @@ + + + This template will add the Kerberos principal which is +- given by then SAN used by AD. The 'short_name' component ++ given by the SAN used by AD. The 'short_name' component + represent the first part of the principal before the '@' + sign. + +@@ -486,7 +486,7 @@ + + This template will add the string which is stored in the + rfc822Name component of the SAN, typically an email +- address. The 'short_name' component represent the first ++ address. The 'short_name' component represents the first + part of the address before the '@' sign. + + +@@ -500,7 +500,7 @@ + + This template will add the string which is stored in the + dNSName component of the SAN, typically a fully-qualified host name. +- The 'short_name' component represent the first ++ The 'short_name' component represents the first + part of the name before the first '.' sign. + + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 59c23e68123d7b83c19ed6ba256989ab4e643b6d..08c1dd09fb829c6cffb416250b9b518668ec5790 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -826,7 +826,7 @@ ad_gpo_map_deny = +my_pam_service + + + This option should only be used to test the machine +- account renewal task. The option expect 2 integers ++ account renewal task. The option expects 2 integers + separated by a colon (':'). The first integer + defines the interval in seconds how often the task + is run. The second specifies the initial timeout in +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index 739ae15c359da4e8dad9bc225ea60cff9dc96b91..a12f52797e67a3cca75ad7f6a10539ca08324d8f 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -2631,7 +2631,7 @@ ldap_access_filter = (employeeType=admin) + + + If the option ldap_use_tokengroups is +- enabled. The searches against Active Directory will ++ enabled, the searches against Active Directory will + not be restricted and return all groups memberships, + even with no GID mapping. It is recommended to disable + this feature, if group names are not being displayed +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index b9eaf5eddb5c39125f7ce1c7a988c374378bbb32..7cd6ffd7a632449e23672da14586560500b9d185 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1100,7 +1100,7 @@ fallback_homedir = /home/%u + A comma separated list of strings which allows to + remove (filter) data sent by the PAM responder to + pam_sss PAM module. There are different kind of +- responses send to pam_sss e.g. messages displayed to ++ responses sent to pam_sss e.g. messages displayed to + the user or environment variables which should be + set by pam_sss. + +@@ -1113,16 +1113,16 @@ fallback_homedir = /home/%u + Currently the following filters are supported: + + ENV +- Do not sent any environment ++ Do not send any environment + variables to any service. + + ENV:var_name +- Do not sent environment ++ Do not send environment + variable var_name to any + service. + + ENV:var_name:service +- Do not sent environment ++ Do not send environment + variable var_name to + service. + +@@ -2862,7 +2862,7 @@ subdomain_inherit = ldap_purge_cache_timeout + The following example illustrates the use of an application + domain. In this setup, the POSIX domain is connected to an LDAP + server and is used by the OS through the NSS responder. In addition, +- the application domains also requests the telephoneNumber attribute, ++ the application domain also requests the telephoneNumber attribute, + stores it as the phone attribute in the cache and makes the phone + attribute reachable through the D-Bus interface. + +-- +2.14.1 + diff --git a/0031-SPEC-require-http-parser-only-on-rhel7.4.patch b/0031-SPEC-require-http-parser-only-on-rhel7.4.patch new file mode 100644 index 0000000..9b7bc36 --- /dev/null +++ b/0031-SPEC-require-http-parser-only-on-rhel7.4.patch @@ -0,0 +1,31 @@ +From 08cb2a34402d865c3052f80f5be8f9e653c7812f Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 16 Aug 2017 13:02:50 +0200 +Subject: [PATCH 31/93] SPEC: require http-parser only on rhel7.4 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It was removed from epel + +Reviewed-by: Fabiano Fidêncio +--- + contrib/sssd.spec.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index c65d4e66178e6b1ccec7835f4518a9fbe2a6336a..0b7a6115778a185eae78be0f5447e6d883be6eb9 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -108,7 +108,7 @@ + %global enable_systemtap_opt --enable-systemtap + %endif + +-%if (0%{?fedora} || 0%{?epel} >= 7) ++%if (0%{?fedora} || (0%{?rhel} >= 7 && 0%{rhel7_minor} >= 4)) + %global with_secrets 1 + %else + %global with_secret_responder --without-secrets +-- +2.14.1 + diff --git a/0032-intg-Increase-startup-timeouts-for-kcm-and-secrets.patch b/0032-intg-Increase-startup-timeouts-for-kcm-and-secrets.patch new file mode 100644 index 0000000..7aeeeb8 --- /dev/null +++ b/0032-intg-Increase-startup-timeouts-for-kcm-and-secrets.patch @@ -0,0 +1,59 @@ +From dc5da74112bde32b0bd33d9304f7e94eb8ed2885 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 17 Aug 2017 06:58:10 +0200 +Subject: [PATCH 32/93] intg: Increase startup timeouts for kcm and secrets + +In cwrap environment, we start sssd_kcm and sssd_secrets ourself +and not by systemd socket activation. Our approach is to wait a second in +a loop till socket is available. However sometimes 1 second is not enough. +Patch increases wait timeout from 1 second to 10 and it seems to be enough even +when processes were executed with valgrind. + +Traceback (most recent call last): + File "src/tests/intg/test_secrets.py", line 419, in setup_for_cli_timeout_test + return create_sssd_secrets_fixture(request) + File "src/tests/intg/test_secrets.py", line 82, in create_sssd_secrets_fixture + assert os.path.exists(sock_path) +AssertionError: assert False + + where False = ('/tmp/sssd-intg.cdv0namx/var/run/secrets.socket') + + where = .exists + + where = os.path + +Resolves: +https://pagure.io/SSSD/sssd/issue/3481 + +Reviewed-by: Jakub Hrozek +--- + src/tests/intg/test_kcm.py | 2 +- + src/tests/intg/test_secrets.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py +index ae49eca808b1b04faf2a9630043f9998816f3efe..72a3458c8c598bae1fe929c062990da0bcbc3063 100644 +--- a/src/tests/intg/test_kcm.py ++++ b/src/tests/intg/test_kcm.py +@@ -90,7 +90,7 @@ def create_sssd_kcm_fixture(sock_path, request): + else: + abs_sock_path = os.path.join(config.RUNSTATEDIR, sock_path) + sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +- for _ in range(1, 10): ++ for _ in range(1, 100): + try: + sck.connect(abs_sock_path) + except: +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index a66431ff4e73a6320e134efafcc3817e08f0802d..32ea58ff017f01bc6a28f826d10dabff60761bcb 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -61,7 +61,7 @@ def create_sssd_secrets_fixture(request): + else: + sock_path = os.path.join(config.RUNSTATEDIR, "secrets.socket") + sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +- for _ in range(1, 10): ++ for _ in range(1, 100): + try: + sck.connect(sock_path) + except: +-- +2.14.1 + diff --git a/0033-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch b/0033-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch new file mode 100644 index 0000000..f216a2f --- /dev/null +++ b/0033-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch @@ -0,0 +1,210 @@ +From a5f300adf19ec9c3087c62bd93a5175db799687a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 11 Jul 2017 12:41:57 +0200 +Subject: [PATCH 33/93] sudo: add a threshold option to reduce size of rules + refresh filter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a large number of rules is expired at one time the ldap filter may +become too large to be processed by server. This commits adds a new +option "sudo_threshold" to sudo responder. If the threshold is +exceeded a full refreshed is done instead of rules refresh. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3478 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + src/confdb/confdb.h | 2 ++ + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd.conf.5.xml | 19 +++++++++++++++++++ + src/responder/sudo/sudosrv.c | 11 +++++++++++ + src/responder/sudo/sudosrv_get_sudorules.c | 25 ++++++++++++++++++++----- + src/responder/sudo/sudosrv_private.h | 1 + + 8 files changed, 56 insertions(+), 5 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 3773358374064c68b2ae254fd18f43ca4c43d834..66ecc041398fda973c0f30a47a3f5944c88d19c2 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -139,6 +139,8 @@ + #define CONFDB_DEFAULT_SUDO_TIMED false + #define CONFDB_SUDO_INVERSE_ORDER "sudo_inverse_order" + #define CONFDB_DEFAULT_SUDO_INVERSE_ORDER false ++#define CONFDB_SUDO_THRESHOLD "sudo_threshold" ++#define CONFDB_DEFAULT_SUDO_THRESHOLD 50 + + /* autofs */ + #define CONFDB_AUTOFS_CONF_ENTRY "config/autofs" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 0e0c3be6d0c6531daddd3927c53156d28a657d2b..de757521cff58460049bb8c4873efaf6bf0b8d95 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -107,6 +107,7 @@ option_strings = { + # [sudo] + 'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'), + 'sudo_inverse_order' : _('If true, SSSD will switch back to lower-wins ordering logic'), ++ 'sudo_threshold' : _('Maximum number of rules that can be refreshed at once. If this is exceeded, full refresh is performed.'), + + # [autofs] + 'autofs_negative_timeout' : _('Negative cache timeout length (seconds)'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 4537d0fe87d7084cdff5e591451298393b7f632f..cba59d2c3813f44b8ab85b4c246108232f9d8fd4 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -145,6 +145,7 @@ option = cache_first + # sudo service + option = sudo_timed + option = sudo_inverse_order ++option = sudo_threshold + + [rule/allowed_autofs_options] + validator = ini_allowed_options +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index ef910f0dfc96241feca6db241219783d774891ef..0d11771ae3df50ba9f380e44747a5385a224544d 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -79,6 +79,7 @@ pam_app_services = str, None, false + # sudo service + sudo_timed = bool, None, false + sudo_inverse_order = bool, None, false ++sudo_threshold = int, None, false + + [autofs] + # autofs service +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7cd6ffd7a632449e23672da14586560500b9d185..7b5abebbf68a832c3b0af9bcff9c535eca77778a 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1378,6 +1378,25 @@ pam_account_locked_message = Account locked, please contact help desk. + + + ++ ++ ++ sudo_threshold (integer) ++ ++ ++ Maximum number of expired rules that can be ++ refreshed at once. If number of expired rules ++ is below threshold, those rules are refreshed ++ with rules refresh mechanism. If ++ the threshold is exceeded a ++ full refresh of sudo rules is ++ triggered instead. ++ ++ ++ Default: 50 ++ ++ ++ ++ + + + +diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c +index b427878d4dbe9090824a01386a7475be88b699c0..dca70ea4afc0e6df6d1b1864338c7b1091a98fee 100644 +--- a/src/responder/sudo/sudosrv.c ++++ b/src/responder/sudo/sudosrv.c +@@ -148,6 +148,17 @@ int sudo_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + ++ /* Get sudo_inverse_order option */ ++ ret = confdb_get_int(sudo_ctx->rctx->cdb, ++ CONFDB_SUDO_CONF_ENTRY, CONFDB_SUDO_THRESHOLD, ++ CONFDB_DEFAULT_SUDO_THRESHOLD, ++ &sudo_ctx->threshold); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n", ++ ret, strerror(ret)); ++ goto fail; ++ } ++ + ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); +diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c +index cfdbfc9c9c66d96f774822d6a4d4aaaf1327abe3..3272e634d895acf4854309371779a00cf1525126 100644 +--- a/src/responder/sudo/sudosrv_get_sudorules.c ++++ b/src/responder/sudo/sudosrv_get_sudorules.c +@@ -479,6 +479,7 @@ sudosrv_refresh_rules_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, + struct sss_domain_info *domain, ++ int threshold, + uid_t uid, + const char *username, + char **groups) +@@ -520,9 +521,20 @@ sudosrv_refresh_rules_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_INTERNAL, "Refreshing %d expired rules of [%s@%s]\n", + num_rules, username, domain->name); + +- subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, +- SSS_DP_SUDO_REFRESH_RULES, +- username, num_rules, rules); ++ if (num_rules > threshold) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Rules threshold [%d] is reached, performing full refresh " ++ "instead.\n", threshold); ++ ++ subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, ++ SSS_DP_SUDO_FULL_REFRESH, ++ username, 0, NULL); ++ } else { ++ subreq = sss_dp_get_sudoers_send(state, rctx, domain, false, ++ SSS_DP_SUDO_REFRESH_RULES, ++ username, num_rules, rules); ++ } ++ + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -609,6 +621,7 @@ struct sudosrv_get_rules_state { + struct sss_domain_info *domain; + char **groups; + bool inverse_order; ++ int threshold; + + struct sysdb_attrs **rules; + uint32_t num_rules; +@@ -640,6 +653,7 @@ struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx, + state->type = type; + state->uid = uid; + state->inverse_order = sudo_ctx->inverse_order; ++ state->threshold = sudo_ctx->threshold; + + DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username); + +@@ -696,8 +710,9 @@ static void sudosrv_get_rules_initgr_done(struct tevent_req *subreq) + } + + subreq = sudosrv_refresh_rules_send(state, state->ev, state->rctx, +- state->domain, state->uid, +- state->username, state->groups); ++ state->domain, state->threshold, ++ state->uid, state->username, ++ state->groups); + if (subreq == NULL) { + ret = ENOMEM; + goto done; +diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h +index 94f3c4458ab20e64db3e0bfce726d5d30a70a202..c76bdd3955bc29b7ba2cda58c503a4c616d7e63a 100644 +--- a/src/responder/sudo/sudosrv_private.h ++++ b/src/responder/sudo/sudosrv_private.h +@@ -48,6 +48,7 @@ struct sudo_ctx { + */ + bool timed; + bool inverse_order; ++ int threshold; + }; + + struct sudo_cmd_ctx { +-- +2.14.1 + diff --git a/0034-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch b/0034-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch new file mode 100644 index 0000000..9509d74 --- /dev/null +++ b/0034-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch @@ -0,0 +1,54 @@ +From 725d04cd21016dc6092a9f03cd363bb83d7c054c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 22 Aug 2017 13:09:18 +0200 +Subject: [PATCH 34/93] libwbclient: Change return code for + wbcAuthenticateUserEx + +Samba-4.6 change behaviour of few functions +New version of code make sure session info for user is stored in cache. +It is a performance optimisation to prevent contacting KDC for each +session. More details in samba bug +https://bugzilla.samba.org/show_bug.cgi?id=11259 + +Old return code WBC_SSSD_NOT_IMPLEMENTED was translated +to NT_STATUS_LOGON_FAILURE which caused many failures. + + [2017/08/21 11:34:15.044321, 5, pid=27742, effective(0, 0), real(0, 0)] + ../libcli/security/security_token.c:53(security_token_debug) + Security token: (NULL) + [2017/08/21 11:34:15.044330, 5, pid=27742, effective(0, 0), real(0, 0)] + ../source3/auth/token_util.c:640(debug_unix_user_token) + UNIX token of user 0 + Primary group is 0 and contains 0 supplementary groups + [2017/08/21 11:34:15.044349, 4, pid=27742, effective(0, 0), real(0, 0)] + ../source3/smbd/sec_ctx.c:439(pop_sec_ctx) + pop_sec_ctx (0, 0) - sec_ctx_stack_ndx = 0 + [2017/08/21 11:34:15.044360, 1, pid=27742, effective(0, 0), real(0, 0)] + ../source3/smbd/sesssetup.c:290(reply_sesssetup_and_X_spnego) + Failed to generate session_info (user and group token) for session + setup: NT_STATUS_LOGON_FAILURE + +Resolves: +https://pagure.io/SSSD/sssd/issue/3461 + +Reviewed-by: Sumit Bose +--- + src/sss_client/libwbclient/wbc_pam_sssd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sss_client/libwbclient/wbc_pam_sssd.c b/src/sss_client/libwbclient/wbc_pam_sssd.c +index 174cf1310fad0243036fe591978cc89700903896..fb269fd7ab1f6b27a9c9a9cb34381383611e76cc 100644 +--- a/src/sss_client/libwbclient/wbc_pam_sssd.c ++++ b/src/sss_client/libwbclient/wbc_pam_sssd.c +@@ -49,7 +49,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, + *error = NULL; + } + +- WBC_SSSD_NOT_IMPLEMENTED; ++ WBC_ERR_WINBIND_NOT_AVAILABLE; + } + + /* Trigger a verification of the trust credentials of a specific domain */ +-- +2.14.1 + diff --git a/0035-libwbclient-Fix-warning-statement-with-no-effect.patch b/0035-libwbclient-Fix-warning-statement-with-no-effect.patch new file mode 100644 index 0000000..288e22b --- /dev/null +++ b/0035-libwbclient-Fix-warning-statement-with-no-effect.patch @@ -0,0 +1,40 @@ +From aede6a1f4412f133e4b3fd76944f764d76fc4868 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 22 Aug 2017 16:50:23 +0200 +Subject: [PATCH 35/93] libwbclient: Fix warning statement with no effect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +src/sss_client/libwbclient/wbc_pam_sssd.c: In function ‘wbcAuthenticateUserEx’: +src/sss_client/libwbclient/wbc_pam_sssd.c:52:5: error: statement with no effect [-Werror=unused-value] + WBC_ERR_WINBIND_NOT_AVAILABLE; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +src/sss_client/libwbclient/wbc_pam_sssd.c:53:1: error: control reaches end of non-void function [-Werror=return-type] + } + ^ + +Related to: +https://pagure.io/SSSD/sssd/issue/3461 + +Reviewed-by: Sumit Bose +--- + src/sss_client/libwbclient/wbc_pam_sssd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sss_client/libwbclient/wbc_pam_sssd.c b/src/sss_client/libwbclient/wbc_pam_sssd.c +index fb269fd7ab1f6b27a9c9a9cb34381383611e76cc..77698f523e6e7aeb37d4db50b469d1604d7ee595 100644 +--- a/src/sss_client/libwbclient/wbc_pam_sssd.c ++++ b/src/sss_client/libwbclient/wbc_pam_sssd.c +@@ -49,7 +49,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, + *error = NULL; + } + +- WBC_ERR_WINBIND_NOT_AVAILABLE; ++ return WBC_ERR_WINBIND_NOT_AVAILABLE; + } + + /* Trigger a verification of the trust credentials of a specific domain */ +-- +2.14.1 + diff --git a/0036-ldap_child-Removing-duplicate-log-message.patch b/0036-ldap_child-Removing-duplicate-log-message.patch new file mode 100644 index 0000000..00b4285 --- /dev/null +++ b/0036-ldap_child-Removing-duplicate-log-message.patch @@ -0,0 +1,66 @@ +From 7aac90a357211379c71b33b5c97fa3dde306d047 Mon Sep 17 00:00:00 2001 +From: AmitKumar +Date: Mon, 21 Aug 2017 19:59:59 +0530 +Subject: [PATCH 36/93] ldap_child: Removing duplicate log message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Duplicate log messages were getting logged if trust relationship +breaks for some reason from AD. That causes lot spam in syslog. +This PR removes duplicate log entry and keeps extended log entry. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3450 + +Reviewed-by: Lukáš Slebodník +--- + src/providers/ldap/ldap_child.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index cfbfc5b7697332366f2a3f4813649a6dcba61b13..b796e5cae01517c85c2fc1605b1e5877454691dc 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -61,13 +61,6 @@ static void sig_term_handler(int sig) + static krb5_context krb5_error_ctx; + #define LDAP_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) + +-static const char *__ldap_child_krb5_error_msg; +-#define KRB5_SYSLOG(krb5_error) do { \ +- __ldap_child_krb5_error_msg = sss_krb5_get_error_message(krb5_error_ctx, krb5_error); \ +- sss_log(SSS_LOG_ERR, "%s", __ldap_child_krb5_error_msg); \ +- sss_krb5_free_error_message(krb5_error_ctx, __ldap_child_krb5_error_msg); \ +-} while(0) +- + struct input_buffer { + const char *realm_str; + const char *princ_str; +@@ -450,11 +443,6 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to init credentials: %s\n", + sss_krb5_get_error_message(context, krberr)); +- sss_log(SSS_LOG_ERR, +- "Failed to initialize credentials using keytab [%s]: %s. " +- "Unable to create GSSAPI-encrypted LDAP connection.", +- KEYTAB_CLEAN_NAME, +- sss_krb5_get_error_message(context, krberr)); + goto done; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n"); +@@ -527,7 +515,11 @@ done: + if (krberr != 0) { + const char *krb5_msg; + +- KRB5_SYSLOG(krberr); ++ sss_log(SSS_LOG_ERR, ++ "Failed to initialize credentials using keytab [%s]: %s. " ++ "Unable to create GSSAPI-encrypted LDAP connection.", ++ KEYTAB_CLEAN_NAME, ++ sss_krb5_get_error_message(context, krberr)); + krb5_msg = sss_krb5_get_error_message(context, krberr); + *_krb5_msg = talloc_strdup(memctx, krb5_msg); + sss_krb5_free_error_message(context, krb5_msg); +-- +2.14.1 + diff --git a/0037-IFP-fix-typo-in-option-name-in-man-pages.patch b/0037-IFP-fix-typo-in-option-name-in-man-pages.patch new file mode 100644 index 0000000..bef2791 --- /dev/null +++ b/0037-IFP-fix-typo-in-option-name-in-man-pages.patch @@ -0,0 +1,43 @@ +From ed7767aa1e3a9bc2027aa6f5f8bdc2c928e9958e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 25 Aug 2017 12:17:36 +0200 +Subject: [PATCH 37/93] IFP: fix typo in option name in man pages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd-ifp.5.xml | 2 +- + src/man/sssd-ldap.5.xml | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/man/sssd-ifp.5.xml b/src/man/sssd-ifp.5.xml +index da247f89dd2d9d08e0b1591d4c89f52197b278df..acb3e341eb046b1c4376d7f629536140ce596b21 100644 +--- a/src/man/sssd-ifp.5.xml ++++ b/src/man/sssd-ifp.5.xml +@@ -133,7 +133,7 @@ user_attributes = +telephoneNumber, -loginShell + + + +- wildcart_limit (integer) ++ wildcard_limit (integer) + + + Specifies an upper limit on the number of entries +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index a12f52797e67a3cca75ad7f6a10539ca08324d8f..3159fdde63da143017d90172a61b9a659dcda40c 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -2184,7 +2184,7 @@ ldap_access_filter = (employeeType=admin) + + + +- wildcart_limit (integer) ++ wildcard_limit (integer) + + + Specifies an upper limit on the number of entries +-- +2.14.1 + diff --git a/0038-IFP-Filter-with-in-infopipe-group-methods.patch b/0038-IFP-Filter-with-in-infopipe-group-methods.patch new file mode 100644 index 0000000..0db16c7 --- /dev/null +++ b/0038-IFP-Filter-with-in-infopipe-group-methods.patch @@ -0,0 +1,67 @@ +From 5fe1e8ba91a1e2e95aadf94ecc5148bec804aa5a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C4=8Cech?= +Date: Thu, 23 Mar 2017 09:17:55 +0100 +Subject: [PATCH 38/93] IFP: Filter with * in infopipe group methods +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch fixes asterisk in filter of the ListByName Groups' method, +which ends up calling ifp_groups_list_copy() with a NULL pointer. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3305 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifp_groups.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index f03c3e4b3720068db4c8266d65ea03a82a7beb62..def241f27241f415b91463dc214fa7791c2a6462 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -307,12 +307,14 @@ static void ifp_groups_list_by_name_done(struct tevent_req *req) + return; + } + +- ret = ifp_groups_list_copy(list_ctx, result->ldb_result); +- if (ret != EOK) { +- error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, +- "Failed to copy domain result"); +- sbus_request_fail_and_finish(sbus_req, error); +- return; ++ if (ret == EOK) { ++ ret = ifp_groups_list_copy(list_ctx, result->ldb_result); ++ if (ret != EOK) { ++ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, ++ "Failed to copy domain result"); ++ sbus_request_fail_and_finish(sbus_req, error); ++ return; ++ } + } + + list_ctx->dom = get_next_domain(list_ctx->dom, SSS_GND_DESCEND); +@@ -394,11 +396,13 @@ static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req) + goto done; + } + +- ret = ifp_groups_list_copy(list_ctx, result->ldb_result); +- if (ret != EOK) { +- error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, +- "Failed to copy domain result"); +- goto done; ++ if (ret == EOK) { ++ ret = ifp_groups_list_copy(list_ctx, result->ldb_result); ++ if (ret != EOK) { ++ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, ++ "Failed to copy domain result"); ++ goto done; ++ } + } + + done: +-- +2.14.1 + diff --git a/0039-IFP-Fix-of-limit-0-unlimited-result.patch b/0039-IFP-Fix-of-limit-0-unlimited-result.patch new file mode 100644 index 0000000..70c5315 --- /dev/null +++ b/0039-IFP-Fix-of-limit-0-unlimited-result.patch @@ -0,0 +1,45 @@ +From 3c31ce392ad9da4ac7c3d8190db89efcdbbc8b85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C4=8Cech?= +Date: Tue, 28 Mar 2017 12:07:55 +0200 +Subject: [PATCH 39/93] IFP: Fix of limit = 0 (unlimited result) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If we set limit to 0 it means that result is unlimited. Internally we +restrict number of result by allocation of result array. +In unlimited case there was a bug and zero array was allocated. +This fix allocates neccessary array when we know real result size. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3306 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifpsrv_util.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index 643881515fb4805ae93ba56c3bca9d1da7796319..33a49f4b4653af3b2e4e8bc01f3ec2397095e880 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -386,6 +386,15 @@ size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, + { + size_t capacity = list_ctx->limit - list_ctx->path_count; + ++ if (list_ctx->limit == 0) { ++ list_ctx->paths = talloc_zero_array(list_ctx, const char *, entries); ++ if (list_ctx->paths == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); ++ return 0; ++ } ++ return entries; ++ } ++ + if (capacity < entries) { + DEBUG(SSSDBG_MINOR_FAILURE, + "IFP list request has limit of %"PRIu32" entries but back end " +-- +2.14.1 + diff --git a/0040-IFP-Change-ifp_list_ctx_remaining_capacity-return-ty.patch b/0040-IFP-Change-ifp_list_ctx_remaining_capacity-return-ty.patch new file mode 100644 index 0000000..d43fde5 --- /dev/null +++ b/0040-IFP-Change-ifp_list_ctx_remaining_capacity-return-ty.patch @@ -0,0 +1,181 @@ +From 5d855b5d546eb995023d80d61433bbe91888dbdf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 5 May 2017 10:38:41 +0200 +Subject: [PATCH 40/93] IFP: Change ifp_list_ctx_remaining_capacity() return + type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now ifp_list_ctx_remaining_capacity() returns an errno_t and receives +the count as an output parameter. It allows better handling and error +reporting in case something goes wrong internally in this function. + +Related: +https://pagure.io/SSSD/sssd/issue/3306 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifp_groups.c | 14 +++++++++++--- + src/responder/ifp/ifp_private.h | 5 +++-- + src/responder/ifp/ifp_users.c | 21 +++++++++++++++++---- + src/responder/ifp/ifpsrv_util.c | 22 ++++++++++++++++------ + 4 files changed, 47 insertions(+), 15 deletions(-) + +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index def241f27241f415b91463dc214fa7791c2a6462..7503254238eafdafbe2d90fbf7416587be49e1b7 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -87,8 +87,12 @@ static int ifp_groups_list_copy(struct ifp_list_ctx *list_ctx, + struct ldb_result *result) + { + size_t copy_count, i; ++ errno_t ret; + +- copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count); ++ ret = ifp_list_ctx_remaining_capacity(list_ctx, result->count, ©_count); ++ if (ret != EOK) { ++ goto done; ++ } + + for (i = 0; i < copy_count; i++) { + list_ctx->paths[list_ctx->path_count + i] = \ +@@ -96,12 +100,16 @@ static int ifp_groups_list_copy(struct ifp_list_ctx *list_ctx, + list_ctx->dom, + result->msgs[i]); + if (list_ctx->paths[list_ctx->path_count + i] == NULL) { +- return ENOMEM; ++ ret = ENOMEM; ++ goto done; + } + } + + list_ctx->path_count += copy_count; +- return EOK; ++ ret = EOK; ++ ++done: ++ return ret; + } + + static void ifp_groups_find_by_name_done(struct tevent_req *req); +diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h +index a6e5701b8d1ebb27af0c35fa3ebe0c6c00d16bd6..ed1b63ad69433094dd6e40a9ca5f16725e8e3371 100644 +--- a/src/responder/ifp/ifp_private.h ++++ b/src/responder/ifp/ifp_private.h +@@ -103,8 +103,9 @@ struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req, + const char *filter, + uint32_t limit); + +-size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, +- size_t entries); ++errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, ++ size_t entries, ++ size_t *_capacity); + + errno_t ifp_ldb_el_output_name(struct resp_ctx *rctx, + struct ldb_message *msg, +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index 90b947ed9ca345fbeba6772c90f898451a0868aa..86a1f43a2c6e7d785c9d34e350c71f242ff7182f 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -436,8 +436,12 @@ static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx, + struct ldb_result *result) + { + size_t copy_count, i; ++ errno_t ret; + +- copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count); ++ ret = ifp_list_ctx_remaining_capacity(list_ctx, result->count, ©_count); ++ if (ret != EOK) { ++ goto done; ++ } + + for (i = 0; i < copy_count; i++) { + list_ctx->paths[list_ctx->path_count + i] = \ +@@ -445,12 +449,16 @@ static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx, + list_ctx->dom, + result->msgs[i]); + if (list_ctx->paths[list_ctx->path_count + i] == NULL) { +- return ENOMEM; ++ ret = ENOMEM; ++ goto done; + } + } + + list_ctx->path_count += copy_count; +- return EOK; ++ ret = EOK; ++ ++done: ++ return ret; + } + + struct name_and_cert_ctx { +@@ -906,7 +914,12 @@ static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req) + goto done; + } + +- copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count); ++ ret = ifp_list_ctx_remaining_capacity(list_ctx, result->count, ©_count); ++ if (ret != EOK) { ++ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, ++ "Failed to get the list remaining capacity\n"); ++ goto done; ++ } + + for (i = 0; i < copy_count; i++) { + list_ctx->paths[i] = ifp_users_build_path_from_msg(list_ctx->paths, +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index 33a49f4b4653af3b2e4e8bc01f3ec2397095e880..6eea3354c0d07fe9605f5788f50524115de4b46c 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -381,28 +381,38 @@ struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req, + return list_ctx; + } + +-size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, +- size_t entries) ++errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, ++ size_t entries, ++ size_t *_capacity) + { + size_t capacity = list_ctx->limit - list_ctx->path_count; ++ errno_t ret; + + if (list_ctx->limit == 0) { + list_ctx->paths = talloc_zero_array(list_ctx, const char *, entries); + if (list_ctx->paths == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); +- return 0; ++ ret = ENOMEM; ++ goto done; + } +- return entries; ++ capacity = entries; ++ goto immediately; + } + + if (capacity < entries) { + DEBUG(SSSDBG_MINOR_FAILURE, + "IFP list request has limit of %"PRIu32" entries but back end " + "returned %zu entries\n", list_ctx->limit, entries); +- return capacity; + } else { +- return entries; ++ capacity = entries; + } ++ ++immediately: ++ *_capacity = capacity; ++ ret = EOK; ++ ++done: ++ return ret; + } + + errno_t ifp_ldb_el_output_name(struct resp_ctx *rctx, +-- +2.14.1 + diff --git a/0041-IFP-Don-t-pre-allocate-the-amount-of-entries-request.patch b/0041-IFP-Don-t-pre-allocate-the-amount-of-entries-request.patch new file mode 100644 index 0000000..ec3a6c8 --- /dev/null +++ b/0041-IFP-Don-t-pre-allocate-the-amount-of-entries-request.patch @@ -0,0 +1,75 @@ +From b0b9222f7dd62b19ec702afe295ec71624888e87 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 9 May 2017 13:08:55 +0200 +Subject: [PATCH 41/93] IFP: Don't pre-allocate the amount of entries requested +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By allocating the number of entries when actually copying the list we +can avoid situations where users request an enourmous amount of results +but the number of results got from the backend are just a few. + +With this new approach we end up allocating the whole list more +frequently but we avoid not returning valid results because the +requested number of enties is too big (note that if the amount of +results is too big as well, there's nothing much we can do). + +A simple reproducer for this issue can be the really extreme call: +$ dbus-send --system --print-reply --dest=org.freedesktop.sssd.infopipe \ + /org/freedesktop/sssd/infopipe/Users \ + org.freedesktop.sssd.infopipe.Users.ListByName string:"*" uint32:"-1" + +The example pasted above would try to allocate an array of MAX_UINT32 +size, which would fail directly. + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifpsrv_util.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index 6eea3354c0d07fe9605f5788f50524115de4b46c..1df646339526186e862dcd09cddd971b77c20a8b 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -372,7 +372,7 @@ struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req, + list_ctx->ctx = ctx; + list_ctx->dom = ctx->rctx->domains; + list_ctx->filter = filter; +- list_ctx->paths = talloc_zero_array(list_ctx, const char *, limit); ++ list_ctx->paths = talloc_zero_array(list_ctx, const char *, 1); + if (list_ctx->paths == NULL) { + talloc_free(list_ctx); + return NULL; +@@ -389,12 +389,6 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, + errno_t ret; + + if (list_ctx->limit == 0) { +- list_ctx->paths = talloc_zero_array(list_ctx, const char *, entries); +- if (list_ctx->paths == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); +- ret = ENOMEM; +- goto done; +- } + capacity = entries; + goto immediately; + } +@@ -408,6 +402,14 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx, + } + + immediately: ++ talloc_zfree(list_ctx->paths); ++ list_ctx->paths = talloc_zero_array(list_ctx, const char *, capacity); ++ if (list_ctx->paths == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ + *_capacity = capacity; + ret = EOK; + +-- +2.14.1 + diff --git a/0042-IPA_ACCESS-Remove-not-used-attribute.patch b/0042-IPA_ACCESS-Remove-not-used-attribute.patch new file mode 100644 index 0000000..d003f9c --- /dev/null +++ b/0042-IPA_ACCESS-Remove-not-used-attribute.patch @@ -0,0 +1,58 @@ +From 8a26d32bc9b71e85a42b7832891100a7249f92aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 11:45:54 +0200 +Subject: [PATCH 42/93] IPA_ACCESS: Remove not used attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +struct time_rules_ctx * is not used anywhere in in the access handler, +thus there's no need to store it. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 2 -- + src/providers/ipa/ipa_access.h | 1 - + 2 files changed, 3 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 9682613e92a3c86a26a714287a51c26d56c804f9..67838cd92f3a926139fccee262544fcb14a25e4d 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -90,7 +90,6 @@ struct ipa_fetch_hbac_state { + struct ipa_access_ctx *access_ctx; + struct sdap_id_op *sdap_op; + struct dp_option *ipa_options; +- struct time_rules_ctx *tr_ctx; + + struct sdap_search_base **search_bases; + +@@ -146,7 +145,6 @@ ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx, + state->access_ctx = access_ctx; + state->sdap_ctx = access_ctx->sdap_ctx; + state->ipa_options = access_ctx->ipa_options; +- state->tr_ctx = access_ctx->tr_ctx; + state->search_bases = access_ctx->hbac_search_bases; + + if (state->search_bases == NULL) { +diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h +index 1e30a89a0792b09eb59ed31e249a428ae7d5ee08..eb19fc43819ad67be2128457365e18a91dd15b4a 100644 +--- a/src/providers/ipa/ipa_access.h ++++ b/src/providers/ipa/ipa_access.h +@@ -35,7 +35,6 @@ enum ipa_access_mode { + struct ipa_access_ctx { + struct sdap_id_ctx *sdap_ctx; + struct dp_option *ipa_options; +- struct time_rules_ctx *tr_ctx; + time_t last_update; + struct sdap_access_ctx *sdap_access_ctx; + +-- +2.14.1 + diff --git a/0043-IPA-Make-ipa_hbac_sysdb_save-more-generic.patch b/0043-IPA-Make-ipa_hbac_sysdb_save-more-generic.patch new file mode 100644 index 0000000..fdbc97c --- /dev/null +++ b/0043-IPA-Make-ipa_hbac_sysdb_save-more-generic.patch @@ -0,0 +1,497 @@ +From 9a18f78f38e274f4906af6ef8e1a82d844fde4cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 12:40:59 +0200 +Subject: [PATCH 43/93] IPA: Make ipa_hbac_sysdb_save() more generic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Although there's no change in the ipa_hbac_sysdb_save() itself, its name +has been changed to ipa_common_entries_and_groups_sysdb_save() and its +been split out from HBAC related files and moved to the newly created +ipa_rules_common.[ch] files, which will also be used in the future for +new backend modules. + +ipa_rules_common.[ch] is not exactly the best name for those files, IMO, +but I really cannot come up with something better. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 2 + + src/providers/ipa/ipa_access.c | 37 +++++--- + src/providers/ipa/ipa_hbac_common.c | 134 ---------------------------- + src/providers/ipa/ipa_hbac_private.h | 7 -- + src/providers/ipa/ipa_rules_common.c | 163 +++++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_rules_common.h | 40 +++++++++ + 6 files changed, 230 insertions(+), 153 deletions(-) + create mode 100644 src/providers/ipa/ipa_rules_common.c + create mode 100644 src/providers/ipa/ipa_rules_common.h + +diff --git a/Makefile.am b/Makefile.am +index faa2fbabab1ac727edbb1b5bdcbbebebc4a9fbf2..161db198061f1a636b77721b42997158543be68d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3890,6 +3890,8 @@ libsss_ipa_la_SOURCES = \ + src/providers/ipa/ipa_hbac_services.c \ + src/providers/ipa/ipa_hbac_users.c \ + src/providers/ipa/ipa_hbac_common.c \ ++ src/providers/ipa/ipa_rules_common.c \ ++ src/providers/ipa/ipa_rules_common.h \ + src/providers/ipa/ipa_srv.c \ + src/providers/ipa/ipa_idmap.c \ + src/providers/ipa/ipa_dn.c \ +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 67838cd92f3a926139fccee262544fcb14a25e4d..262f146dae788a68a394cc44e3719f5e16ef5f03 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -32,6 +32,7 @@ + #include "providers/ipa/ipa_hosts.h" + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_hbac_rules.h" ++#include "providers/ipa/ipa_rules_common.h" + + /* External logging function for HBAC. */ + void hbac_debug_messages(const char *file, int line, +@@ -515,10 +516,15 @@ static errno_t ipa_save_hbac(struct sss_domain_info *domain, + in_transaction = true; + + /* Save the hosts */ +- ret = ipa_hbac_sysdb_save(domain, HBAC_HOSTS_SUBDIR, SYSDB_FQDN, +- state->host_count, state->hosts, +- HBAC_HOSTGROUPS_SUBDIR, SYSDB_NAME, +- state->hostgroup_count, state->hostgroups); ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ HBAC_HOSTS_SUBDIR, ++ SYSDB_FQDN, ++ state->host_count, ++ state->hosts, ++ HBAC_HOSTGROUPS_SUBDIR, ++ SYSDB_NAME, ++ state->hostgroup_count, ++ state->hostgroups); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts [%d]: %s\n", + ret, sss_strerror(ret)); +@@ -526,20 +532,27 @@ static errno_t ipa_save_hbac(struct sss_domain_info *domain, + } + + /* Save the services */ +- ret = ipa_hbac_sysdb_save(domain, HBAC_SERVICES_SUBDIR, IPA_CN, +- state->service_count, state->services, +- HBAC_SERVICEGROUPS_SUBDIR, IPA_CN, +- state->servicegroup_count, +- state->servicegroups); ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ HBAC_SERVICES_SUBDIR, ++ IPA_CN, ++ state->service_count, ++ state->services, ++ HBAC_SERVICEGROUPS_SUBDIR, ++ IPA_CN, ++ state->servicegroup_count, ++ state->servicegroups); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + /* Save the rules */ +- ret = ipa_hbac_sysdb_save(domain, HBAC_RULES_SUBDIR, IPA_UNIQUE_ID, +- state->rule_count, state->rules, +- NULL, NULL, 0, NULL); ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ HBAC_RULES_SUBDIR, ++ IPA_UNIQUE_ID, ++ state->rule_count, ++ state->rules, ++ NULL, NULL, 0, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Error saving rules [%d]: %s\n", + ret, sss_strerror(ret)); +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index ba677965a3eb68a54baf99b1875bca2acbb76c99..3866ee2385b262a137c1521ee78a277158777c1a 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -23,140 +23,6 @@ + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_common.h" + +-static errno_t +-ipa_hbac_save_list(struct sss_domain_info *domain, +- bool delete_subdir, const char *subdir, +- const char *naming_attribute, size_t count, +- struct sysdb_attrs **list) +-{ +- int ret; +- size_t c; +- struct ldb_dn *base_dn; +- const char *object_name; +- struct ldb_message_element *el; +- TALLOC_CTX *tmp_ctx; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n"); +- return ENOMEM; +- } +- +- if (delete_subdir) { +- base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, subdir); +- if (base_dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n"); +- goto done; +- } +- } +- +- for (c = 0; c < count; c++) { +- ret = sysdb_attrs_get_el(list[c], naming_attribute, &el); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n"); +- goto done; +- } +- if (el->num_values == 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, "[%s] not found.\n", naming_attribute); +- ret = EINVAL; +- goto done; +- } +- object_name = talloc_strndup(tmp_ctx, (const char *)el->values[0].data, +- el->values[0].length); +- if (object_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Object name: [%s].\n", object_name); +- +- ret = sysdb_store_custom(domain, object_name, subdir, list[c]); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_store_custom failed.\n"); +- goto done; +- } +- } +- +- ret = EOK; +- +-done: +- talloc_free(tmp_ctx); +- return ret; +-} +- +-errno_t +-ipa_hbac_sysdb_save(struct sss_domain_info *domain, +- const char *primary_subdir, const char *attr_name, +- size_t primary_count, struct sysdb_attrs **primary, +- const char *group_subdir, const char *groupattr_name, +- size_t group_count, struct sysdb_attrs **groups) +-{ +- errno_t ret, sret; +- bool in_transaction = false; +- +- if ((primary_count == 0 || primary == NULL) +- || (group_count > 0 && groups == NULL)) { +- /* There always has to be at least one +- * primary entry. +- */ +- return EINVAL; +- } +- +- /* Save the entries and groups to the cache */ +- ret = sysdb_transaction_start(domain->sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); +- goto done; +- }; +- in_transaction = true; +- +- /* First, save the specific entries */ +- ret = ipa_hbac_save_list(domain, true, primary_subdir, +- attr_name, primary_count, primary); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n", +- primary_subdir, ret, strerror(ret)); +- goto done; +- } +- +- /* Second, save the groups */ +- if (group_count > 0) { +- ret = ipa_hbac_save_list(domain, true, group_subdir, +- groupattr_name, group_count, groups); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n", +- group_subdir, ret, strerror(ret)); +- goto done; +- } +- } +- +- ret = sysdb_transaction_commit(domain->sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); +- goto done; +- } +- in_transaction = false; +- +-done: +- if (in_transaction) { +- sret = sysdb_transaction_cancel(domain->sysdb); +- if (sret != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel sysdb transaction\n"); +- } +- } +- +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Error [%d][%s]\n", ret, strerror(ret)); +- } +- return ret; +-} +- + errno_t + replace_attribute_name(const char *old_name, + const char *new_name, const size_t count, +diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h +index 8fc5dc6d03cc2373e32641a399157c900ec18107..ca0bd4710f40206a7c236f86ec7af01f266317fa 100644 +--- a/src/providers/ipa/ipa_hbac_private.h ++++ b/src/providers/ipa/ipa_hbac_private.h +@@ -65,13 +65,6 @@ + #define HBAC_SERVICEGROUPS_SUBDIR "hbac_servicegroups" + + /* From ipa_hbac_common.c */ +-errno_t +-ipa_hbac_sysdb_save(struct sss_domain_info *domain, +- const char *primary_subdir, const char *attr_name, +- size_t primary_count, struct sysdb_attrs **primary, +- const char *group_subdir, const char *groupattr_name, +- size_t group_count, struct sysdb_attrs **groups); +- + errno_t + replace_attribute_name(const char *old_name, + const char *new_name, const size_t count, +diff --git a/src/providers/ipa/ipa_rules_common.c b/src/providers/ipa/ipa_rules_common.c +new file mode 100644 +index 0000000000000000000000000000000000000000..056d04dd1b622284634995f21dc0f2f0087c7741 +--- /dev/null ++++ b/src/providers/ipa/ipa_rules_common.c +@@ -0,0 +1,163 @@ ++/* ++ SSSD ++ ++ Authors: ++ Stephen Gallagher ++ ++ Copyright (C) 2011 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "providers/ipa/ipa_rules_common.h" ++ ++static errno_t ++ipa_common_save_list(struct sss_domain_info *domain, ++ bool delete_subdir, ++ const char *subdir, ++ const char *naming_attribute, ++ size_t count, ++ struct sysdb_attrs **list) ++{ ++ int ret; ++ size_t c; ++ struct ldb_dn *base_dn; ++ const char *object_name; ++ struct ldb_message_element *el; ++ TALLOC_CTX *tmp_ctx; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n"); ++ return ENOMEM; ++ } ++ ++ if (delete_subdir) { ++ base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, subdir); ++ if (base_dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n"); ++ goto done; ++ } ++ } ++ ++ for (c = 0; c < count; c++) { ++ ret = sysdb_attrs_get_el(list[c], naming_attribute, &el); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n"); ++ goto done; ++ } ++ if (el->num_values == 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "[%s] not found.\n", naming_attribute); ++ ret = EINVAL; ++ goto done; ++ } ++ object_name = talloc_strndup(tmp_ctx, (const char *)el->values[0].data, ++ el->values[0].length); ++ if (object_name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Object name: [%s].\n", object_name); ++ ++ ret = sysdb_store_custom(domain, object_name, subdir, list[c]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_store_custom failed.\n"); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++ipa_common_entries_and_groups_sysdb_save(struct sss_domain_info *domain, ++ const char *primary_subdir, ++ const char *attr_name, ++ size_t primary_count, ++ struct sysdb_attrs **primary, ++ const char *group_subdir, ++ const char *groupattr_name, ++ size_t group_count, ++ struct sysdb_attrs **groups) ++{ ++ errno_t ret, sret; ++ bool in_transaction = false; ++ ++ if ((primary_count == 0 || primary == NULL) ++ || (group_count > 0 && groups == NULL)) { ++ /* There always has to be at least one ++ * primary entry. ++ */ ++ return EINVAL; ++ } ++ ++ /* Save the entries and groups to the cache */ ++ ret = sysdb_transaction_start(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); ++ goto done; ++ }; ++ in_transaction = true; ++ ++ /* First, save the specific entries */ ++ ret = ipa_common_save_list(domain, true, primary_subdir, ++ attr_name, primary_count, primary); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n", ++ primary_subdir, ret, strerror(ret)); ++ goto done; ++ } ++ ++ /* Second, save the groups */ ++ if (group_count > 0) { ++ ret = ipa_common_save_list(domain, true, group_subdir, ++ groupattr_name, group_count, groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not save %s. [%d][%s]\n", ++ group_subdir, ret, strerror(ret)); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ goto done; ++ } ++ in_transaction = false; ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(domain->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel sysdb transaction\n"); ++ } ++ } ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Error [%d][%s]\n", ret, strerror(ret)); ++ } ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +new file mode 100644 +index 0000000000000000000000000000000000000000..38a6ba3a51f1553483e43a0a2dd186077f5089d4 +--- /dev/null ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -0,0 +1,40 @@ ++/* ++ SSSD ++ ++ Authors: ++ Stephen Gallagher ++ ++ Copyright (C) 2011 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_RULES_COMMON_H_ ++#define IPA_RULES_COMMON_H_ ++ ++#include "providers/backend.h" ++ ++/* From ipa_rules_common.c */ ++errno_t ++ipa_common_entries_and_groups_sysdb_save(struct sss_domain_info *domain, ++ const char *primary_subdir, ++ const char *attr_name, ++ size_t primary_count, ++ struct sysdb_attrs **primary, ++ const char *group_subdir, ++ const char *groupattr_name, ++ size_t group_count, ++ struct sysdb_attrs **groups); ++ ++#endif /* IPA_RULES_COMMON_H_ */ +-- +2.14.1 + diff --git a/0044-IPA-Leave-only-HBAC-specific-defines-in-ipa_hbac_pri.patch b/0044-IPA-Leave-only-HBAC-specific-defines-in-ipa_hbac_pri.patch new file mode 100644 index 0000000..9151c57 --- /dev/null +++ b/0044-IPA-Leave-only-HBAC-specific-defines-in-ipa_hbac_pri.patch @@ -0,0 +1,162 @@ +From 21909d3b620d97e81dd946b959a47efe88d2b7d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 13:00:25 +0200 +Subject: [PATCH 44/93] IPA: Leave only HBAC specific defines in + ipa_hbac_private.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The defines that were moved can and will be used by another backend +module that will be introduced in the near future. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +Reviewed-by: Pavel Březina +--- + src/providers/ipa/ipa_hbac_common.c | 1 + + src/providers/ipa/ipa_hbac_hosts.c | 1 + + src/providers/ipa/ipa_hbac_private.h | 11 ----------- + src/providers/ipa/ipa_hbac_rules.c | 1 + + src/providers/ipa/ipa_hbac_services.c | 1 + + src/providers/ipa/ipa_hbac_users.c | 1 + + src/providers/ipa/ipa_rules_common.h | 12 ++++++++++++ + src/providers/ipa/ipa_selinux.c | 1 + + 8 files changed, 18 insertions(+), 11 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index 3866ee2385b262a137c1521ee78a277158777c1a..2dba314962bd76c669b1bdbb33f2bb1858fe43c1 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -22,6 +22,7 @@ + + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_common.h" ++#include "providers/ipa/ipa_rules_common.h" + + errno_t + replace_attribute_name(const char *old_name, +diff --git a/src/providers/ipa/ipa_hbac_hosts.c b/src/providers/ipa/ipa_hbac_hosts.c +index d331cdfabb489914658487734042086361c7e7b1..74d91e513cb93f936b7ca09149343cee9b7fda82 100644 +--- a/src/providers/ipa/ipa_hbac_hosts.c ++++ b/src/providers/ipa/ipa_hbac_hosts.c +@@ -23,6 +23,7 @@ + #include "util/util.h" + #include "db/sysdb.h" + #include "providers/ipa/ipa_hbac_private.h" ++#include "providers/ipa/ipa_rules_common.h" + #include "providers/ldap/sdap_async.h" + + /* +diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h +index ca0bd4710f40206a7c236f86ec7af01f266317fa..7d8b1ed2f82a5d4502a47f51ddd4f19171430688 100644 +--- a/src/providers/ipa/ipa_hbac_private.h ++++ b/src/providers/ipa/ipa_hbac_private.h +@@ -31,29 +31,18 @@ + #define IPA_HBAC_SERVICE "ipaHBACService" + #define IPA_HBAC_SERVICE_GROUP "ipaHBACServiceGroup" + +-#define IPA_UNIQUE_ID "ipauniqueid" +- + #define IPA_MEMBER "member" + #define HBAC_HOSTS_SUBDIR "hbac_hosts" + #define HBAC_HOSTGROUPS_SUBDIR "hbac_hostgroups" + +-#define OBJECTCLASS "objectclass" + #define IPA_MEMBEROF "memberOf" + #define IPA_ACCESS_RULE_TYPE "accessRuleType" + #define IPA_HBAC_ALLOW "allow" +-#define IPA_MEMBER_USER "memberUser" +-#define IPA_USER_CATEGORY "userCategory" + #define IPA_SERVICE_NAME "serviceName" + #define IPA_SOURCE_HOST "sourceHost" + #define IPA_SOURCE_HOST_CATEGORY "sourceHostCategory" +-#define IPA_EXTERNAL_HOST "externalHost" +-#define IPA_ENABLED_FLAG "ipaenabledflag" +-#define IPA_MEMBER_HOST "memberHost" +-#define IPA_HOST_CATEGORY "hostCategory" +-#define IPA_CN "cn" + #define IPA_MEMBER_SERVICE "memberService" + #define IPA_SERVICE_CATEGORY "serviceCategory" +-#define IPA_TRUE_VALUE "TRUE" + + #define IPA_HBAC_BASE_TMPL "cn=hbac,%s" + #define IPA_SERVICES_BASE_TMPL "cn=hbacservices,cn=accounts,%s" +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index 7912dbec98f9f4bb5e4c9a64d709196c53e7512b..c860905cc5544100be22ef74379895b3adb94173 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -21,6 +21,7 @@ + */ + + #include "util/util.h" ++#include "providers/ipa/ipa_rules_common.h" + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_hbac_rules.h" + #include "providers/ldap/sdap_async.h" +diff --git a/src/providers/ipa/ipa_hbac_services.c b/src/providers/ipa/ipa_hbac_services.c +index cf8ce84bf54f2d22bd5cd19d88e647889742a41e..79088ff66d72a9ca575dc8ee9b8d35070526a927 100644 +--- a/src/providers/ipa/ipa_hbac_services.c ++++ b/src/providers/ipa/ipa_hbac_services.c +@@ -21,6 +21,7 @@ + */ + + #include "util/util.h" ++#include "providers/ipa/ipa_rules_common.h" + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ldap/sdap_async.h" + +diff --git a/src/providers/ipa/ipa_hbac_users.c b/src/providers/ipa/ipa_hbac_users.c +index 0881647c25f96008c16d00896d8a4564baaf4a03..af53fa035323a87e4bbaa807db503aab34112e3e 100644 +--- a/src/providers/ipa/ipa_hbac_users.c ++++ b/src/providers/ipa/ipa_hbac_users.c +@@ -21,6 +21,7 @@ + */ + + #include "util/util.h" ++#include "providers/ipa/ipa_rules_common.h" + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ldap/sdap_async.h" + +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +index 38a6ba3a51f1553483e43a0a2dd186077f5089d4..b5e05b039836902ac4ce0bc61b0fbc98648db974 100644 +--- a/src/providers/ipa/ipa_rules_common.h ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -25,6 +25,18 @@ + + #include "providers/backend.h" + ++#define IPA_UNIQUE_ID "ipauniqueid" ++ ++#define OBJECTCLASS "objectclass" ++#define IPA_MEMBER_USER "memberUser" ++#define IPA_USER_CATEGORY "userCategory" ++#define IPA_EXTERNAL_HOST "externalHost" ++#define IPA_ENABLED_FLAG "ipaenabledflag" ++#define IPA_MEMBER_HOST "memberHost" ++#define IPA_HOST_CATEGORY "hostCategory" ++#define IPA_CN "cn" ++#define IPA_TRUE_VALUE "TRUE" ++ + /* From ipa_rules_common.c */ + errno_t + ipa_common_entries_and_groups_sysdb_save(struct sss_domain_info *domain, +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index 6d0778d7817762dc6f314b8ed72ff292486dffd7..e9cc33953ea4f10e1fb4cf0b2db3c2d15777b519 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -36,6 +36,7 @@ + #include "providers/ipa/ipa_access.h" + #include "providers/ipa/ipa_selinux_maps.h" + #include "providers/ipa/ipa_subdomains.h" ++#include "providers/ipa/ipa_rules_common.h" + + #ifndef SELINUX_CHILD_DIR + #ifndef SSSD_LIBEXEC_PATH +-- +2.14.1 + diff --git a/0045-IPA_ACCESS-Make-hbac_get_cache_rules-more-generic.patch b/0045-IPA_ACCESS-Make-hbac_get_cache_rules-more-generic.patch new file mode 100644 index 0000000..8082fc9 --- /dev/null +++ b/0045-IPA_ACCESS-Make-hbac_get_cache_rules-more-generic.patch @@ -0,0 +1,360 @@ +From e17e37cd0e2109e7f1bd4ae48edfc8cca85b3f93 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 13:49:48 +0200 +Subject: [PATCH 45/93] IPA_ACCESS: Make hbac_get_cache_rules() more generic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This method can also be reused in the future for new backend modules. + +In order to make it more generic, let's just move it to +ipa_rules_common.[ch], rename it to ipa_common_get_cached_rules() and +make the rule, subtree name and the attributes to be searched new +parameters of this method. + +In order to not be declaring the enourmous list of attributes HBAC uses +when calling this method, a new hbac_get_attrs_to_get_cached_rules() +method has been introduced. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +Reviewed-by: Pavel Březina +--- + src/providers/ipa/ipa_access.c | 77 ++++++------------------------------ + src/providers/ipa/ipa_access.h | 5 --- + src/providers/ipa/ipa_hbac_common.c | 30 ++++++++++++++ + src/providers/ipa/ipa_hbac_private.h | 3 ++ + src/providers/ipa/ipa_rules_common.c | 61 ++++++++++++++++++++++++++++ + src/providers/ipa/ipa_rules_common.h | 9 +++++ + src/providers/ipa/ipa_selinux.c | 33 ++++++++++++---- + 7 files changed, 141 insertions(+), 77 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 262f146dae788a68a394cc44e3719f5e16ef5f03..58c4992e0381f443d942c9c8a63216587de5ac1d 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -591,6 +591,7 @@ errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx, + struct hbac_eval_req *eval_req; + enum hbac_eval_result result; + struct hbac_info *info = NULL; ++ const char **attrs_get_cached_rules; + errno_t ret; + + tmp_ctx = talloc_new(NULL); +@@ -603,8 +604,17 @@ errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx, + hbac_ctx.pd = pd; + + /* Get HBAC rules from the sysdb */ +- ret = hbac_get_cached_rules(tmp_ctx, be_ctx->domain, +- &hbac_ctx.rule_count, &hbac_ctx.rules); ++ attrs_get_cached_rules = hbac_get_attrs_to_get_cached_rules(tmp_ctx); ++ if (attrs_get_cached_rules == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "hbac_get_attrs_to_get_cached_rules() failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ipa_common_get_cached_rules(tmp_ctx, be_ctx->domain, ++ IPA_HBAC_RULE, HBAC_RULES_SUBDIR, ++ attrs_get_cached_rules, ++ &hbac_ctx.rule_count, &hbac_ctx.rules); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve rules from the cache\n"); + goto done; +@@ -649,69 +659,6 @@ done: + return ret; + } + +-errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- size_t *_rule_count, +- struct sysdb_attrs ***_rules) +-{ +- errno_t ret; +- struct ldb_message **msgs; +- struct sysdb_attrs **rules; +- size_t rule_count; +- TALLOC_CTX *tmp_ctx; +- char *filter; +- const char *attrs[] = { OBJECTCLASS, +- IPA_CN, +- SYSDB_ORIG_DN, +- IPA_UNIQUE_ID, +- IPA_ENABLED_FLAG, +- IPA_ACCESS_RULE_TYPE, +- IPA_MEMBER_USER, +- IPA_USER_CATEGORY, +- IPA_MEMBER_SERVICE, +- IPA_SERVICE_CATEGORY, +- IPA_SOURCE_HOST, +- IPA_SOURCE_HOST_CATEGORY, +- IPA_EXTERNAL_HOST, +- IPA_MEMBER_HOST, +- IPA_HOST_CATEGORY, +- NULL }; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) return ENOMEM; +- +- filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE); +- if (filter == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_search_custom(tmp_ctx, domain, filter, +- HBAC_RULES_SUBDIR, attrs, +- &rule_count, &msgs); +- if (ret != EOK && ret != ENOENT) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n"); +- goto done; +- } if (ret == ENOENT) { +- rule_count = 0; +- } +- +- ret = sysdb_msg2attrs(tmp_ctx, rule_count, msgs, &rules); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Could not convert ldb message to sysdb_attrs\n"); +- goto done; +- } +- +- if (_rules) *_rules = talloc_steal(mem_ctx, rules); +- if (_rule_count) *_rule_count = rule_count; +- +- ret = EOK; +-done: +- talloc_free(tmp_ctx); +- return ret; +-} +- + struct ipa_pam_access_handler_state { + struct tevent_context *ev; + struct be_ctx *be_ctx; +diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h +index eb19fc43819ad67be2128457365e18a91dd15b4a..de690350218bd47165a2b48c10059b8de96b718a 100644 +--- a/src/providers/ipa/ipa_access.h ++++ b/src/providers/ipa/ipa_access.h +@@ -63,9 +63,4 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); + +-errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- size_t *_rule_count, +- struct sysdb_attrs ***_rules); +- + #endif /* _IPA_ACCESS_H_ */ +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index 2dba314962bd76c669b1bdbb33f2bb1858fe43c1..9414419122a201c00dccf65e6ee88a0bcaa38477 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -716,3 +716,33 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++const char ** ++hbac_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx) ++{ ++ const char **attrs = talloc_zero_array(mem_ctx, const char *, 16); ++ if (attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array() failed\n"); ++ goto done; ++ } ++ ++ attrs[0] = OBJECTCLASS; ++ attrs[1] = IPA_CN; ++ attrs[2] = SYSDB_ORIG_DN; ++ attrs[3] = IPA_UNIQUE_ID; ++ attrs[4] = IPA_ENABLED_FLAG; ++ attrs[5] = IPA_ACCESS_RULE_TYPE; ++ attrs[6] = IPA_MEMBER_USER; ++ attrs[7] = IPA_USER_CATEGORY; ++ attrs[8] = IPA_MEMBER_SERVICE; ++ attrs[9] = IPA_SERVICE_CATEGORY; ++ attrs[10] = IPA_SOURCE_HOST; ++ attrs[11] = IPA_SOURCE_HOST_CATEGORY; ++ attrs[12] = IPA_EXTERNAL_HOST; ++ attrs[13] = IPA_MEMBER_HOST; ++ attrs[14] = IPA_HOST_CATEGORY; ++ attrs[15] = NULL; ++ ++done: ++ return attrs; ++} +diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h +index 7d8b1ed2f82a5d4502a47f51ddd4f19171430688..b11814b83cc7498476d8624b3b2e298437738299 100644 +--- a/src/providers/ipa/ipa_hbac_private.h ++++ b/src/providers/ipa/ipa_hbac_private.h +@@ -89,6 +89,9 @@ get_ipa_hostgroupname(TALLOC_CTX *mem_ctx, + const char *host_dn, + char **hostgroupname); + ++const char ** ++hbac_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx); ++ + /* From ipa_hbac_services.c */ + struct tevent_req * + ipa_hbac_service_info_send(TALLOC_CTX *mem_ctx, +diff --git a/src/providers/ipa/ipa_rules_common.c b/src/providers/ipa/ipa_rules_common.c +index 056d04dd1b622284634995f21dc0f2f0087c7741..6964e93fb338fd17916a7130eea55b98974837ec 100644 +--- a/src/providers/ipa/ipa_rules_common.c ++++ b/src/providers/ipa/ipa_rules_common.c +@@ -161,3 +161,64 @@ done: + } + return ret; + } ++ ++errno_t ++ipa_common_get_cached_rules(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *rule, ++ const char *subtree_name, ++ const char **attrs, ++ size_t *_rule_count, ++ struct sysdb_attrs ***_rules) ++{ ++ errno_t ret; ++ struct ldb_message **msgs; ++ struct sysdb_attrs **rules; ++ size_t rule_count; ++ TALLOC_CTX *tmp_ctx; ++ char *filter; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", rule); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_custom(tmp_ctx, domain, filter, ++ subtree_name, attrs, ++ &rule_count, &msgs); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n"); ++ goto done; ++ } ++ ++ if (ret == ENOENT) { ++ rule_count = 0; ++ } ++ ++ ret = sysdb_msg2attrs(tmp_ctx, rule_count, msgs, &rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Could not convert ldb message to sysdb_attrs\n"); ++ goto done; ++ } ++ ++ if (_rules) { ++ *_rules = talloc_steal(mem_ctx, rules); ++ } ++ ++ if (_rule_count) { ++ *_rule_count = rule_count; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +index b5e05b039836902ac4ce0bc61b0fbc98648db974..9ccff7f71c73417cf9c3897d202009c54dc471d4 100644 +--- a/src/providers/ipa/ipa_rules_common.h ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -49,4 +49,13 @@ ipa_common_entries_and_groups_sysdb_save(struct sss_domain_info *domain, + size_t group_count, + struct sysdb_attrs **groups); + ++errno_t ++ipa_common_get_cached_rules(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *rule, ++ const char *subtree_name, ++ const char **attrs, ++ size_t *_rule_count, ++ struct sysdb_attrs ***_rules); ++ + #endif /* IPA_RULES_COMMON_H_ */ +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index e9cc33953ea4f10e1fb4cf0b2db3c2d15777b519..2c61bac374ab52c765d78ae7034299c49d91f80f 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -1009,6 +1009,7 @@ ipa_get_selinux_maps_offline(struct tevent_req *req) + SYSDB_SELINUX_SEEALSO, + SYSDB_SELINUX_USER, + NULL }; ++ const char **attrs_get_cached_rules; + const char *default_user; + const char *order; + +@@ -1066,10 +1067,20 @@ ipa_get_selinux_maps_offline(struct tevent_req *req) + state->nmaps = nmaps; + + /* read all the HBAC rules */ +- ret = hbac_get_cached_rules(state, state->be_ctx->domain, +- &state->hbac_rule_count, &state->hbac_rules); ++ attrs_get_cached_rules = hbac_get_attrs_to_get_cached_rules(state); ++ if (attrs_get_cached_rules == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "hbac_get_attrs_to_get_cached_rules() failed\n"); ++ return ENOMEM; ++ } ++ ++ ret = ipa_common_get_cached_rules(state, state->be_ctx->domain, ++ IPA_HBAC_RULE, HBAC_RULES_SUBDIR, ++ attrs_get_cached_rules, ++ &state->hbac_rule_count, ++ &state->hbac_rules); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "hbac_get_cached_rules failed [%d]: %s\n", ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_common_get_cached_rules failed [%d]: %s\n", + ret, strerror(ret)); + return ret; + } +@@ -1168,7 +1179,7 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq) + struct ipa_id_ctx *id_ctx; + struct dp_module *access_mod; + struct dp_module *selinux_mod; +- ++ const char **attrs_get_cached_rules; + const char *tmp_str; + bool check_hbac; + errno_t ret; +@@ -1208,9 +1219,17 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq) + access_mod = dp_target_module(state->be_ctx->provider, DPT_ACCESS); + selinux_mod = dp_target_module(state->be_ctx->provider, DPT_SELINUX); + if (access_mod == selinux_mod) { +- ret = hbac_get_cached_rules(state, state->be_ctx->domain, +- &state->hbac_rule_count, +- &state->hbac_rules); ++ attrs_get_cached_rules = hbac_get_attrs_to_get_cached_rules(state); ++ if (attrs_get_cached_rules == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ipa_common_get_cached_rules(state, state->be_ctx->domain, ++ IPA_HBAC_RULE, HBAC_RULES_SUBDIR, ++ attrs_get_cached_rules, ++ &state->hbac_rule_count, ++ &state->hbac_rules); + /* Terminates the request */ + goto done; + } +-- +2.14.1 + diff --git a/0046-IPA_ACCESS-Make-ipa_purge_hbac-more-generic.patch b/0046-IPA_ACCESS-Make-ipa_purge_hbac-more-generic.patch new file mode 100644 index 0000000..a1ffb65 --- /dev/null +++ b/0046-IPA_ACCESS-Make-ipa_purge_hbac-more-generic.patch @@ -0,0 +1,143 @@ +From d2a0b4a6a220bf9a58c7306c3f673891efc419eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 14:36:34 +0200 +Subject: [PATCH 46/93] IPA_ACCESS: Make ipa_purge_hbac() more generic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This mothod can also be reused in the future for new backend modules. + +In order to make it more generic, let's just move it to +ipa_rules_common.[ch], rename it to ipa_common_purge_rules() and make +the subtreename to be purged a new paramether of this method. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 35 ++--------------------------------- + src/providers/ipa/ipa_rules_common.c | 32 ++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_rules_common.h | 4 ++++ + 3 files changed, 38 insertions(+), 33 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 58c4992e0381f443d942c9c8a63216587de5ac1d..28d46fecfd8897e63cc4e5ead142f3aeff9f34c2 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -118,7 +118,6 @@ static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req); + static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_services_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq); +-static errno_t ipa_purge_hbac(struct sss_domain_info *domain); + static errno_t ipa_save_hbac(struct sss_domain_info *domain, + struct ipa_fetch_hbac_state *state); + +@@ -436,7 +435,8 @@ static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq) + + if (found == false) { + /* No rules were found that apply to this host. */ +- ret = ipa_purge_hbac(state->be_ctx->domain); ++ ret = ipa_common_purge_rules(state->be_ctx->domain, ++ HBAC_RULES_SUBDIR); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove HBAC rules\n"); + goto done; +@@ -470,37 +470,6 @@ static errno_t ipa_fetch_hbac_recv(struct tevent_req *req) + return EOK; + } + +-static errno_t ipa_purge_hbac(struct sss_domain_info *domain) +-{ +- TALLOC_CTX *tmp_ctx; +- struct ldb_dn *base_dn; +- errno_t ret; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- /* Delete any rules in the sysdb so offline logins are also denied. */ +- base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, HBAC_RULES_SUBDIR); +- if (base_dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n"); +- goto done; +- } +- +- ret = EOK; +- +-done: +- talloc_free(tmp_ctx); +- return ret; +-} +- + static errno_t ipa_save_hbac(struct sss_domain_info *domain, + struct ipa_fetch_hbac_state *state) + { +diff --git a/src/providers/ipa/ipa_rules_common.c b/src/providers/ipa/ipa_rules_common.c +index 6964e93fb338fd17916a7130eea55b98974837ec..971870c48ddb8f48a199d8fef7bd34204299743c 100644 +--- a/src/providers/ipa/ipa_rules_common.c ++++ b/src/providers/ipa/ipa_rules_common.c +@@ -222,3 +222,35 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++errno_t ++ipa_common_purge_rules(struct sss_domain_info *domain, ++ const char *subtree_name) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *base_dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, subtree_name); ++ if (base_dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n"); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +index 9ccff7f71c73417cf9c3897d202009c54dc471d4..7c62f453815657a22dab00131359161d877bc392 100644 +--- a/src/providers/ipa/ipa_rules_common.h ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -58,4 +58,8 @@ ipa_common_get_cached_rules(TALLOC_CTX *mem_ctx, + size_t *_rule_count, + struct sysdb_attrs ***_rules); + ++errno_t ++ipa_common_purge_rules(struct sss_domain_info *domain, ++ const char *subtree_name); ++ + #endif /* IPA_RULES_COMMON_H_ */ +-- +2.14.1 + diff --git a/0047-IPA_RULES_COMMON-Introduce-ipa_common_save_rules.patch b/0047-IPA_RULES_COMMON-Introduce-ipa_common_save_rules.patch new file mode 100644 index 0000000..940743a --- /dev/null +++ b/0047-IPA_RULES_COMMON-Introduce-ipa_common_save_rules.patch @@ -0,0 +1,311 @@ +From 0f623456437c96f50330fe0ff21afd9638d14e57 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 15:29:35 +0200 +Subject: [PATCH 47/93] IPA_RULES_COMMON: Introduce ipa_common_save_rules() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This method is kind of a replacement for ipa_save_hbac() one. + +While ipa_save_hbac() wasn't removed, its porpuse has been totally +changed. Now it just prepare the ground and calls +ipa_common_save_rules() which is a more generic function that can be +reused for new backend modules. + +In order to make the code cleaner a new structure has also been +introduced: struct ipa_common_entries; which contains the values that +will be used to save the entry and the entrygroup to sysdb. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 99 +++++++++++++++--------------------- + src/providers/ipa/ipa_rules_common.c | 90 ++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_rules_common.h | 18 +++++++ + 3 files changed, 148 insertions(+), 59 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 28d46fecfd8897e63cc4e5ead142f3aeff9f34c2..fe475a25f9fb5e6ce3bbc68b01e222939f0bfd56 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -118,7 +118,8 @@ static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req); + static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_services_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq); +-static errno_t ipa_save_hbac(struct sss_domain_info *domain, ++static errno_t ipa_save_hbac(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, + struct ipa_fetch_hbac_state *state); + + static struct tevent_req * +@@ -446,7 +447,7 @@ static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq) + goto done; + } + +- ret = ipa_save_hbac(state->be_ctx->domain, state); ++ ret = ipa_save_hbac(state, state->be_ctx->domain, state); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save HBAC rules\n"); + goto done; +@@ -470,83 +471,63 @@ static errno_t ipa_fetch_hbac_recv(struct tevent_req *req) + return EOK; + } + +-static errno_t ipa_save_hbac(struct sss_domain_info *domain, ++static errno_t ipa_save_hbac(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, + struct ipa_fetch_hbac_state *state) + { +- bool in_transaction = false; ++ struct ipa_common_entries *hosts; ++ struct ipa_common_entries *services; ++ struct ipa_common_entries *rules; + errno_t ret; +- errno_t sret; + +- ret = sysdb_transaction_start(domain->sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Could not start transaction\n"); ++ hosts = talloc_zero(mem_ctx, struct ipa_common_entries); ++ if (hosts == NULL) { ++ ret = ENOMEM; + goto done; + } +- in_transaction = true; + +- /* Save the hosts */ +- ret = ipa_common_entries_and_groups_sysdb_save(domain, +- HBAC_HOSTS_SUBDIR, +- SYSDB_FQDN, +- state->host_count, +- state->hosts, +- HBAC_HOSTGROUPS_SUBDIR, +- SYSDB_NAME, +- state->hostgroup_count, +- state->hostgroups); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts [%d]: %s\n", +- ret, sss_strerror(ret)); +- goto done; +- } ++ hosts->entry_subdir = HBAC_HOSTS_SUBDIR; ++ hosts->entry_count = state->host_count; ++ hosts->entries = state->hosts; ++ hosts->group_subdir = HBAC_HOSTGROUPS_SUBDIR; ++ hosts->group_count = state->hostgroup_count; ++ hosts->groups = state->hostgroups; + +- /* Save the services */ +- ret = ipa_common_entries_and_groups_sysdb_save(domain, +- HBAC_SERVICES_SUBDIR, +- IPA_CN, +- state->service_count, +- state->services, +- HBAC_SERVICEGROUPS_SUBDIR, +- IPA_CN, +- state->servicegroup_count, +- state->servicegroups); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services [%d]: %s\n", +- ret, sss_strerror(ret)); ++ services = talloc_zero(mem_ctx, struct ipa_common_entries); ++ if (services == NULL) { ++ ret = ENOMEM; + goto done; + } +- /* Save the rules */ +- ret = ipa_common_entries_and_groups_sysdb_save(domain, +- HBAC_RULES_SUBDIR, +- IPA_UNIQUE_ID, +- state->rule_count, +- state->rules, +- NULL, NULL, 0, NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Error saving rules [%d]: %s\n", +- ret, sss_strerror(ret)); ++ ++ services->entry_subdir = HBAC_SERVICES_SUBDIR; ++ services->entry_count = state->service_count; ++ services->entries = state->services; ++ services->group_subdir = HBAC_SERVICEGROUPS_SUBDIR; ++ services->group_count = state->servicegroup_count; ++ services->groups = state->servicegroups; ++ ++ rules = talloc_zero(mem_ctx, struct ipa_common_entries); ++ if (rules == NULL) { ++ ret = ENOMEM; + goto done; + } + +- ret = sysdb_transaction_commit(domain->sysdb); ++ rules->entry_subdir = HBAC_RULES_SUBDIR; ++ rules->entry_count = state->rule_count; ++ rules->entries = state->rules; ++ ++ ret = ipa_common_save_rules(domain, hosts, services, rules, ++ &state->access_ctx->last_update); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_common_save_rules() failed [%d]: [%s]\n", ++ ret, sss_strerror(ret)); + goto done; + } +- in_transaction = false; +- +- state->access_ctx->last_update = time(NULL); + + ret = EOK; + + done: +- if (in_transaction) { +- sret = sysdb_transaction_cancel(domain->sysdb); +- if (sret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); +- } +- } +- + return ret; + } + +diff --git a/src/providers/ipa/ipa_rules_common.c b/src/providers/ipa/ipa_rules_common.c +index 971870c48ddb8f48a199d8fef7bd34204299743c..9765bac1892c75b8d21ef3bb54032a53004fc04a 100644 +--- a/src/providers/ipa/ipa_rules_common.c ++++ b/src/providers/ipa/ipa_rules_common.c +@@ -254,3 +254,93 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++errno_t ipa_common_save_rules(struct sss_domain_info *domain, ++ struct ipa_common_entries *hosts, ++ struct ipa_common_entries *services, ++ struct ipa_common_entries *rules, ++ time_t *last_update) ++{ ++ bool in_transaction = false; ++ errno_t ret; ++ errno_t sret; ++ ++ ret = sysdb_transaction_start(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not start transaction\n"); ++ goto done; ++ } ++ in_transaction = true; ++ ++ /* Save the hosts */ ++ if (hosts != NULL) { ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ hosts->entry_subdir, ++ SYSDB_FQDN, ++ hosts->entry_count, ++ hosts->entries, ++ hosts->group_subdir, ++ SYSDB_NAME, ++ hosts->group_count, ++ hosts->groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ /* Save the services */ ++ if (services != NULL) { ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ services->entry_subdir, ++ IPA_CN, ++ services->entry_count, ++ services->entries, ++ services->group_subdir, ++ IPA_CN, ++ services->group_count, ++ services->groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ /* Save the rules */ ++ if (rules != NULL) { ++ ret = ipa_common_entries_and_groups_sysdb_save(domain, ++ rules->entry_subdir, ++ IPA_UNIQUE_ID, ++ rules->entry_count, ++ rules->entries, ++ NULL, NULL, 0, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error saving rules [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ goto done; ++ } ++ in_transaction = false; ++ ++ *last_update = time(NULL); ++ ++ ret = EOK; ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(domain->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); ++ } ++ } ++ ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +index 7c62f453815657a22dab00131359161d877bc392..7882ce21309d26a573345edd3d2baeabbe063235 100644 +--- a/src/providers/ipa/ipa_rules_common.h ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -38,6 +38,17 @@ + #define IPA_TRUE_VALUE "TRUE" + + /* From ipa_rules_common.c */ ++ ++struct ipa_common_entries { ++ const char *entry_subdir; ++ size_t entry_count; ++ struct sysdb_attrs **entries; ++ ++ const char *group_subdir; ++ size_t group_count; ++ struct sysdb_attrs **groups; ++}; ++ + errno_t + ipa_common_entries_and_groups_sysdb_save(struct sss_domain_info *domain, + const char *primary_subdir, +@@ -62,4 +73,11 @@ errno_t + ipa_common_purge_rules(struct sss_domain_info *domain, + const char *subtree_name); + ++errno_t ++ipa_common_save_rules(struct sss_domain_info *domain, ++ struct ipa_common_entries *hosts, ++ struct ipa_common_entries *services, ++ struct ipa_common_entries *rules, ++ time_t *last_update); ++ + #endif /* IPA_RULES_COMMON_H_ */ +-- +2.14.1 + diff --git a/0048-IPA_RULES_COMMON-Introduce-ipa_common_get_hostgroupn.patch b/0048-IPA_RULES_COMMON-Introduce-ipa_common_get_hostgroupn.patch new file mode 100644 index 0000000..4e3c1b0 --- /dev/null +++ b/0048-IPA_RULES_COMMON-Introduce-ipa_common_get_hostgroupn.patch @@ -0,0 +1,316 @@ +From ee164913f9c12a557044eb469f4498b9be9a8f50 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 7 Aug 2017 11:40:31 +0200 +Subject: [PATCH 48/93] IPA_RULES_COMMON: Introduce + ipa_common_get_hostgroupname() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By moving the get_ipa_hostgroupname() method from ipa_hbac_hosts.[ch] to +ipa_rules_common.[ch] it can be used by both HBAC and, in the future, +for new backend modules. + +The method got renamed to ipa_common_get_hostgroupname() and some coding +style changes have been made in order to match with what SSSD follows. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_common.c | 6 +- + src/providers/ipa/ipa_hbac_hosts.c | 109 ----------------------------------- + src/providers/ipa/ipa_hbac_private.h | 5 -- + src/providers/ipa/ipa_rules_common.c | 109 +++++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_rules_common.h | 6 ++ + 5 files changed, 118 insertions(+), 117 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index 9414419122a201c00dccf65e6ee88a0bcaa38477..31e53d24d4ff73489d2137ff3df3931b08e3e117 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -686,9 +686,9 @@ hbac_eval_host_element(TALLOC_CTX *mem_ctx, + } + + for (i = j = 0; i < el->num_values; i++) { +- ret = get_ipa_hostgroupname(tmp_ctx, domain->sysdb, +- (const char *)el->values[i].data, +- &name); ++ ret = ipa_common_get_hostgroupname(tmp_ctx, domain->sysdb, ++ (const char *)el->values[i].data, ++ &name); + if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) { + DEBUG(SSSDBG_MINOR_FAILURE, "Skipping malformed entry [%s]\n", + (const char *)el->values[i].data); +diff --git a/src/providers/ipa/ipa_hbac_hosts.c b/src/providers/ipa/ipa_hbac_hosts.c +index 74d91e513cb93f936b7ca09149343cee9b7fda82..f85ce533fae8efd995bc2c5cf6d6f7a1703fca52 100644 +--- a/src/providers/ipa/ipa_hbac_hosts.c ++++ b/src/providers/ipa/ipa_hbac_hosts.c +@@ -333,112 +333,3 @@ done: + talloc_free(tmp_ctx); + return ret; + } +- +-errno_t +-get_ipa_hostgroupname(TALLOC_CTX *mem_ctx, +- struct sysdb_ctx *sysdb, +- const char *host_dn, +- char **hostgroupname) +-{ +- errno_t ret; +- struct ldb_dn *dn; +- const char *rdn_name; +- const char *hostgroup_comp_name; +- const char *account_comp_name; +- const struct ldb_val *rdn_val; +- const struct ldb_val *hostgroup_comp_val; +- const struct ldb_val *account_comp_val; +- +- /* This is an IPA-specific hack. It may not +- * work for non-IPA servers and will need to +- * be changed if SSSD ever supports HBAC on +- * a non-IPA server. +- */ +- *hostgroupname = NULL; +- +- dn = ldb_dn_new(mem_ctx, sysdb_ctx_get_ldb(sysdb), host_dn); +- if (dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- if (!ldb_dn_validate(dn)) { +- ret = ERR_MALFORMED_ENTRY; +- goto done; +- } +- +- if (ldb_dn_get_comp_num(dn) < 4) { +- /* RDN, hostgroups, accounts, and at least one DC= */ +- /* If it's fewer, it's not a group DN */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- /* If the RDN name is 'cn' */ +- rdn_name = ldb_dn_get_rdn_name(dn); +- if (rdn_name == NULL) { +- /* Shouldn't happen if ldb_dn_validate() +- * passed, but we'll be careful. +- */ +- ret = ERR_MALFORMED_ENTRY; +- goto done; +- } +- +- if (strcasecmp("cn", rdn_name) != 0) { +- /* RDN has the wrong attribute name. +- * It's not a host. +- */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- /* and the second component is "cn=hostgroups" */ +- hostgroup_comp_name = ldb_dn_get_component_name(dn, 1); +- if (strcasecmp("cn", hostgroup_comp_name) != 0) { +- /* The second component name is not "cn" */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- hostgroup_comp_val = ldb_dn_get_component_val(dn, 1); +- if (strncasecmp("hostgroups", +- (const char *) hostgroup_comp_val->data, +- hostgroup_comp_val->length) != 0) { +- /* The second component value is not "hostgroups" */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- /* and the third component is "accounts" */ +- account_comp_name = ldb_dn_get_component_name(dn, 2); +- if (strcasecmp("cn", account_comp_name) != 0) { +- /* The third component name is not "cn" */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- account_comp_val = ldb_dn_get_component_val(dn, 2); +- if (strncasecmp("accounts", +- (const char *) account_comp_val->data, +- account_comp_val->length) != 0) { +- /* The third component value is not "accounts" */ +- ret = ERR_UNEXPECTED_ENTRY_TYPE; +- goto done; +- } +- +- /* Then the value of the RDN is the group name */ +- rdn_val = ldb_dn_get_rdn_val(dn); +- *hostgroupname = talloc_strndup(mem_ctx, +- (const char *)rdn_val->data, +- rdn_val->length); +- if (*hostgroupname == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = EOK; +- +-done: +- talloc_free(dn); +- return ret; +-} +diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h +index b11814b83cc7498476d8624b3b2e298437738299..8ca7d09c9a4a7b0c91c03d7cbc48ffd06ce25ed7 100644 +--- a/src/providers/ipa/ipa_hbac_private.h ++++ b/src/providers/ipa/ipa_hbac_private.h +@@ -83,11 +83,6 @@ hbac_shost_attrs_to_rule(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *rule_attrs, + bool support_srchost, + struct hbac_rule_element **source_hosts); +-errno_t +-get_ipa_hostgroupname(TALLOC_CTX *mem_ctx, +- struct sysdb_ctx *sysdb, +- const char *host_dn, +- char **hostgroupname); + + const char ** + hbac_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx); +diff --git a/src/providers/ipa/ipa_rules_common.c b/src/providers/ipa/ipa_rules_common.c +index 9765bac1892c75b8d21ef3bb54032a53004fc04a..11823476bb908bcf2f073e0697a54c6a119958c9 100644 +--- a/src/providers/ipa/ipa_rules_common.c ++++ b/src/providers/ipa/ipa_rules_common.c +@@ -344,3 +344,112 @@ done: + + return ret; + } ++ ++errno_t ++ipa_common_get_hostgroupname(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *host_dn, ++ char **_hostgroupname) ++{ ++ errno_t ret; ++ struct ldb_dn *dn; ++ const char *rdn_name; ++ const char *hostgroup_comp_name; ++ const char *account_comp_name; ++ const struct ldb_val *rdn_val; ++ const struct ldb_val *hostgroup_comp_val; ++ const struct ldb_val *account_comp_val; ++ ++ /* This is an IPA-specific hack. It may not ++ * work for non-IPA servers and will need to ++ * be changed if SSSD ever supports HBAC on ++ * a non-IPA server. ++ */ ++ *_hostgroupname = NULL; ++ ++ dn = ldb_dn_new(mem_ctx, sysdb_ctx_get_ldb(sysdb), host_dn); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (!ldb_dn_validate(dn)) { ++ ret = ERR_MALFORMED_ENTRY; ++ goto done; ++ } ++ ++ if (ldb_dn_get_comp_num(dn) < 4) { ++ /* RDN, hostgroups, accounts, and at least one DC= */ ++ /* If it's fewer, it's not a group DN */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ /* If the RDN name is 'cn' */ ++ rdn_name = ldb_dn_get_rdn_name(dn); ++ if (rdn_name == NULL) { ++ /* Shouldn't happen if ldb_dn_validate() ++ * passed, but we'll be careful. ++ */ ++ ret = ERR_MALFORMED_ENTRY; ++ goto done; ++ } ++ ++ if (strcasecmp("cn", rdn_name) != 0) { ++ /* RDN has the wrong attribute name. ++ * It's not a host. ++ */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ /* and the second component is "cn=hostgroups" */ ++ hostgroup_comp_name = ldb_dn_get_component_name(dn, 1); ++ if (strcasecmp("cn", hostgroup_comp_name) != 0) { ++ /* The second component name is not "cn" */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ hostgroup_comp_val = ldb_dn_get_component_val(dn, 1); ++ if (strncasecmp("hostgroups", ++ (const char *) hostgroup_comp_val->data, ++ hostgroup_comp_val->length) != 0) { ++ /* The second component value is not "hostgroups" */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ /* and the third component is "accounts" */ ++ account_comp_name = ldb_dn_get_component_name(dn, 2); ++ if (strcasecmp("cn", account_comp_name) != 0) { ++ /* The third component name is not "cn" */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ account_comp_val = ldb_dn_get_component_val(dn, 2); ++ if (strncasecmp("accounts", ++ (const char *) account_comp_val->data, ++ account_comp_val->length) != 0) { ++ /* The third component value is not "accounts" */ ++ ret = ERR_UNEXPECTED_ENTRY_TYPE; ++ goto done; ++ } ++ ++ /* Then the value of the RDN is the group name */ ++ rdn_val = ldb_dn_get_rdn_val(dn); ++ *_hostgroupname = talloc_strndup(mem_ctx, ++ (const char *)rdn_val->data, ++ rdn_val->length); ++ if (*_hostgroupname == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(dn); ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_rules_common.h b/src/providers/ipa/ipa_rules_common.h +index 7882ce21309d26a573345edd3d2baeabbe063235..6cf57eb29d8a522c5280d8df1e8d73c1e84c6eca 100644 +--- a/src/providers/ipa/ipa_rules_common.h ++++ b/src/providers/ipa/ipa_rules_common.h +@@ -80,4 +80,10 @@ ipa_common_save_rules(struct sss_domain_info *domain, + struct ipa_common_entries *rules, + time_t *last_update); + ++errno_t ++ipa_common_get_hostgroupname(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *host_dn, ++ char **_hostgroupname); ++ + #endif /* IPA_RULES_COMMON_H_ */ +-- +2.14.1 + diff --git a/0049-IPA_ACCESS-Make-use-of-struct-ipa_common_entries.patch b/0049-IPA_ACCESS-Make-use-of-struct-ipa_common_entries.patch new file mode 100644 index 0000000..e8fb6cb --- /dev/null +++ b/0049-IPA_ACCESS-Make-use-of-struct-ipa_common_entries.patch @@ -0,0 +1,225 @@ +From 18d898d9cb30f298b3a35dc1c1bace95ef4e0b3b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 10 Apr 2017 15:47:50 +0200 +Subject: [PATCH 49/93] IPA_ACCESS: Make use of struct ipa_common_entries +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Just by doing so ipa_save_hbac() can be completely removed. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 123 ++++++++++++++--------------------------- + 1 file changed, 41 insertions(+), 82 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index fe475a25f9fb5e6ce3bbc68b01e222939f0bfd56..36f05ed60eff7d6aadaa8ea0a5f4965cfbe5a4da 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -95,21 +95,14 @@ struct ipa_fetch_hbac_state { + struct sdap_search_base **search_bases; + + /* Hosts */ +- size_t host_count; +- struct sysdb_attrs **hosts; +- size_t hostgroup_count; +- struct sysdb_attrs **hostgroups; ++ struct ipa_common_entries *hosts; + struct sysdb_attrs *ipa_host; + + /* Rules */ +- size_t rule_count; +- struct sysdb_attrs **rules; ++ struct ipa_common_entries *rules; + + /* Services */ +- size_t service_count; +- struct sysdb_attrs **services; +- size_t servicegroup_count; +- struct sysdb_attrs **servicegroups; ++ struct ipa_common_entries *services; + }; + + static errno_t ipa_fetch_hbac_retry(struct tevent_req *req); +@@ -118,9 +111,6 @@ static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req); + static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_services_done(struct tevent_req *subreq); + static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq); +-static errno_t ipa_save_hbac(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct ipa_fetch_hbac_state *state); + + static struct tevent_req * + ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx, +@@ -147,6 +137,21 @@ ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx, + state->sdap_ctx = access_ctx->sdap_ctx; + state->ipa_options = access_ctx->ipa_options; + state->search_bases = access_ctx->hbac_search_bases; ++ state->hosts = talloc_zero(state, struct ipa_common_entries); ++ if (state->hosts == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ state->services = talloc_zero(state, struct ipa_common_entries); ++ if (state->hosts == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ state->rules = talloc_zero(state, struct ipa_common_entries); ++ if (state->rules == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } + + if (state->search_bases == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC search base found.\n"); +@@ -296,8 +301,12 @@ static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq) + state = tevent_req_data(req, struct ipa_fetch_hbac_state); + + ret = ipa_host_info_recv(subreq, state, +- &state->host_count, &state->hosts, +- &state->hostgroup_count, &state->hostgroups); ++ &state->hosts->entry_count, ++ &state->hosts->entries, ++ &state->hosts->group_count, ++ &state->hosts->groups); ++ state->hosts->entry_subdir = HBAC_HOSTS_SUBDIR; ++ state->hosts->group_subdir = HBAC_HOSTGROUPS_SUBDIR; + talloc_zfree(subreq); + if (ret != EOK) { + goto done; +@@ -338,8 +347,12 @@ static void ipa_fetch_hbac_services_done(struct tevent_req *subreq) + state = tevent_req_data(req, struct ipa_fetch_hbac_state); + + ret = ipa_hbac_service_info_recv(subreq, state, +- &state->service_count, &state->services, +- &state->servicegroup_count, &state->servicegroups); ++ &state->services->entry_count, ++ &state->services->entries, ++ &state->services->group_count, ++ &state->services->groups); ++ state->services->entry_subdir = HBAC_SERVICES_SUBDIR; ++ state->services->group_subdir = HBAC_SERVICEGROUPS_SUBDIR; + talloc_zfree(subreq); + if (ret != EOK) { + goto done; +@@ -355,15 +368,16 @@ static void ipa_fetch_hbac_services_done(struct tevent_req *subreq) + goto done; + } + +- for (i = 0; i < state->host_count; i++) { +- ret = sysdb_attrs_get_string(state->hosts[i], SYSDB_FQDN, &hostname); ++ for (i = 0; i < state->hosts->entry_count; i++) { ++ ret = sysdb_attrs_get_string(state->hosts->entries[i], SYSDB_FQDN, ++ &hostname); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n"); + goto done; + } + + if (strcasecmp(hostname, ipa_hostname) == 0) { +- state->ipa_host = state->hosts[i]; ++ state->ipa_host = state->hosts->entries[i]; + break; + } + } +@@ -409,7 +423,9 @@ static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq) + state = tevent_req_data(req, struct ipa_fetch_hbac_state); + + ret = ipa_hbac_rule_info_recv(subreq, state, +- &state->rule_count, &state->rules); ++ &state->rules->entry_count, ++ &state->rules->entries); ++ state->rules->entry_subdir = HBAC_RULES_SUBDIR; + talloc_zfree(subreq); + if (ret == ENOENT) { + /* Set ret to EOK so we can safely call sdap_id_op_done. */ +@@ -447,7 +463,10 @@ static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq) + goto done; + } + +- ret = ipa_save_hbac(state, state->be_ctx->domain, state); ++ ret = ipa_common_save_rules(state->be_ctx->domain, ++ state->hosts, state->services, state->rules, ++ &state->access_ctx->last_update); ++ + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save HBAC rules\n"); + goto done; +@@ -471,66 +490,6 @@ static errno_t ipa_fetch_hbac_recv(struct tevent_req *req) + return EOK; + } + +-static errno_t ipa_save_hbac(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct ipa_fetch_hbac_state *state) +-{ +- struct ipa_common_entries *hosts; +- struct ipa_common_entries *services; +- struct ipa_common_entries *rules; +- errno_t ret; +- +- hosts = talloc_zero(mem_ctx, struct ipa_common_entries); +- if (hosts == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- hosts->entry_subdir = HBAC_HOSTS_SUBDIR; +- hosts->entry_count = state->host_count; +- hosts->entries = state->hosts; +- hosts->group_subdir = HBAC_HOSTGROUPS_SUBDIR; +- hosts->group_count = state->hostgroup_count; +- hosts->groups = state->hostgroups; +- +- services = talloc_zero(mem_ctx, struct ipa_common_entries); +- if (services == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- services->entry_subdir = HBAC_SERVICES_SUBDIR; +- services->entry_count = state->service_count; +- services->entries = state->services; +- services->group_subdir = HBAC_SERVICEGROUPS_SUBDIR; +- services->group_count = state->servicegroup_count; +- services->groups = state->servicegroups; +- +- rules = talloc_zero(mem_ctx, struct ipa_common_entries); +- if (rules == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- rules->entry_subdir = HBAC_RULES_SUBDIR; +- rules->entry_count = state->rule_count; +- rules->entries = state->rules; +- +- ret = ipa_common_save_rules(domain, hosts, services, rules, +- &state->access_ctx->last_update); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "ipa_common_save_rules() failed [%d]: [%s]\n", +- ret, sss_strerror(ret)); +- goto done; +- } +- +- ret = EOK; +- +-done: +- return ret; +-} +- + errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx, + struct dp_option *ipa_options, + struct pam_data *pd) +-- +2.14.1 + diff --git a/0050-IPA_COMMON-Introduce-ipa_get_host_attrs.patch b/0050-IPA_COMMON-Introduce-ipa_get_host_attrs.patch new file mode 100644 index 0000000..7f6164d --- /dev/null +++ b/0050-IPA_COMMON-Introduce-ipa_get_host_attrs.patch @@ -0,0 +1,147 @@ +From 7c1d1393537dec95e09b83b607ce9d0e8f49584c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 18 Apr 2017 14:33:20 +0200 +Subject: [PATCH 50/93] IPA_COMMON: Introduce ipa_get_host_attrs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By adding this method it can reused in the future for new backend +modules. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 35 ++++++---------------------------- + src/providers/ipa/ipa_common.c | 43 ++++++++++++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_common.h | 6 ++++++ + 3 files changed, 55 insertions(+), 29 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 36f05ed60eff7d6aadaa8ea0a5f4965cfbe5a4da..32ccf541c9436b633e7724b2c44ee545810a7fb8 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -338,10 +338,7 @@ static void ipa_fetch_hbac_services_done(struct tevent_req *subreq) + { + struct ipa_fetch_hbac_state *state; + struct tevent_req *req; +- const char *ipa_hostname; +- const char *hostname; + errno_t ret; +- size_t i; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ipa_fetch_hbac_state); +@@ -359,32 +356,12 @@ static void ipa_fetch_hbac_services_done(struct tevent_req *subreq) + } + + /* Get the ipa_host attrs */ +- state->ipa_host = NULL; +- ipa_hostname = dp_opt_get_cstring(state->ipa_options, IPA_HOSTNAME); +- if (ipa_hostname == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Missing ipa_hostname, this should never happen.\n"); +- ret = EINVAL; +- goto done; +- } +- +- for (i = 0; i < state->hosts->entry_count; i++) { +- ret = sysdb_attrs_get_string(state->hosts->entries[i], SYSDB_FQDN, +- &hostname); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n"); +- goto done; +- } +- +- if (strcasecmp(hostname, ipa_hostname) == 0) { +- state->ipa_host = state->hosts->entries[i]; +- break; +- } +- } +- +- if (state->ipa_host == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n"); +- ret = EINVAL; ++ ret = ipa_get_host_attrs(state->ipa_options, ++ state->hosts->entry_count, ++ state->hosts->entries, ++ &state->ipa_host); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host.\n"); + goto done; + } + +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 657994508e0733e86ba474419380a0081c51ee6e..6b29f2fde31f3866bb62b5c03e47e6c24f837550 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -1194,3 +1194,46 @@ errno_t ipa_get_dyndns_options(struct be_ctx *be_ctx, + + return EOK; + } ++ ++errno_t ipa_get_host_attrs(struct dp_option *ipa_options, ++ size_t host_count, ++ struct sysdb_attrs **hosts, ++ struct sysdb_attrs **_ipa_host) ++{ ++ const char *ipa_hostname; ++ const char *hostname; ++ errno_t ret; ++ ++ *_ipa_host = NULL; ++ ipa_hostname = dp_opt_get_cstring(ipa_options, IPA_HOSTNAME); ++ if (ipa_hostname == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Missing ipa_hostname, this should never happen.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ for (size_t i = 0; i < host_count; i++) { ++ ret = sysdb_attrs_get_string(hosts[i], SYSDB_FQDN, &hostname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n"); ++ goto done; ++ } ++ ++ if (strcasecmp(hostname, ipa_hostname) == 0) { ++ *_ipa_host = hosts[i]; ++ break; ++ } ++ } ++ ++ if (*_ipa_host == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index add9df87692c732b3567eee5584e7698991c66ca..b1d90d3624b5bc6a126709e6bd6fb1fdbbaafad8 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -292,4 +292,10 @@ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, + + + struct krb5_ctx *ipa_init_get_krb5_auth_ctx(void *data); ++ ++errno_t ipa_get_host_attrs(struct dp_option *ipa_options, ++ size_t host_count, ++ struct sysdb_attrs **hosts, ++ struct sysdb_attrs **_ipa_host); ++ + #endif /* _IPA_COMMON_H_ */ +-- +2.14.1 + diff --git a/0051-UTIL-move-files-selinux-.c-under-util-directory.patch b/0051-UTIL-move-files-selinux-.c-under-util-directory.patch new file mode 100644 index 0000000..4c7cc30 --- /dev/null +++ b/0051-UTIL-move-files-selinux-.c-under-util-directory.patch @@ -0,0 +1,344 @@ +From 5b93634c7f0e34f69b4cf8fb9b2e77b9179024a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 2 Aug 2017 12:10:10 +0200 +Subject: [PATCH 51/93] UTIL: move {files,selinux}.c under util directory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +files.c has at least one function that will be re-used for the new +session provider that's about to be added. Also, a few other functions +may be added and files.c seems the right place for those. + +selinux.c has been moved together with files.c as the latter takes +advantage of some functions from the former and we do not want to always +link agains the tools code. + +The public functions from files.c got a "sss_" prefix and it has been +changed whenever they're used. + +Last but not least, all the places that included "tools/tools_util.h" +due to the functions on files.c had this include removed (as they were +already including "util/util.h". + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 8 ++++---- + src/tests/files-tests.c | 13 ++++++------- + src/tools/sssctl/sssctl_data.c | 3 +-- + src/tools/sssctl/sssctl_logs.c | 3 +-- + src/tools/tools_util.c | 5 ++--- + src/tools/tools_util.h | 17 ----------------- + src/{tools => util}/files.c | 22 +++++++++++----------- + src/{tools => util}/selinux.c | 0 + src/util/util.h | 19 +++++++++++++++++++ + 9 files changed, 44 insertions(+), 46 deletions(-) + rename src/{tools => util}/files.c (98%) + rename src/{tools => util}/selinux.c (100%) + +diff --git a/Makefile.am b/Makefile.am +index 161db198061f1a636b77721b42997158543be68d..c292c1317ae45ae73cc3e86eb464d72e77eaf1fe 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -583,8 +583,6 @@ SSSD_RESPONDER_OBJ = \ + SSSD_TOOLS_OBJ = \ + src/tools/sss_sync_ops.c \ + src/tools/tools_util.c \ +- src/tools/files.c \ +- src/tools/selinux.c \ + src/tools/common/sss_tools.c \ + src/tools/common/sss_process.c \ + src/confdb/confdb_setup.c \ +@@ -1052,6 +1050,8 @@ libsss_util_la_SOURCES = \ + src/util/become_user.c \ + src/util/util_watchdog.c \ + src/util/sss_ptr_hash.c \ ++ src/util/files.c \ ++ src/util/selinux.c \ + $(NULL) + libsss_util_la_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -2016,8 +2016,8 @@ files_tests_SOURCES = \ + src/tests/files-tests.c \ + src/util/check_and_open.c \ + src/util/atomic_io.c \ +- src/tools/selinux.c \ +- src/tools/files.c ++ src/util/selinux.c \ ++ src/util/files.c + files_tests_CFLAGS = \ + $(AM_CFLAGS) \ + $(CHECK_CFLAGS) +diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c +index e96a60af1817b5f7a2e99d8b09ebc91c1a52667b..9feb9274ace02dd977950b8de220ee1f1aa18e65 100644 +--- a/src/tests/files-tests.c ++++ b/src/tests/files-tests.c +@@ -32,7 +32,6 @@ + #include + + #include "config.h" +-#include "tools/tools_util.h" + #include "util/util.h" + #include "tests/common.h" + +@@ -144,7 +143,7 @@ START_TEST(test_remove_tree) + fail_if(ret == -1, "Cannot chdir\n"); + + /* and finally wipe it out.. */ +- ret = remove_tree(dir_path); ++ ret = sss_remove_tree(dir_path); + fail_unless(ret == EOK, "remove_tree failed\n"); + + /* check if really gone */ +@@ -193,7 +192,7 @@ START_TEST(test_remove_subtree) + fail_if(ret == -1, "Cannot chdir\n"); + + /* and finally wipe it out.. */ +- ret = remove_subtree(dir_path); ++ ret = sss_remove_subtree(dir_path); + fail_unless(ret == EOK, "remove_subtree failed\n"); + + /* check if really gone */ +@@ -240,7 +239,7 @@ START_TEST(test_simple_copy) + /* and finally copy.. */ + DEBUG(SSSDBG_FUNC_DATA, + "Will copy from '%s' to '%s'\n", dir_path, dst_path); +- ret = copy_tree(dir_path, dst_path, 0700, uid, gid); ++ ret = sss_copy_tree(dir_path, dst_path, 0700, uid, gid); + fail_unless(ret == EOK, "copy_tree failed\n"); + + /* check if really copied */ +@@ -284,7 +283,7 @@ START_TEST(test_copy_file) + /* Copy this file to a new file */ + DEBUG(SSSDBG_FUNC_DATA, + "Will copy from 'foo' to 'bar'\n"); +- ret = copy_file_secure(foo_path, bar_path, 0700, uid, gid, 0); ++ ret = sss_copy_file_secure(foo_path, bar_path, 0700, uid, gid, 0); + fail_unless(ret == EOK, "copy_file_secure failed\n"); + + /* check if really copied */ +@@ -326,7 +325,7 @@ START_TEST(test_copy_symlink) + /* and finally copy.. */ + DEBUG(SSSDBG_FUNC_DATA, + "Will copy from '%s' to '%s'\n", dir_path, dst_path); +- ret = copy_tree(dir_path, dst_path, 0700, uid, gid); ++ ret = sss_copy_tree(dir_path, dst_path, 0700, uid, gid); + fail_unless(ret == EOK, "copy_tree failed\n"); + + /* check if really copied */ +@@ -365,7 +364,7 @@ START_TEST(test_copy_node) + /* and finally copy.. */ + DEBUG(SSSDBG_FUNC_DATA, + "Will copy from '%s' to '%s'\n", dir_path, dst_path); +- ret = copy_tree(dir_path, dst_path, 0700, uid, gid); ++ ret = sss_copy_tree(dir_path, dst_path, 0700, uid, gid); + fail_unless(ret == EOK, "copy_tree failed\n"); + + /* check if really copied and without special files */ +diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c +index 29c5e676056ce4bd4abf579e14963680731e10a9..860c5df55094a44e23da683b6a6b3c92902f985b 100644 +--- a/src/tools/sssctl/sssctl_data.c ++++ b/src/tools/sssctl/sssctl_data.c +@@ -23,7 +23,6 @@ + + #include "util/util.h" + #include "db/sysdb.h" +-#include "tools/common/sss_tools.h" + #include "tools/common/sss_process.h" + #include "tools/sssctl/sssctl.h" + #include "tools/tools_util.h" +@@ -241,7 +240,7 @@ errno_t sssctl_cache_remove(struct sss_cmdline *cmdline, + } + + printf(_("Removing cache files...\n")); +- ret = remove_subtree(DB_PATH); ++ ret = sss_remove_subtree(DB_PATH); + if (ret != EOK) { + fprintf(stderr, _("Unable to remove cache files\n")); + return ret; +diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c +index 1aea54e36a8b566f20f352871c0950de1c038960..472a553d1700f097f856d64c036c6b4f646ede59 100644 +--- a/src/tools/sssctl/sssctl_logs.c ++++ b/src/tools/sssctl/sssctl_logs.c +@@ -23,7 +23,6 @@ + #include + + #include "util/util.h" +-#include "tools/common/sss_tools.h" + #include "tools/common/sss_process.h" + #include "tools/sssctl/sssctl.h" + #include "tools/tools_util.h" +@@ -57,7 +56,7 @@ errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, + + if (opts.delete) { + printf(_("Deleting log files...\n")); +- ret = remove_subtree(LOG_PATH); ++ ret = sss_remove_subtree(LOG_PATH); + if (ret != EOK) { + fprintf(stderr, _("Unable to remove log files\n")); + return ret; +diff --git a/src/tools/tools_util.c b/src/tools/tools_util.c +index 5e51a4089e48d44347d87ba1beec6fff9ca30748..87a17491d52649da8ec48d6147e161e59298beaa 100644 +--- a/src/tools/tools_util.c ++++ b/src/tools/tools_util.c +@@ -33,7 +33,6 @@ + #include "util/util.h" + #include "confdb/confdb.h" + #include "db/sysdb.h" +-#include "tools/tools_util.h" + #include "tools/sss_sync_ops.h" + + static int setup_db(struct tools_ctx *ctx) +@@ -414,7 +413,7 @@ int remove_homedir(TALLOC_CTX *mem_ctx, + } + + /* Remove the tree */ +- ret = remove_tree(homedir); ++ ret = sss_remove_tree(homedir); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot remove homedir %s: %d\n", + homedir, ret); +@@ -502,7 +501,7 @@ int create_homedir(const char *skeldir, + + selinux_file_context(homedir); + +- ret = copy_tree(skeldir, homedir, 0777 & ~default_umask, uid, gid); ++ ret = sss_copy_tree(skeldir, homedir, 0777 & ~default_umask, uid, gid); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot populate user's home directory: [%d][%s].\n", +diff --git a/src/tools/tools_util.h b/src/tools/tools_util.h +index 389c7b5c4563118ccb7fdc9448a0879638a35a0b..fcfd8a659c1c0c61d9afda72c7bbacb9c97dddfd 100644 +--- a/src/tools/tools_util.h ++++ b/src/tools/tools_util.h +@@ -111,21 +111,4 @@ errno_t sss_mc_refresh_group(const char *groupname); + errno_t sss_mc_refresh_grouplist(struct tools_ctx *tctx, + char **groupnames); + +-/* from files.c */ +-int remove_tree(const char *root); +-int remove_subtree(const char *root); +- +-int copy_tree(const char *src_root, const char *dst_root, +- mode_t mode_root, uid_t uid, gid_t gid); +-int +-copy_file_secure(const char *src, +- const char *dest, +- mode_t mode, +- uid_t uid, gid_t gid, +- bool force); +- +-/* from selinux.c */ +-int selinux_file_context(const char *dst_name); +-int reset_selinux_file_context(void); +- + #endif /* __TOOLS_UTIL_H__ */ +diff --git a/src/tools/files.c b/src/util/files.c +similarity index 98% +rename from src/tools/files.c +rename to src/util/files.c +index 9f4e7caa7257144702c417c39bc1643f0be8661a..5827b29d8b5cf13248514f693e859d42335069d9 100644 +--- a/src/tools/files.c ++++ b/src/util/files.c +@@ -65,7 +65,6 @@ + #include + + #include "util/util.h" +-#include "tools/tools_util.h" + + struct copy_ctx { + const char *src_orig; +@@ -140,7 +139,7 @@ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx, + dev_t parent_dev, + bool keep_root_dir); + +-int remove_tree(const char *root) ++int sss_remove_tree(const char *root) + { + TALLOC_CTX *tmp_ctx = NULL; + int ret; +@@ -155,7 +154,7 @@ int remove_tree(const char *root) + return ret; + } + +-int remove_subtree(const char *root) ++int sss_remove_subtree(const char *root) + { + TALLOC_CTX *tmp_ctx = NULL; + int ret; +@@ -489,11 +488,11 @@ done: + } + + int +-copy_file_secure(const char *src, +- const char *dest, +- mode_t mode, +- uid_t uid, gid_t gid, +- bool force) ++sss_copy_file_secure(const char *src, ++ const char *dest, ++ mode_t mode, ++ uid_t uid, gid_t gid, ++ bool force) + { + int ifd = -1; + int ofd = -1; +@@ -761,8 +760,10 @@ done: + * For several reasons, including the fact that we copy even special files + * (pipes, etc) from the skeleton directory, the skeldir needs to be trusted + */ +-int copy_tree(const char *src_root, const char *dst_root, +- mode_t mode_root, uid_t uid, gid_t gid) ++int sss_copy_tree(const char *src_root, ++ const char *dst_root, ++ mode_t mode_root, ++ uid_t uid, gid_t gid) + { + int ret = EOK; + struct copy_ctx *cctx = NULL; +@@ -806,4 +807,3 @@ fail: + talloc_free(cctx); + return ret; + } +- +diff --git a/src/tools/selinux.c b/src/util/selinux.c +similarity index 100% +rename from src/tools/selinux.c +rename to src/util/selinux.c +diff --git a/src/util/util.h b/src/util/util.h +index 9b64dead88f05f16b00e73d59b2af06dcd485ff7..80411ec91046b7dc7993b8d175fedebd2b70a79a 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -681,4 +681,23 @@ int sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl); + int setup_watchdog(struct tevent_context *ev, int interval); + void teardown_watchdog(void); + ++/* from files.c */ ++int sss_remove_tree(const char *root); ++int sss_remove_subtree(const char *root); ++ ++int sss_copy_tree(const char *src_root, ++ const char *dst_root, ++ mode_t mode_root, ++ uid_t uid, gid_t gid); ++ ++int sss_copy_file_secure(const char *src, ++ const char *dest, ++ mode_t mode, ++ uid_t uid, gid_t gid, ++ bool force); ++ ++/* from selinux.c */ ++int selinux_file_context(const char *dst_name); ++int reset_selinux_file_context(void); ++ + #endif /* __SSSD_UTIL_H__ */ +-- +2.14.1 + diff --git a/0052-UTIL-Add-sss_create_dir.patch b/0052-UTIL-Add-sss_create_dir.patch new file mode 100644 index 0000000..3041790 --- /dev/null +++ b/0052-UTIL-Add-sss_create_dir.patch @@ -0,0 +1,187 @@ +From 6f466e0a3d950d21bd750ef53cb93b75dc023f9e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 2 Aug 2017 14:00:03 +0200 +Subject: [PATCH 52/93] UTIL: Add sss_create_dir() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The newly added function helps us to create a new dir avoiding a +possible TUCTOU issue. + +It's going to be used by the new session provider code. + +A simple test for this new function has also been provided. + +Related: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/tests/files-tests.c | 37 ++++++++++++++++++++++++ + src/util/files.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/util.h | 5 ++++ + 3 files changed, 119 insertions(+) + +diff --git a/src/tests/files-tests.c b/src/tests/files-tests.c +index 9feb9274ace02dd977950b8de220ee1f1aa18e65..1ccf404b94dc5518308c54380117c1162dc85f22 100644 +--- a/src/tests/files-tests.c ++++ b/src/tests/files-tests.c +@@ -378,6 +378,42 @@ START_TEST(test_copy_node) + } + END_TEST + ++START_TEST(test_create_dir) ++{ ++ int ret; ++ char origpath[PATH_MAX+1]; ++ char *new_dir; ++ struct stat info; ++ ++ errno = 0; ++ ++ fail_unless(getcwd(origpath, PATH_MAX) == origpath, "Cannot getcwd\n"); ++ fail_unless(errno == 0, "Cannot getcwd\n"); ++ ++ /* create a dir */ ++ ret = sss_create_dir(dir_path, "testdir", S_IRUSR | S_IXUSR, uid, gid); ++ fail_unless(ret == EOK, "cannot create dir: %s", strerror(ret)); ++ ++ new_dir = talloc_asprintf(NULL, "%s/testdir", dir_path); ++ ret = stat(new_dir, &info); ++ fail_unless(ret == EOK, "failed to stat '%s'\n", new_dir); ++ ++ /* check the dir has been created */ ++ fail_unless(S_ISDIR(info.st_mode) != 0, "'%s' is not a dir.\n", new_dir); ++ ++ /* check the permissions are okay */ ++ fail_unless((info.st_mode & S_IRUSR) != 0, "Read permission is not set\n"); ++ fail_unless((info.st_mode & S_IWUSR) == 0, "Write permission is set\n"); ++ fail_unless((info.st_mode & S_IXUSR) != 0, "Exec permission is not set\n"); ++ ++ /* check the owner is okay */ ++ fail_unless(info.st_uid == uid, "Dir created with the wrong uid\n"); ++ fail_unless(info.st_gid == gid, "Dir created with the wrong gid\n"); ++ ++ talloc_free(new_dir); ++} ++END_TEST ++ + static Suite *files_suite(void) + { + Suite *s = suite_create("files_suite"); +@@ -393,6 +429,7 @@ static Suite *files_suite(void) + tcase_add_test(tc_files, test_copy_file); + tcase_add_test(tc_files, test_copy_symlink); + tcase_add_test(tc_files, test_copy_node); ++ tcase_add_test(tc_files, test_create_dir); + suite_add_tcase(s, tc_files); + + return s; +diff --git a/src/util/files.c b/src/util/files.c +index 5827b29d8b5cf13248514f693e859d42335069d9..33b21e2ea3bad854d5a8e831a84ad4d768b7f9c0 100644 +--- a/src/util/files.c ++++ b/src/util/files.c +@@ -807,3 +807,80 @@ fail: + talloc_free(cctx); + return ret; + } ++ ++int sss_create_dir(const char *parent_dir_path, ++ const char *dir_name, ++ mode_t mode, ++ uid_t uid, gid_t gid) ++{ ++ TALLOC_CTX *tmp_ctx; ++ char *dir_path; ++ int ret = EOK; ++ int parent_dir_fd = -1; ++ int dir_fd = -1; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ parent_dir_fd = sss_open_cloexec(parent_dir_path, O_RDONLY | O_DIRECTORY, ++ &ret); ++ if (parent_dir_fd == -1) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Cannot open() directory '%s' [%d]: %s\n", ++ parent_dir_path, ret, sss_strerror(ret)); ++ goto fail; ++ } ++ ++ dir_path = talloc_asprintf(tmp_ctx, "%s/%s", parent_dir_path, dir_name); ++ if (dir_path == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ errno = 0; ++ ret = mkdirat(parent_dir_fd, dir_name, mode); ++ if (ret == -1) { ++ if (errno == EEXIST) { ++ ret = EOK; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Directory '%s' already created!\n", dir_path); ++ } else { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Error reading '%s': %s\n", parent_dir_path, strerror(ret)); ++ goto fail; ++ } ++ } ++ ++ dir_fd = sss_open_cloexec(dir_path, O_RDONLY | O_DIRECTORY, &ret); ++ if (dir_fd == -1) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Cannot open() directory '%s' [%d]: %s\n", ++ dir_path, ret, sss_strerror(ret)); ++ goto fail; ++ } ++ ++ errno = 0; ++ ret = fchown(dir_fd, uid, gid); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to own the newly created directory '%s' [%d]: %s\n", ++ dir_path, ret, sss_strerror(ret)); ++ goto fail; ++ } ++ ++ ret = EOK; ++ ++fail: ++ if (parent_dir_fd != -1) { ++ close(parent_dir_fd); ++ } ++ if (dir_fd != -1) { ++ close(dir_fd); ++ } ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/util/util.h b/src/util/util.h +index 80411ec91046b7dc7993b8d175fedebd2b70a79a..3d8bfe4795e976294b565c0869e3b842cf318efd 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -696,6 +696,11 @@ int sss_copy_file_secure(const char *src, + uid_t uid, gid_t gid, + bool force); + ++int sss_create_dir(const char *parent_dir_path, ++ const char *dir_name, ++ mode_t mode, ++ uid_t uid, gid_t gid); ++ + /* from selinux.c */ + int selinux_file_context(const char *dst_name); + int reset_selinux_file_context(void); +-- +2.14.1 + diff --git a/0053-DESKPROFILE-Introduce-the-new-IPA-session-provider.patch b/0053-DESKPROFILE-Introduce-the-new-IPA-session-provider.patch new file mode 100644 index 0000000..86b6901 --- /dev/null +++ b/0053-DESKPROFILE-Introduce-the-new-IPA-session-provider.patch @@ -0,0 +1,3147 @@ +From f982039c75ec064894deb676ae53ee57de868590 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 2 Nov 2016 00:15:16 +0100 +Subject: [PATCH 53/93] DESKPROFILE: Introduce the new IPA session provider +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to provide FleetCommander[0] integration, a session provider +has been introduced for IPA. The design of this feature and more +technical details can be found at [1] and [2], which are the design +pages of both freeIPA and SSSD parts. + +As there's no way to test freeIPA integration with our upstream tests, +no test has been provided yet. + +Is also worth to mention that the name "deskprofile" has been chosen +instead of "fleetcmd" in order to match with the freeIPA plugin. It +means that, for consistence, all source files, directories created, +options added, functions prefixes and so on are following the choice +accordingly. + +[0]: https://wiki.gnome.org/Projects/FleetCommander +[1]: https://github.com/abbra/freeipa-desktop-profile/blob/master/plugin/Feature.mediawiki +[2]: https://docs.pagure.org/SSSD.sssd/design_pages/fleet_commander_integration.html + +Resolves: +https://pagure.io/SSSD/sssd/issue/2995 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 11 + + contrib/sssd.spec.in | 2 + + src/confdb/confdb.h | 1 + + src/config/SSSDConfig/__init__.py.in | 3 + + src/config/SSSDConfig/sssd_upgrade_config.py | 1 + + src/config/SSSDConfigTest.py | 3 + + src/config/cfg_rules.ini | 3 + + src/config/etc/sssd.api.conf | 1 + + src/config/etc/sssd.api.d/sssd-ipa.conf | 2 + + src/man/sssd-ipa.5.xml | 29 + + src/man/sssd.conf.5.xml | 24 + + src/providers/data_provider/dp.h | 2 + + src/providers/data_provider/dp_target_auth.c | 10 +- + src/providers/data_provider/dp_targets.c | 2 + + src/providers/ipa/ipa_common.c | 26 + + src/providers/ipa/ipa_common.h | 3 + + src/providers/ipa/ipa_deskprofile_config.c | 156 +++++ + src/providers/ipa/ipa_deskprofile_config.h | 45 ++ + src/providers/ipa/ipa_deskprofile_private.h | 50 ++ + src/providers/ipa/ipa_deskprofile_rules.c | 367 ++++++++++ + src/providers/ipa/ipa_deskprofile_rules.h | 43 ++ + src/providers/ipa/ipa_deskprofile_rules_util.c | 932 +++++++++++++++++++++++++ + src/providers/ipa/ipa_deskprofile_rules_util.h | 57 ++ + src/providers/ipa/ipa_init.c | 49 ++ + src/providers/ipa/ipa_opts.c | 2 + + src/providers/ipa/ipa_session.c | 833 ++++++++++++++++++++++ + src/providers/ipa/ipa_session.h | 52 ++ + src/responder/ifp/ifp_components.c | 3 +- + 28 files changed, 2709 insertions(+), 3 deletions(-) + create mode 100644 src/providers/ipa/ipa_deskprofile_config.c + create mode 100644 src/providers/ipa/ipa_deskprofile_config.h + create mode 100644 src/providers/ipa/ipa_deskprofile_private.h + create mode 100644 src/providers/ipa/ipa_deskprofile_rules.c + create mode 100644 src/providers/ipa/ipa_deskprofile_rules.h + create mode 100644 src/providers/ipa/ipa_deskprofile_rules_util.c + create mode 100644 src/providers/ipa/ipa_deskprofile_rules_util.h + create mode 100644 src/providers/ipa/ipa_session.c + create mode 100644 src/providers/ipa/ipa_session.h + +diff --git a/Makefile.am b/Makefile.am +index c292c1317ae45ae73cc3e86eb464d72e77eaf1fe..6cda729d381948d27fae702a557b5f3aab423683 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -88,6 +88,7 @@ polkitdir = @polkitdir@ + pamconfdir = $(sysconfdir)/pam.d + systemtap_tapdir = @tapset_dir@ + sssdkcmdatadir = $(datadir)/sssd-kcm ++deskprofilepath = $(sss_statedir)/deskprofile + + if HAVE_SYSTEMD_UNIT + ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated +@@ -801,6 +802,7 @@ dist_noinst_HEADERS = \ + src/providers/ipa/ipa_srv.h \ + src/providers/ipa/ipa_dn.h \ + src/providers/ipa/ipa_sudo.h \ ++ src/providers/ipa/ipa_session.h \ + src/providers/ad/ad_srv.h \ + src/providers/ad/ad_common.h \ + src/providers/ad/ad_pac.h \ +@@ -3892,6 +3894,14 @@ libsss_ipa_la_SOURCES = \ + src/providers/ipa/ipa_hbac_common.c \ + src/providers/ipa/ipa_rules_common.c \ + src/providers/ipa/ipa_rules_common.h \ ++ src/providers/ipa/ipa_session.c \ ++ src/providers/ipa/ipa_deskprofile_private.h \ ++ src/providers/ipa/ipa_deskprofile_config.c \ ++ src/providers/ipa/ipa_deskprofile_config.h \ ++ src/providers/ipa/ipa_deskprofile_rules.c \ ++ src/providers/ipa/ipa_deskprofile_rules.h \ ++ src/providers/ipa/ipa_deskprofile_rules_util.c \ ++ src/providers/ipa/ipa_deskprofile_rules_util.h \ + src/providers/ipa/ipa_srv.c \ + src/providers/ipa/ipa_idmap.c \ + src/providers/ipa/ipa_dn.c \ +@@ -4617,6 +4627,7 @@ SSSD_USER_DIRS = \ + $(DESTDIR)$(sssdconfdir)/conf.d \ + $(DESTDIR)$(sssddefaultconfdir) \ + $(DESTDIR)$(logpath) \ ++ $(DESTDIR)$(deskprofilepath) \ + $(NULL) + + installsssddirs:: +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 0b7a6115778a185eae78be0f5447e6d883be6eb9..942d57f8eae88eec477e1e344412f1a92404e0f0 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -156,6 +156,7 @@ Requires: python2-sssdconfig = %{version}-%{release} + %global pubconfpath %{sssdstatedir}/pubconf + %global gpocachepath %{sssdstatedir}/gpo_cache + %global secdbpath %{sssdstatedir}/secrets ++%global deskprofilepath %{sssdstatedir}/deskprofile + + ### Build Dependencies ### + +@@ -958,6 +959,7 @@ done + %if (0%{?with_secrets} == 1) + %attr(700,root,root) %dir %{secdbpath} + %endif ++%attr(700,root,root) %dir %{deskprofilepath} + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 66ecc041398fda973c0f30a47a3f5944c88d19c2..da725fb667afea6747d22d1d3a4315fb7a7bace2 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -183,6 +183,7 @@ + #define CONFDB_DOMAIN_SELINUX_PROVIDER "selinux_provider" + #define CONFDB_DOMAIN_HOSTID_PROVIDER "hostid_provider" + #define CONFDB_DOMAIN_SUBDOMAINS_PROVIDER "subdomains_provider" ++#define CONFDB_DOMAIN_SESSION_PROVIDER "session_provider" + #define CONFDB_DOMAIN_COMMAND "command" + #define CONFDB_DOMAIN_TIMEOUT "timeout" + #define CONFDB_DOMAIN_ATTR "cn" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index de757521cff58460049bb8c4873efaf6bf0b8d95..2a19b60a987c5f2c5c59ac2466f8f6821803e146 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -154,6 +154,7 @@ option_strings = { + 'autofs_provider' : _('Autofs provider'), + 'hostid_provider' : _('Host identity provider'), + 'selinux_provider' : _('SELinux provider'), ++ 'session_provider' : _('Session management provider'), + + # [domain] + 'domain_type' : _('Whether the domain is usable by the OS or by applications'), +@@ -217,6 +218,8 @@ option_strings = { + 'ipa_anchor_uuid': _("Attribute with the reference to the original object"), + 'ipa_user_override_object_class': _("Objectclass for user override objects"), + 'ipa_group_override_object_class': _("Objectclass for group override objects"), ++ 'ipa_deskprofile_search_base': _("Search base for Desktop Profile related objects"), ++ 'ipa_deskprofile_refresh': _("The amount of time in seconds between lookups of the Desktop Profile rules against the IPA server"), + + # [provider/ad] + 'ad_domain' : _('Active Directory domain'), +diff --git a/src/config/SSSDConfig/sssd_upgrade_config.py b/src/config/SSSDConfig/sssd_upgrade_config.py +index 767d06ddc18b16f1a1af65805516518f5a3f8ad6..d2d94b21e87920c76065462e4ccb10606c3aca93 100644 +--- a/src/config/SSSDConfig/sssd_upgrade_config.py ++++ b/src/config/SSSDConfig/sssd_upgrade_config.py +@@ -148,6 +148,7 @@ class SSSDConfigFile(SSSDChangeConf): + 'auth_provider' : 'auth-module', + 'access_provider' : 'access-module', + 'chpass_provider' : 'chpass-module', ++ 'session_provider' : 'session-module', + 'use_fully_qualified_names' : 'useFullyQualifiedNames', + 'store_legacy_passwords' : 'store-legacy-passwords', + } +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 5f3ff3958d033dded386850a8653db9872fe4718..d0e97f02beaf5695149702c5c029197634ab8923 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -616,6 +616,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'hostid_provider', + 'subdomains_provider', + 'selinux_provider', ++ 'session_provider', + 'realmd_tags', + 'subdomain_refresh_interval', + 'subdomain_inherit', +@@ -986,6 +987,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'hostid_provider', + 'subdomains_provider', + 'selinux_provider', ++ 'session_provider', + 'realmd_tags', + 'subdomain_refresh_interval', + 'subdomain_inherit', +@@ -1381,6 +1383,7 @@ class SSSDConfigTestSSSDConfig(unittest.TestCase): + 'id_provider', + 'auth_provider', + 'access_provider', ++ 'session_provider', + 'default_shell', + 'fallback_homedir', + 'cache_credentials', +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index cba59d2c3813f44b8ab85b4c246108232f9d8fd4..3ebd39e93cec6d1ddf547d7ebdb49884e637f8c7 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -330,6 +330,7 @@ option = autofs_provider + option = hostid_provider + option = subdomains_provider + option = selinux_provider ++option = session_provider + + # Options available to all domains + option = domain_type +@@ -438,6 +439,8 @@ option = ad_site + option = ipa_anchor_uuid + option = ipa_automount_location + option = ipa_backup_server ++option = ipa_deskprofile_refresh ++option = ipa_deskprofile_search_base + option = ipa_domain + option = ipa_dyndns_iface + option = ipa_dyndns_ttl +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 0d11771ae3df50ba9f380e44747a5385a224544d..9eb6aeb83bbc1989cec7465e6442a1bf7762d9d8 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -139,6 +139,7 @@ autofs_provider = str, None, false + hostid_provider = str, None, false + subdomains_provider = str, None, false + selinux_provider = str, None, false ++session_provider = str, None, false + + [domain] + # Options available to all domains +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index f36b568c3ea813db3f46fdd69059957f6373801e..8178b123e3b42cb92029db8b879d26f1fd16cf3e 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -3,6 +3,7 @@ ipa_domain = str, None, false + ipa_server = str, None, false + ipa_backup_server = str, None, false + ipa_hostname = str, None, false ++ipa_deskprofile_search_base = str, None, false + ipa_dyndns_update = bool, None, false + ipa_dyndns_ttl = int, None, false + ipa_dyndns_iface = str, None, false +@@ -193,6 +194,7 @@ ldap_autofs_search_base = str, None, false + [provider/ipa/chpass] + + [provider/ipa/session] ++ipa_deskprofile_refresh = int, None, false + ipa_host_object_class = str, None, false + ipa_host_name = str, None, false + ipa_host_fqdn = str, None, false +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index 5e7f8ff1a581cf206c9aec99ba8084e3de56a7e6..4d1c3c8a11dea956c31be690f5bdceea94252fd2 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -306,6 +306,19 @@ + + + ++ ++ ipa_deskprofile_search_base (string) ++ ++ ++ Optional. Use the given string as search base for ++ Desktop Profile related objects. ++ ++ ++ Default: Use base DN ++ ++ ++ ++ + + ipa_hbac_search_base (string) + +@@ -447,6 +460,22 @@ + + + ++ ++ ipa_deskprofile_refresh (integer) ++ ++ ++ The amount of time between lookups of the Desktop ++ Profile rules against the IPA server. This will ++ reduce the latency and load on the IPA server if ++ there are many desktop profiles requests made in a ++ short period. ++ ++ ++ Default: 5 (seconds) ++ ++ ++ ++ + + ipa_hbac_refresh (integer) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7b5abebbf68a832c3b0af9bcff9c535eca77778a..c26f4a3bac1f009d19d9a5a3a49ad7370ac72791 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2387,6 +2387,30 @@ pam_account_locked_message = Account locked, please contact help desk. + + + ++ ++ session_provider (string) ++ ++ ++ The provider which configures and manages user session ++ related tasks. The only user session task currently ++ provided is the integration with Fleet Commander, which ++ works only with IPA. ++ Supported session providers are: ++ ++ ++ ipa to allow performing user session ++ related tasks. ++ ++ ++ none does not perform any kind of user ++ session related tasks. ++ ++ ++ Default: id_provider is used if it ++ is set and can perform session related tasks. ++ ++ ++ + + + autofs_provider (string) +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index e80a6c3398784dfc176baeff2daf7203c52fc072..9cdbe5b3a56ba159f9a10df6e010e616e4aefcac 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -66,6 +66,7 @@ enum dp_targets { + DPT_SELINUX, + DPT_HOSTID, + DPT_SUBDOMAINS, ++ DPT_SESSION, + + DP_TARGET_SENTINEL + }; +@@ -80,6 +81,7 @@ enum dp_methods { + DPM_AUTOFS_HANDLER, + DPM_HOSTID_HANDLER, + DPM_DOMAINS_HANDLER, ++ DPM_SESSION_HANDLER, + + DP_METHOD_SENTINEL + }; +diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c +index 78c4cce7ee76e3e169a3aac48c11399bc3d05ce1..6bb3313b2de002466e5ca84464c962acd2412bfa 100644 +--- a/src/providers/data_provider/dp_target_auth.c ++++ b/src/providers/data_provider/dp_target_auth.c +@@ -126,9 +126,15 @@ static void choose_target(struct data_provider *provider, + name = "PAM Chpass 2nd"; + break; + case SSS_PAM_OPEN_SESSION: +- target = DP_TARGET_SENTINEL; +- method = DP_METHOD_SENTINEL; + name = "PAM Open Session"; ++ if (dp_method_enabled(provider, DPT_SESSION, DPM_SESSION_HANDLER)) { ++ target = DPT_SESSION; ++ method = DPM_SESSION_HANDLER; ++ break; ++ } ++ ++ target = DP_TARGET_SENTINEL; ++ method = DP_METHOD_SENTINEL; + pd->pam_status = PAM_SUCCESS; + break; + case SSS_PAM_SETCRED: +diff --git a/src/providers/data_provider/dp_targets.c b/src/providers/data_provider/dp_targets.c +index e2a45bbac969ca7b9b13729f26b8cded8ab7eebc..2dd15d80d7094aa760f8767588dc096d1482052b 100644 +--- a/src/providers/data_provider/dp_targets.c ++++ b/src/providers/data_provider/dp_targets.c +@@ -114,6 +114,8 @@ const char *dp_target_to_string(enum dp_targets target) + return "hostid"; + case DPT_SUBDOMAINS: + return "subdomains"; ++ case DPT_SESSION: ++ return "session"; + case DP_TARGET_SENTINEL: + return NULL; + } +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 6b29f2fde31f3866bb62b5c03e47e6c24f837550..6bb1e679c4b5abcb7bb74fa17cdbd296f6eaef59 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -152,6 +152,9 @@ static errno_t ipa_parse_search_base(TALLOC_CTX *mem_ctx, + case IPA_VIEWS_SEARCH_BASE: + class_name = "IPA_VIEWS"; + break; ++ case IPA_DESKPROFILE_SEARCH_BASE: ++ class_name = "IPA_DESKPROFILE"; ++ break; + default: + DEBUG(SSSDBG_CONF_SETTINGS, + "Unknown search base type: [%d]\n", class); +@@ -398,6 +401,29 @@ int ipa_get_id_options(struct ipa_options *ipa_opts, + &ipa_opts->selinux_search_bases); + if (ret != EOK) goto done; + ++ if (NULL == dp_opt_get_string(ipa_opts->basic, ++ IPA_DESKPROFILE_SEARCH_BASE)) { ++ value = talloc_asprintf(tmpctx, "cn=desktop-profile,%s", basedn); ++ if (!value) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = dp_opt_set_string(ipa_opts->basic, IPA_DESKPROFILE_SEARCH_BASE, value); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n", ++ ipa_opts->basic[IPA_DESKPROFILE_SEARCH_BASE].opt_name, ++ dp_opt_get_string(ipa_opts->basic, ++ IPA_DESKPROFILE_SEARCH_BASE)); ++ } ++ ret = ipa_parse_search_base(ipa_opts->basic, ipa_opts->basic, ++ IPA_DESKPROFILE_SEARCH_BASE, ++ &ipa_opts->deskprofile_search_bases); ++ if (ret != EOK) goto done; ++ + value = dp_opt_get_string(ipa_opts->id->basic, SDAP_DEREF); + if (value != NULL) { + ret = deref_string_to_val(value, &i); +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index b1d90d3624b5bc6a126709e6bd6fb1fdbbaafad8..5b3507cd47aab75a4a7bbc16a8146d82411f2d16 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -56,6 +56,8 @@ enum ipa_basic_opt { + IPA_SERVER_MODE, + IPA_VIEWS_SEARCH_BASE, + IPA_KRB5_CONFD_PATH, ++ IPA_DESKPROFILE_SEARCH_BASE, ++ IPA_DESKPROFILE_REFRESH, + + IPA_OPTS_BASIC /* opts counter */ + }; +@@ -218,6 +220,7 @@ struct ipa_options { + struct sdap_search_base **master_domain_search_bases; + struct sdap_search_base **ranges_search_bases; + struct sdap_search_base **views_search_bases; ++ struct sdap_search_base **deskprofile_search_bases; + struct ipa_service *service; + + /* id provider */ +diff --git a/src/providers/ipa/ipa_deskprofile_config.c b/src/providers/ipa/ipa_deskprofile_config.c +new file mode 100644 +index 0000000000000000000000000000000000000000..8c66dda7550f200887ab99932b8be4c00e9785c0 +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_config.c +@@ -0,0 +1,156 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "util/util.h" ++#include "providers/ipa/ipa_common.h" ++#include "providers/ipa/ipa_deskprofile_private.h" ++#include "providers/ipa/ipa_deskprofile_config.h" ++#include "providers/ldap/sdap_async.h" ++ ++struct ipa_deskprofile_config_state { ++ struct sysdb_attrs *config; ++}; ++ ++static void ++ipa_deskprofile_get_config_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_deskprofile_get_config_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_handle *sh, ++ struct sdap_options *opts, ++ struct dp_option *ipa_opts) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq; ++ struct ipa_deskprofile_rule_state *state; ++ char *rule_filter; ++ const char *attrs[] = { IPA_DESKPROFILE_PRIORITY, NULL }; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_deskprofile_config_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed.\n"); ++ return NULL; ++ } ++ ++ rule_filter = talloc_asprintf(state, "(objectclass=%s)", ++ IPA_DESKPROFILE_CONFIG); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ subreq = sdap_get_generic_send(state, ev, opts, sh, ++ dp_opt_get_string(ipa_opts, ++ IPA_DESKPROFILE_SEARCH_BASE), ++ LDAP_SCOPE_BASE, rule_filter, ++ attrs, NULL, 0, ++ dp_opt_get_int(opts->basic, ++ SDAP_ENUM_SEARCH_TIMEOUT), ++ false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_get_generic_send failed.\n"); ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_deskprofile_get_config_done, req); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ ++ return req; ++} ++ ++static void ++ipa_deskprofile_get_config_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct ipa_deskprofile_config_state *state; ++ size_t reply_count; ++ struct sysdb_attrs **reply = NULL; ++ errno_t ret; ++ ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_deskprofile_config_state); ++ ++ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Could not retrieve Desktop Profile config\n"); ++ goto done; ++ } ++ ++ if (reply_count == 0) { ++ /* ++ * When connecting to an old server that doesn't support Desktop ++ * Profile, the reply_count will be zero. ++ * In order to not throw a unnecessary error and fail let's just ++ * return ENOENT and print a debug message about it. ++ */ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Server doesn't support Desktop Profile.\n"); ++ ret = ENOENT; ++ goto done; ++ } else if (reply_count != 1) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unexpected number of results, expected 1, got %zu.\n", ++ reply_count); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ state->config = reply[0]; ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t ++ipa_deskprofile_get_config_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **config) ++{ ++ struct ipa_deskprofile_config_state *state; ++ ++ state = tevent_req_data(req, struct ipa_deskprofile_config_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *config = talloc_steal(mem_ctx, state->config); ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_deskprofile_config.h b/src/providers/ipa/ipa_deskprofile_config.h +new file mode 100644 +index 0000000000000000000000000000000000000000..c4a05b2152beac95691e38c513b464bd5ab5becc +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_config.h +@@ -0,0 +1,45 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_DESKPROFILE_CONFIG_H_ ++#define IPA_DESKPROFILE_CONFIG_H_ ++ ++#include ++#include ++ ++#include "providers/ldap/ldap_common.h" ++#include "db/sysdb.h" ++ ++/* From ipa_deskprofile_config.c */ ++struct tevent_req * ++ipa_deskprofile_get_config_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_handle *sh, ++ struct sdap_options *opts, ++ struct dp_option *ipa_opts); ++ ++errno_t ++ipa_deskprofile_get_config_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **config); ++ ++#endif /* IPA_DESKPROFILE_CONFIG_H_ */ +diff --git a/src/providers/ipa/ipa_deskprofile_private.h b/src/providers/ipa/ipa_deskprofile_private.h +new file mode 100644 +index 0000000000000000000000000000000000000000..1db154b76a7bbe3114c2a4fc28eddc3fa16d9460 +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_private.h +@@ -0,0 +1,50 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_DESKPROFILE_PRIVATE_H_ ++#define IPA_DESKPROFILE_PRIVATE_H_ ++ ++#define IPA_DESKPROFILE_CONFIG "ipaDeskProfileConfig" ++#define IPA_DESKPROFILE_RULE "ipaDeskProfileRule" ++#define IPA_DESKPROFILE_PRIORITY "ipaDeskProfilePriority" ++#define IPA_DESKPROFILE_DATA "ipaDeskData" ++ ++#define DESKPROFILE_HOSTS_SUBDIR "deskprofile_hosts" ++#define DESKPROFILE_HOSTGROUPS_SUBDIR "deskprofile_hostgroups" ++ ++#define IPA_SESSION_RULE_TYPE "sessionRuleType" ++ ++#define IPA_DESKPROFILE_BASE_TMPL "cn=desktop-profile,%s" ++ ++#define SYSDB_DESKPROFILE_BASE_TMPL "cn=desktop-profile,"SYSDB_TMPL_CUSTOM_BASE ++ ++#define DESKPROFILE_RULES_SUBDIR "deskprofile_rules" ++ ++#define DESKPROFILE_CONFIG_SUBDIR "deskprofile_config" ++ ++struct deskprofile_rule { ++ const char *name; ++ int priority; ++ const char *data; ++}; ++ ++#endif /* IPA_DESKPROFILE_PRIVATE_H_ */ +diff --git a/src/providers/ipa/ipa_deskprofile_rules.c b/src/providers/ipa/ipa_deskprofile_rules.c +new file mode 100644 +index 0000000000000000000000000000000000000000..65994356e82515611dc13c214d5a504b1009870d +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_rules.c +@@ -0,0 +1,367 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "util/util.h" ++#include "providers/ldap/ldap_common.h" ++#include "providers/ldap/sdap_async_private.h" ++#include "providers/ipa/ipa_rules_common.h" ++#include "providers/ipa/ipa_deskprofile_private.h" ++#include "providers/ipa/ipa_deskprofile_rules.h" ++#include "providers/ipa/ipa_deskprofile_rules_util.h" ++ ++struct ipa_deskprofile_rule_state { ++ struct tevent_context *ev; ++ struct sdap_handle *sh; ++ struct sdap_options *opts; ++ ++ int search_base_iter; ++ struct sdap_search_base **search_bases; ++ ++ const char **attrs; ++ char *rules_filter; ++ char *cur_filter; ++ ++ size_t rule_count; ++ struct sysdb_attrs **rules; ++}; ++ ++static errno_t ++ipa_deskprofile_rule_info_next(struct tevent_req *req, ++ struct ipa_deskprofile_rule_state *state); ++static void ++ipa_deskprofile_rule_info_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_deskprofile_rule_info_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_handle *sh, ++ struct sdap_options *opts, ++ struct sdap_search_base **search_bases, ++ struct sysdb_attrs *ipa_host, ++ struct sss_domain_info *domain, ++ const char *username) ++{ ++ struct tevent_req *req = NULL; ++ struct ipa_deskprofile_rule_state *state; ++ char *user; ++ char *group; ++ char *host_dn_clean; ++ char *group_clean; ++ char *host_group_clean; ++ char *rule_filter; ++ const char *host_dn; ++ const char **memberof_list; ++ char **groups_list; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ipa_deskprofile_rule_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n"); ++ return NULL; ++ } ++ ++ if (ipa_host == NULL) { ++ ret = EINVAL; ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing host\n"); ++ goto immediate; ++ } ++ ++ ret = sysdb_attrs_get_string(ipa_host, SYSDB_ORIG_DN, &host_dn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify IPA hostname\n"); ++ goto immediate; ++ } ++ ++ ret = sss_filter_sanitize(state, host_dn, &host_dn_clean); ++ if (ret != EOK) { ++ goto immediate; ++ } ++ ++ state->ev = ev; ++ state->sh = sh; ++ state->opts = opts; ++ state->search_bases = search_bases; ++ state->search_base_iter = 0; ++ state->attrs = deskprofile_get_attrs_to_get_cached_rules(state); ++ if (state->attrs == NULL) { ++ ret = ENOMEM; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "deskprofile_get_attrs_get_cached_rules() failed\n"); ++ goto immediate; ++ } ++ ++ rule_filter = talloc_asprintf(state, ++ "(&(objectclass=%s)" ++ "(%s=%s)" ++ "(|(%s=%s)(%s=%s)(%s=%s)", ++ IPA_DESKPROFILE_RULE, ++ IPA_ENABLED_FLAG, IPA_TRUE_VALUE, ++ IPA_HOST_CATEGORY, "all", ++ IPA_USER_CATEGORY, "all", ++ IPA_MEMBER_HOST, host_dn_clean); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ /* Add all parent groups of ipa_hostname to the filter */ ++ ret = sysdb_attrs_get_string_array(ipa_host, SYSDB_ORIG_MEMBEROF, ++ state, &memberof_list); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify.\n"); ++ } else if (ret == ENOENT) { ++ /* This host is not a member of any hostgroups */ ++ memberof_list = talloc_array(state, const char *, 1); ++ if (memberof_list == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ memberof_list[0] = NULL; ++ } ++ ++ for (size_t i = 0; memberof_list[i] != NULL; i++) { ++ ret = sss_filter_sanitize(state, ++ memberof_list[i], ++ &host_group_clean); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_filter_sanitize() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ rule_filter = talloc_asprintf_append(rule_filter, "(%s=%s)", ++ IPA_MEMBER_HOST, ++ host_group_clean); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ } ++ ++ /* Add the username to the filter */ ++ ret = sss_parse_internal_fqname(state, username, &user, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_parse_internal_fqname() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ rule_filter = talloc_asprintf_append(rule_filter, "(%s=%s)", ++ IPA_MEMBER_USER, user); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ /* Add all parent groups of `username` to the filter */ ++ ret = get_sysdb_grouplist(state, domain->sysdb, domain, username, ++ &groups_list); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "get_sysdb_grouplist() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ for (size_t i = 0; groups_list[i] != NULL; i++) { ++ ret = sss_filter_sanitize(state, groups_list[i], &group_clean); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_filter_sanitize() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ ret = sss_parse_internal_fqname(state, group_clean, &group, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_parse_internal_fqname() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ rule_filter = talloc_asprintf_append(rule_filter, "(%s=%s)", ++ IPA_MEMBER_USER, group); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ } ++ ++ rule_filter = talloc_asprintf_append(rule_filter, "))"); ++ if (rule_filter == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ state->rules_filter = talloc_steal(state, rule_filter); ++ ++ ret = ipa_deskprofile_rule_info_next(req, state); ++ if (ret != EAGAIN) { ++ if (ret == EOK) { ++ /* ipa_deskprofile_rule_info_next should always have a search base ++ * when called for the first time. ++ * ++ * For the subsequent iterations, not finding any more search bases ++ * is fine though (thus the function returns EOK). ++ * ++ * As, here, it's the first case happening, let's return EINVAL. ++ */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "No search base found\n"); ++ ret = EINVAL; ++ } ++ goto immediate; ++ } ++ ++ return req; ++ ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ++ipa_deskprofile_rule_info_next(struct tevent_req *req, ++ struct ipa_deskprofile_rule_state *state) ++{ ++ struct tevent_req *subreq; ++ struct sdap_search_base *base; ++ ++ base = state->search_bases[state->search_base_iter]; ++ if (base == NULL) { ++ return EOK; ++ } ++ ++ talloc_zfree(state->cur_filter); ++ state->cur_filter = sdap_combine_filters(state, state->rules_filter, ++ base->filter); ++ if (state->cur_filter == NULL) { ++ return ENOMEM; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Sending request for next search base: [%s][%d][%s]\n", ++ base->basedn, base->scope, state->cur_filter); ++ ++ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, ++ base->basedn, base->scope, ++ state->cur_filter, state->attrs, ++ NULL, 0, ++ dp_opt_get_int(state->opts->basic, ++ SDAP_ENUM_SEARCH_TIMEOUT), ++ true); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_get_generic_send failed.\n"); ++ return ENOMEM; ++ } ++ tevent_req_set_callback(subreq, ipa_deskprofile_rule_info_done, req); ++ ++ return EAGAIN; ++} ++ ++static void ++ipa_deskprofile_rule_info_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req; ++ struct ipa_deskprofile_rule_state *state; ++ size_t rule_count; ++ size_t total_count; ++ struct sysdb_attrs **rules; ++ struct sysdb_attrs **target; ++ int i; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_deskprofile_rule_state); ++ ++ ret = sdap_get_generic_recv(subreq, state, ++ &rule_count, ++ &rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Could not retrieve Desktop Profile rules\n"); ++ goto fail; ++ } ++ ++ if (rule_count > 0) { ++ total_count = rule_count + state->rule_count; ++ state->rules = talloc_realloc(state, state->rules, ++ struct sysdb_attrs *, ++ total_count); ++ if (state->rules == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ i = 0; ++ while (state->rule_count < total_count) { ++ target = &state->rules[state->rule_count]; ++ *target = talloc_steal(state->rules, rules[i]); ++ ++ state->rule_count++; ++ i++; ++ } ++ } ++ ++ state->search_base_iter++; ++ ret = ipa_deskprofile_rule_info_next(req, state); ++ if (ret == EAGAIN) { ++ return; ++ } else if (ret != EOK) { ++ goto fail; ++ } else if (ret == EOK && state->rule_count == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "No rules apply to this host\n"); ++ tevent_req_error(req, ENOENT); ++ return; ++ } ++ ++ /* We went through all search bases and we have some results */ ++ tevent_req_done(req); ++ ++ return; ++ ++fail: ++ tevent_req_error(req, ret); ++} ++ ++errno_t ++ipa_deskprofile_rule_info_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ size_t *_rule_count, ++ struct sysdb_attrs ***_rules) ++{ ++ struct ipa_deskprofile_rule_state *state; ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ state = tevent_req_data(req, struct ipa_deskprofile_rule_state); ++ ++ *_rule_count = state->rule_count; ++ *_rules = talloc_steal(mem_ctx, state->rules); ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_deskprofile_rules.h b/src/providers/ipa/ipa_deskprofile_rules.h +new file mode 100644 +index 0000000000000000000000000000000000000000..313e526780c0780bce667fb459b27de7cc6fe9e9 +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_rules.h +@@ -0,0 +1,43 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_DESKPROFILE_RULES_H_ ++#define IPA_DESKPROFILE_RULES_H_ ++ ++/* From ipa_deskprofile_rules.c */ ++struct tevent_req * ++ipa_deskprofile_rule_info_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_handle *sh, ++ struct sdap_options *opts, ++ struct sdap_search_base **search_bases, ++ struct sysdb_attrs *ipa_host, ++ struct sss_domain_info *domain, ++ const char *username); ++ ++errno_t ++ipa_deskprofile_rule_info_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ size_t *rule_count, ++ struct sysdb_attrs ***rules); ++ ++#endif /* IPA_DESKPROFILE_RULES_H_ */ +diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.c b/src/providers/ipa/ipa_deskprofile_rules_util.c +new file mode 100644 +index 0000000000000000000000000000000000000000..1f5b7f9c5244c5863dec4096e2af58914425c37c +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_rules_util.c +@@ -0,0 +1,932 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "providers/ipa/ipa_deskprofile_rules_util.h" ++#include "providers/ipa/ipa_deskprofile_private.h" ++#include "providers/ipa/ipa_rules_common.h" ++#include ++#include ++ ++#define DESKPROFILE_GLOBAL_POLICY_MIN_VALUE 1 ++#define DESKPROFILE_GLOBAL_POLICY_MAX_VALUE 24 ++ ++enum deskprofile_name { ++ RULES_DIR = 0, ++ DOMAIN, ++ USERNAME, ++ PRIORITY, ++ USER, ++ GROUP, ++ HOST, ++ HOSTGROUP, ++ RULE_NAME, ++ EXTENSION, ++ DESKPROFILE_NAME_SENTINEL ++}; ++ ++/* ++ * The rule's filename has to follow a global policy, used by FleetCommander ++ * client that shows how the profile should be applied. ++ * ++ * This global policy is represented by an integer from 1 to 24 (inclusive) and ++ * has the following meaning: ++ * 1 = user, group, host, hostgroup ++ * 2 = user, group, hostgroup, host ++ * 3 = user, host, group, hostgroup ++ * 4 = user, host, hostgroup, group ++ * 5 = user, hostgroup, group, host ++ * 6 = user, hostgroup, host, group ++ * 7 = group, user, host, hostgroup ++ * 8 = group, user, hostgroup, host ++ * 9 = group, host, user, hostgroup ++ * 10 = group, host, hostgroup, user ++ * 11 = group, hostgroup, user, host ++ * 12 = group, hostgroup, host, user ++ * 13 = host, user, group, hostgroup ++ * 14 = host, user, hostgroup, group ++ * 15 = host, group, user, hostgroup ++ * 16 = host, group, hostgroup, user ++ * 17 = host, hostgroup, user, group ++ * 18 = host, hostgroup, group, user ++ * 19 = hostgroup, user, group, host ++ * 20 = hostgroup, user, host, group ++ * 21 = hostgroup, group, user, host ++ * 22 = hostgroup, group, host, user ++ * 23 = hostgroup, host, user, group ++ * 24 = hostgroup, host, group, user ++ * ++ * Having the table above in mind and considering the following example: ++ * - rule name: testrule ++ * - policy: 22 ++ * - priority: 420 ++ * - client's machine matches: host and group ++ * ++ * So, the filename will be: "000420_000000_000420_000420_000000_testrule.json" ++ * ++ * The function below not only helps us to create this filename in the correct ++ * format, but also create the whole path for this rule's file. ++ * ++ * An example of the full path would be: ++ * "/var/lib/sss/deskprofile/ipa.example/user_foobar/000420_000000_000420_000420_000000_testrule.json" ++ * | RULES DIR | DOMAIN | USERNAME | | |GROUP | HOST | USER | | ++ * PRIORITY RULE NAME ++ * HOSTGROUP EXTENSION ++ * ++ * In case a element has to be added/remove, please, remember to update: ++ * - deskprofile_name enum; ++ * - permuts's matrix; ++ * - vals array; ++ */ ++static errno_t ++ipa_deskprofile_get_filename_path(TALLOC_CTX *mem_ctx, ++ uint16_t config_priority, ++ const char *rules_dir, ++ const char *domain, ++ const char *username, ++ const char *priority, ++ const char *user_priority, ++ const char *group_priority, ++ const char *host_priority, ++ const char *hostgroup_priority, ++ const char *rule_name, ++ const char *extension, ++ char **_filename_path) ++{ ++ TALLOC_CTX *tmp_ctx; ++ static const uint8_t permuts[][DESKPROFILE_NAME_SENTINEL] = { ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, GROUP, HOST, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, GROUP, HOSTGROUP, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOST, GROUP, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOST, HOSTGROUP, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOSTGROUP, GROUP, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOSTGROUP, HOST, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, USER, HOST, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, USER, HOSTGROUP, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOST, USER, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOST, HOSTGROUP, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOSTGROUP, USER, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOSTGROUP, HOST, USER, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, USER, GROUP, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, USER, HOSTGROUP, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, GROUP, USER, HOSTGROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, GROUP, HOSTGROUP, USER, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, HOSTGROUP, USER, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, HOSTGROUP, GROUP, USER, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, USER, GROUP, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, USER, HOST, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, GROUP, USER, HOST, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, GROUP, HOST, USER, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, HOST, USER, GROUP, RULE_NAME, EXTENSION}, ++ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, HOST, GROUP, USER, RULE_NAME, EXTENSION}, ++ }; ++ const char *vals[] = { ++ rules_dir, ++ domain, ++ username, ++ priority, ++ user_priority, ++ group_priority, ++ host_priority, ++ hostgroup_priority, ++ rule_name, ++ extension, ++ NULL, ++ }; ++ const uint8_t *perms; ++ char *result; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ if (config_priority < DESKPROFILE_GLOBAL_POLICY_MIN_VALUE || ++ config_priority > DESKPROFILE_GLOBAL_POLICY_MAX_VALUE) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "The configuration priority has an invalid value: %d!\n", ++ config_priority); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ perms = permuts[config_priority - 1]; ++ ++ result = talloc_strdup(tmp_ctx, ""); ++ if (result == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (int i = 0; i < DESKPROFILE_NAME_SENTINEL; i++) { ++ switch(perms[i]) { ++ case RULES_DIR: ++ case DOMAIN: ++ case USERNAME: ++ result = talloc_asprintf_append(result, "%s/", vals[perms[i]]); ++ break; ++ case PRIORITY: ++ case USER: ++ case GROUP: ++ case HOST: ++ case HOSTGROUP: ++ result = talloc_asprintf_append(result, "%s_", vals[perms[i]]); ++ break; ++ case RULE_NAME: ++ result = talloc_asprintf_append(result, "%s", vals[perms[i]]); ++ break; ++ case EXTENSION: ++ result = talloc_asprintf_append(result, ".%s", vals[perms[i]]); ++ break; ++ default: ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "This situation should never happen\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (result == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ *_filename_path = talloc_steal(mem_ctx, result); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++ipa_deskprofile_rules_create_user_dir( ++ const char *username, /* fully-qualified */ ++ uid_t uid, ++ gid_t gid) ++{ ++ TALLOC_CTX *tmp_ctx; ++ char *shortname; ++ char *domain; ++ char *domain_dir; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, username, &shortname, &domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_parse_internal_fqname() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_create_dir(IPA_DESKPROFILE_RULES_USER_DIR, domain, 0755, ++ getuid(), getgid()); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to create the directory \"%s/%s\" that would be used to " ++ "store the Desktop Profile rules users' directory [%d]: %s\n", ++ IPA_DESKPROFILE_RULES_USER_DIR, domain, ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ domain_dir = talloc_asprintf(tmp_ctx, IPA_DESKPROFILE_RULES_USER_DIR"/%s", ++ domain); ++ if (domain_dir == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sss_create_dir(domain_dir, shortname, 0600, uid, gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to create the directory \"%s/%s/%s\" that would be used " ++ "to store the Desktop Profile rules for the user \"%s\" [%d]: " ++ "%s\n", ++ IPA_DESKPROFILE_RULES_USER_DIR, domain, shortname, username, ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ipa_deskprofile_get_normalized_rule_name(TALLOC_CTX *mem_ctx, ++ const char *name, ++ char **_rule_name) ++{ ++ char buffer[PATH_MAX]; ++ size_t buffer_len; ++ size_t name_len; ++ ++ name_len = strlen(name); ++ buffer_len = 0; ++ for (size_t i = 0; i < name_len; i++) { ++ char character; ++ bool replace; ++ ++ character = name[i]; ++ replace = false; ++ ++ if (isalnum(character) == 0) { ++ char next_character; ++ ++ next_character = name[i+1]; ++ if (i + 1 >= name_len || isalnum(next_character) == 0) { ++ continue; ++ } ++ ++ replace = true; ++ } ++ ++ buffer[buffer_len] = replace ? '_' : character; ++ buffer_len++; ++ } ++ buffer[buffer_len] = '\0'; ++ ++ *_rule_name = talloc_strdup(mem_ctx, buffer); ++ if (*_rule_name == NULL) { ++ return ENOMEM; ++ } ++ ++ return EOK; ++} ++ ++static errno_t ++ipa_deskprofile_rule_check_memberuser( ++ TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ struct sysdb_attrs *rule, ++ const char *rule_name, ++ const char *rule_prio, ++ const char *base_dn, ++ const char *username, /* fully-qualified */ ++ char **_user_prio, ++ char **_group_prio) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message_element *el; ++ struct ldb_result *res; ++ size_t num_groups; ++ char **groups = NULL; ++ const char *fqgroupname = NULL; ++ char *groupname = NULL; ++ char *shortname; ++ char *domainname; ++ char *data; ++ char *memberuser; ++ char *membergroup; ++ char *user_prio; ++ char *group_prio; ++ bool user = false; ++ bool group = false; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, username, ++ &shortname, &domainname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_parse_internal_fqname() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_initgroups(tmp_ctx, domain, username, &res); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sysdb_initgroups() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ /* This really should NOT happen at this point */ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "User [%s] not found in cache\n", username); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ groups = talloc_array(tmp_ctx, char *, res->count); ++ if (groups == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ num_groups = 0; ++ /* Start counting from 1 to exclude the user entry */ ++ for (size_t i = 1; i < res->count; i++) { ++ fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i], ++ SYSDB_NAME, ++ NULL); ++ if (fqgroupname == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Skipping malformed entry [%s]\n", ++ ldb_dn_get_linearized(res->msgs[i]->dn)); ++ continue; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname, ++ &groupname, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Malformed name %s, skipping!\n", fqgroupname); ++ continue; ++ } ++ ++ groups[num_groups] = groupname; ++ num_groups++; ++ } ++ groups[num_groups] = NULL; ++ ++ ret = sysdb_attrs_get_el(rule, IPA_MEMBER_USER, &el); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule memberUser for rule " ++ "\"%s\" [%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ ++ goto done; ++ } ++ ++ memberuser = talloc_asprintf(tmp_ctx, "uid=%s,cn=users,cn=accounts,%s", ++ shortname, base_dn); ++ if (memberuser == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate memberuser\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (size_t i = 0; i < el->num_values; i++) { ++ if (user && group) { ++ break; ++ } ++ ++ data = (char *)el->values[i].data; ++ ++ if (!user && data != NULL && strcmp(memberuser, data) == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Desktop Profile rule \"%s\" matches with the user \"%s\" " ++ "for the \"%s\" domain!\n", ++ rule_name, shortname, domainname); ++ user = true; ++ continue; ++ } ++ ++ if (!group && data != NULL) { ++ for (size_t j = 0; !group && groups[j] != NULL; j++) { ++ membergroup = talloc_asprintf(tmp_ctx, ++ "cn=%s,cn=groups,cn=accounts,%s", ++ groups[j], base_dn); ++ if (membergroup == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate membergroup\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (strcmp(membergroup, data) == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Desktop Profile rule \"%s\" matches with (at least) " ++ "the group \"%s\" for the \"%s\" domain!\n", ++ rule_name, groups[j], domainname); ++ group = true; ++ } ++ } ++ } ++ } ++ ++ user_prio = user ? talloc_strdup(tmp_ctx, rule_prio) : ++ talloc_asprintf(tmp_ctx, "%06d", 0); ++ if (user_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the user priority\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ group_prio = group ? talloc_strdup(tmp_ctx, rule_prio) : ++ talloc_asprintf(tmp_ctx, "%06d", 0); ++ if (group_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the group priority\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_user_prio = talloc_steal(mem_ctx, user_prio); ++ *_group_prio = talloc_steal(mem_ctx, group_prio); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ipa_deskprofile_rule_check_memberhost(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ struct sysdb_attrs *rule, ++ const char *rule_name, ++ const char *rule_prio, ++ const char *base_dn, ++ const char *hostname, ++ char **_host_prio, ++ char **_hostgroup_prio) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *host_dn; ++ struct ldb_message_element *el_orig_memberof = NULL; ++ struct ldb_message_element *el = NULL; ++ struct ldb_message **msgs; ++ size_t count; ++ size_t num_memberhostgroup; ++ char **memberhostgroups = NULL; ++ char *data; ++ char *memberhost; ++ char *memberhostgroup; ++ char *name; ++ char *host_prio; ++ char *hostgroup_prio; ++ const char *memberof_attrs[] = { SYSDB_ORIG_MEMBEROF, NULL }; ++ bool host = false; ++ bool hostgroup = false; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ host_dn = sysdb_custom_dn(tmp_ctx, domain, hostname, ++ DESKPROFILE_HOSTS_SUBDIR); ++ if (host_dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_entry(tmp_ctx, domain->sysdb, host_dn, ++ LDB_SCOPE_BASE, NULL, ++ memberof_attrs, ++ &count, &msgs); ++ if (ret == ENOENT || count == 0) { ++ memberhostgroups = talloc_array(tmp_ctx, char *, 1); ++ memberhostgroups[0] = NULL; ++ } else if (ret != EOK) { ++ goto done; ++ } else if (count > 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "More than one result for a BASE search!\n"); ++ ret = EIO; ++ goto done; ++ } else { /* ret == EOK && count == 1 */ ++ el_orig_memberof = ldb_msg_find_element(msgs[0], SYSDB_ORIG_MEMBEROF); ++ memberhostgroups = talloc_array(tmp_ctx, ++ char *, ++ el_orig_memberof->num_values); ++ } ++ ++ if (el_orig_memberof != NULL) { ++ num_memberhostgroup = 0; ++ for (size_t i = 0; i < el_orig_memberof->num_values; i++) { ++ data = (char *)el_orig_memberof->values[i].data; ++ ++ ret = ipa_common_get_hostgroupname(tmp_ctx, domain->sysdb, data, ++ &name); ++ ++ /* ERR_UNEXPECTED_ENTRY_TYPE means we had a memberOf entry that ++ * wasn't a host group, thus we'll just ignore those. ++ */ ++ if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Skipping malformed entry [%s]\n", ++ data); ++ continue; ++ } else if (ret == EOK) { ++ memberhostgroups[num_memberhostgroup] = name; ++ num_memberhostgroup++; ++ } ++ } ++ memberhostgroups[num_memberhostgroup] = NULL; ++ } ++ ++ ret = sysdb_attrs_get_el(rule, IPA_MEMBER_HOST, &el); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule memberHost for rule " ++ "\"%s\" [%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ ++ goto done; ++ } ++ ++ memberhost = talloc_asprintf(tmp_ctx, "fqdn=%s,cn=computers,cn=accounts,%s", ++ hostname, base_dn); ++ if (memberhost == NULL) { ++ ret = ENOMEM; ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate memberhost\n"); ++ goto done; ++ } ++ ++ for (size_t i = 0; i < el->num_values; i++) { ++ if (host && hostgroup) { ++ break; ++ } ++ ++ data = (char *)el->values[i].data; ++ ++ if (!host && data != NULL && strcmp(memberhost, data) == 0) { ++ host = true; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Desktop Profile rule \"%s\" matches with the host \"%s\" " ++ "for the \"%s\" domain!\n", ++ rule_name, hostname, domain->name); ++ continue; ++ } ++ ++ if (!hostgroup && data != NULL) { ++ for (size_t j = 0; !hostgroup && memberhostgroups[j] != NULL; j++) { ++ memberhostgroup = talloc_asprintf( ++ tmp_ctx, ++ "cn=%s,cn=hostgroups,cn=accounts,%s", ++ memberhostgroups[j], base_dn); ++ ++ if (memberhostgroup == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to allocate memberhostgroup\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (strcmp(memberhostgroup, data) == 0) { ++ hostgroup = true; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Desktop Profile rule \"%s\" matches with (at least) " ++ "the hostgroup \"%s\" for the \"%s\" domain!\n", ++ rule_name, memberhostgroups[j], domain->name); ++ continue; ++ } ++ } ++ } ++ } ++ ++ host_prio = host ? talloc_strdup(tmp_ctx, rule_prio) : ++ talloc_asprintf(tmp_ctx, "%06d", 0); ++ if (host_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the host priority\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ hostgroup_prio = hostgroup ? talloc_strdup(tmp_ctx, rule_prio) : ++ talloc_asprintf(tmp_ctx, "%06d", 0); ++ if (hostgroup_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the hostgroup priority\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_host_prio = talloc_steal(mem_ctx, host_prio); ++ *_hostgroup_prio = talloc_steal(mem_ctx, hostgroup_prio); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++ ++errno_t ++ipa_deskprofile_rules_save_rule_to_disk( ++ TALLOC_CTX *mem_ctx, ++ uint16_t priority, ++ struct sysdb_attrs *rule, ++ struct sss_domain_info *domain, ++ const char *hostname, ++ const char *username, /* fully-qualified */ ++ uid_t uid, ++ gid_t gid) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *rule_name; ++ const char *data; ++ char *shortname; ++ char *domainname; ++ char *base_dn; ++ char *rule_prio; ++ char *user_prio; ++ char *group_prio; ++ char *host_prio; ++ char *hostgroup_prio; ++ char *normalized_rule_name = NULL; ++ char *filename_path = NULL; ++ const char *extension = "json"; ++ uint32_t prio; ++ int fd = -1; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_get_string(rule, IPA_CN, &rule_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_uint32_t(rule, IPA_DESKPROFILE_PRIORITY, &prio); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule priority for rule " ++ "\"%s\" [%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ rule_prio = talloc_asprintf(tmp_ctx, "%06d", prio); ++ if (rule_prio == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate rule priority\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string(rule, IPA_DESKPROFILE_DATA, &data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Failed to get the Desktop Profile Rule data for rule \"%s\" " ++ "[%d]: %s\n", ++ rule_name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, username, &shortname, &domainname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_parse_internal_fqname() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = domain_to_basedn(tmp_ctx, domainname, &base_dn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "domain_to_basedn() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule, ++ rule_name, rule_prio, ++ base_dn, username, ++ &user_prio, &group_prio); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule, ++ rule_name, rule_prio, ++ base_dn, hostname, ++ &host_prio, &hostgroup_prio); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_deskprofile_get_normalized_rule_name(mem_ctx, rule_name, ++ &normalized_rule_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_get_normalized_rule_name() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_deskprofile_get_filename_path(tmp_ctx, ++ priority, ++ IPA_DESKPROFILE_RULES_USER_DIR, ++ domainname, ++ shortname, ++ rule_prio, ++ user_prio, ++ group_prio, ++ host_prio, ++ hostgroup_prio, ++ normalized_rule_name, ++ extension, ++ &filename_path); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_get_filename_path() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ fd = open(filename_path, O_WRONLY | O_CREAT | O_TRUNC, 0600); ++ if (fd == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to create the Desktop Profile rule file \"%s\" " ++ "[%d]: %s\n", ++ filename_path, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = dprintf(fd, "%s", data); ++ if (ret < 0) { ++ ret = EIO; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to write the content of the Desktop Profile rule for " ++ "the \"%s\" file.\n", ++ filename_path); ++ goto done; ++ } ++ ++ ret = fchown(fd, uid, gid); ++ if (ret != EOK) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to own the Desktop Profile Rule file \"%s\" [%d]: %s\n", ++ filename_path, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (fd != -1) { ++ close(fd); ++ } ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++ipa_deskprofile_rules_remove_user_dir(const char *user_dir) ++{ ++ errno_t ret; ++ ++ ret = sss_remove_tree(user_dir); ++ if (ret == ENOENT) { ++ return EOK; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot remove \"%s\" directory [%d]: %s\n", ++ user_dir, ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++errno_t ++deskprofile_get_cached_priority(struct sss_domain_info *domain, ++ uint16_t *_priority) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = { IPA_DESKPROFILE_PRIORITY, NULL }; ++ struct ldb_message **resp; ++ size_t resp_count; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_search_custom_by_name(tmp_ctx, ++ domain, ++ IPA_DESKPROFILE_PRIORITY, ++ DESKPROFILE_CONFIG_SUBDIR, ++ attrs, &resp_count, &resp); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sysdb_search_custom_by_name() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (resp_count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sysdb_search_custom_by_name() got more attributes than " ++ "expected. Expected (%d), got (%"PRIu64")\n", 1, resp_count); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ *_priority = ldb_msg_find_attr_as_uint(resp[0], ++ IPA_DESKPROFILE_PRIORITY, ++ 0); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++const char ** ++deskprofile_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx) ++{ ++ const char **attrs = talloc_zero_array(mem_ctx, const char *, 11); ++ if (attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array() failed\n"); ++ goto done; ++ } ++ ++ attrs[0] = OBJECTCLASS; ++ attrs[1] = IPA_CN; ++ attrs[2] = IPA_UNIQUE_ID; ++ attrs[3] = IPA_ENABLED_FLAG; ++ attrs[4] = IPA_MEMBER_USER; ++ attrs[5] = IPA_USER_CATEGORY; ++ attrs[6] = IPA_MEMBER_HOST; ++ attrs[7] = IPA_HOST_CATEGORY; ++ attrs[8] = IPA_DESKPROFILE_PRIORITY; ++ attrs[9] = IPA_DESKPROFILE_DATA; ++ attrs[10] = NULL; ++ ++done: ++ return attrs; ++} +diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.h b/src/providers/ipa/ipa_deskprofile_rules_util.h +new file mode 100644 +index 0000000000000000000000000000000000000000..61f404df83382e139abc859ed43db65037d04ace +--- /dev/null ++++ b/src/providers/ipa/ipa_deskprofile_rules_util.h +@@ -0,0 +1,57 @@ ++/* ++ SSSD ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_DESKPROFILE_RULES_UTIL_H_ ++#define IPA_DESKPROFILE_RULES_UTIL_H_ ++ ++#include "db/sysdb.h" ++ ++#ifndef IPA_DESKPROFILE_RULES_USER_DIR ++#define IPA_DESKPROFILE_RULES_USER_DIR SSS_STATEDIR"/deskprofile" ++#endif /* IPA_DESKPROFILE_RULES_USER_DIR */ ++ ++errno_t ++ipa_deskprofile_rules_create_user_dir( ++ const char *username, /* fully-qualified */ ++ uid_t uid, ++ gid_t gid); ++errno_t ++ipa_deskprofile_rules_save_rule_to_disk( ++ TALLOC_CTX *mem_ctx, ++ uint16_t priority, ++ struct sysdb_attrs *rule, ++ struct sss_domain_info *domain, ++ const char *hostname, ++ const char *username, /* fully-qualified */ ++ uid_t uid, ++ gid_t gid); ++errno_t ++ipa_deskprofile_rules_remove_user_dir(const char *user_dir); ++ ++errno_t ++deskprofile_get_cached_priority(struct sss_domain_info *domain, ++ uint16_t *_priority); ++ ++const char ** ++deskprofile_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx); ++ ++#endif /* IPA_DESKPROFILE_RULES_UTIL_H_ */ +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index 7dec4d1fb8541a48470d4e44f10838e5bea67ad5..7cae43c065e0cd687a80620faf6a354f001bd41c 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -42,6 +42,7 @@ + #include "providers/ipa/ipa_subdomains.h" + #include "providers/ipa/ipa_srv.h" + #include "providers/be_dyndns.h" ++#include "providers/ipa/ipa_session.h" + + #define DNS_SRV_MISCONFIGURATION "SRV discovery is enabled on the IPA " \ + "server while using custom dns_discovery_domain. DNS discovery of " \ +@@ -940,3 +941,51 @@ errno_t sssm_ipa_sudo_init(TALLOC_CTX *mem_ctx, + return EOK; + #endif + } ++ ++errno_t sssm_ipa_session_init(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, ++ void *module_data, ++ struct dp_method *dp_methods) ++{ ++ struct ipa_session_ctx *session_ctx; ++ struct ipa_init_ctx *init_ctx; ++ struct ipa_id_ctx *id_ctx; ++ errno_t ret; ++ ++ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx); ++ id_ctx = init_ctx->id_ctx; ++ ++ session_ctx = talloc_zero(mem_ctx, struct ipa_session_ctx); ++ if (session_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed.\n"); ++ ++ return ENOMEM; ++ } ++ ++ session_ctx->sdap_ctx = id_ctx->sdap_id_ctx; ++ session_ctx->host_map = id_ctx->ipa_options->host_map; ++ session_ctx->hostgroup_map = id_ctx->ipa_options->hostgroup_map; ++ session_ctx->host_search_bases = id_ctx->ipa_options->host_search_bases; ++ session_ctx->deskprofile_search_bases = id_ctx->ipa_options->deskprofile_search_bases; ++ ++ ret = dp_copy_options(session_ctx, id_ctx->ipa_options->basic, ++ IPA_OPTS_BASIC, &session_ctx->ipa_options); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options() failed.\n"); ++ ++ goto done; ++ } ++ ++ dp_set_method(dp_methods, DPM_SESSION_HANDLER, ++ ipa_pam_session_handler_send, ipa_pam_session_handler_recv, session_ctx, ++ struct ipa_session_ctx, struct pam_data, struct pam_data *); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(session_ctx); ++ } ++ ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index f9f3a2a6992be6cf5cb3c699b30c45ca9dbb42ab..4836445dad82c4d3ecaecc32d22cb6f9730f0fcb 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -48,6 +48,8 @@ struct dp_option ipa_basic_opts[] = { + { "ipa_server_mode", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ipa_views_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING }, ++ { "ipa_deskprofile_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, ++ { "ipa_deskprofile_refresh", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER }, + DP_OPTION_TERMINATOR + }; + +diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c +new file mode 100644 +index 0000000000000000000000000000000000000000..7adf8b6d7dfef9b2c29c1ee42f47842131773e90 +--- /dev/null ++++ b/src/providers/ipa/ipa_session.c +@@ -0,0 +1,833 @@ ++/* ++ SSSD ++ ++ IPA Backend Module -- Session Management ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++#include ++ ++#include "util/child_common.h" ++#include "providers/ldap/sdap_async.h" ++#include "providers/ipa/ipa_common.h" ++#include "providers/ipa/ipa_config.h" ++#include "providers/ipa/ipa_hosts.h" ++#include "providers/ipa/ipa_subdomains.h" ++#include "providers/ipa/ipa_session.h" ++#include "providers/ipa/ipa_rules_common.h" ++#include "providers/ipa/ipa_deskprofile_private.h" ++#include "providers/ipa/ipa_deskprofile_config.h" ++#include "providers/ipa/ipa_deskprofile_rules.h" ++#include "providers/ipa/ipa_deskprofile_rules_util.h" ++ ++/* Those here are used for sending a message to the deskprofile client ++ * informing that our side is done. */ ++#define SSS_FLEETCOMMANDERCLIENT_BUS "org.freedesktop.FleetCommanderClient" ++#define SSS_FLEETCOMMANDERCLIENT_PATH "/org/freedesktop/FleetCommanderClient" ++#define SSS_FLEETCOMMANDERCLIENT_IFACE "org.freedesktop.FleetCommanderClient" ++ ++struct ipa_fetch_deskprofile_state { ++ struct tevent_context *ev; ++ struct be_ctx *be_ctx; ++ struct sdap_id_ctx *sdap_ctx; ++ struct ipa_session_ctx *session_ctx; ++ struct sdap_id_op *sdap_op; ++ struct dp_option *ipa_options; ++ struct sdap_search_base **search_bases; ++ const char *username; ++ ++ /* Hosts */ ++ struct ipa_common_entries *hosts; ++ struct sysdb_attrs *ipa_host; ++ ++ /* Rules */ ++ struct ipa_common_entries *rules; ++ struct sysdb_attrs *config; ++ uint16_t priority; ++}; ++ ++static errno_t ipa_fetch_deskprofile_retry(struct tevent_req *req); ++static void ipa_fetch_deskprofile_connect_done(struct tevent_req *subreq); ++static errno_t ipa_fetch_deskprofile_hostinfo(struct tevent_req *req); ++static void ipa_fetch_deskprofile_hostinfo_done(struct tevent_req *subreq); ++static void ipa_fetch_deskprofile_config_done(struct tevent_req *subreq); ++static void ipa_fetch_deskprofile_rules_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ipa_fetch_deskprofile_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct be_ctx *be_ctx, ++ struct ipa_session_ctx *session_ctx, ++ const char *username) ++{ ++ struct ipa_fetch_deskprofile_state *state; ++ struct tevent_req *req; ++ time_t now; ++ time_t refresh_interval; ++ bool offline; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_fetch_deskprofile_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->be_ctx = be_ctx; ++ state->session_ctx = session_ctx; ++ state->sdap_ctx = session_ctx->sdap_ctx; ++ state->ipa_options = session_ctx->ipa_options; ++ state->search_bases = session_ctx->deskprofile_search_bases; ++ state->username = username; ++ state->hosts = talloc_zero(state, struct ipa_common_entries); ++ if (state->hosts == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ state->rules = talloc_zero(state, struct ipa_common_entries); ++ if (state->rules == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ if (state->search_bases == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No Desktop Profile search base found.\n"); ++ ret = EINVAL; ++ goto immediately; ++ } ++ ++ state->sdap_op = sdap_id_op_create(state, ++ state->sdap_ctx->conn->conn_cache); ++ if (state->sdap_op == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ offline = be_is_offline(be_ctx); ++ DEBUG(SSSDBG_TRACE_ALL, "Connection status is [%s].\n", ++ offline ? "offline" : "online"); ++ ++ refresh_interval = dp_opt_get_int(state->ipa_options, ++ IPA_DESKPROFILE_REFRESH); ++ now = time(NULL); ++ ++ if (offline || now < session_ctx->last_update + refresh_interval) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Performing cached Desktop Profile evaluation\n"); ++ ret = EOK; ++ goto immediately; ++ } ++ ++ ret = ipa_fetch_deskprofile_retry(req); ++ if (ret != EAGAIN) { ++ goto immediately; ++ } ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static errno_t ++ipa_fetch_deskprofile_retry(struct tevent_req *req) ++{ ++ struct tevent_req *subreq; ++ struct ipa_fetch_deskprofile_state *state; ++ int ret; ++ ++ state = tevent_req_data(req, struct ipa_fetch_deskprofile_state); ++ ++ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sdap_id_op_connect_send() failed: %d (%s)\n", ++ ret, strerror(ret)); ++ ++ return ret; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_fetch_deskprofile_connect_done, req); ++ ++ return EAGAIN; ++} ++ ++static void ++ipa_fetch_deskprofile_connect_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = NULL; ++ int dp_error; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = ipa_fetch_deskprofile_hostinfo(req); ++ if (ret == EAGAIN) { ++ return; ++ } ++ ++done: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++} ++ ++static errno_t ++ipa_fetch_deskprofile_hostinfo(struct tevent_req *req) ++{ ++ struct tevent_req *subreq; ++ struct ipa_fetch_deskprofile_state *state; ++ const char *hostname; ++ ++ state = tevent_req_data(req, struct ipa_fetch_deskprofile_state); ++ hostname = dp_opt_get_string(state->ipa_options, IPA_HOSTNAME); ++ ++ subreq = ipa_host_info_send(state, ++ state->ev, ++ sdap_id_op_handle(state->sdap_op), ++ state->sdap_ctx->opts, ++ hostname, ++ state->session_ctx->host_map, ++ state->session_ctx->hostgroup_map, ++ state->session_ctx->host_search_bases); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_fetch_deskprofile_hostinfo_done, req); ++ ++ return EAGAIN; ++} ++ ++static void ++ipa_fetch_deskprofile_hostinfo_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct ipa_fetch_deskprofile_state *state; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_fetch_deskprofile_state); ++ ++ ret = ipa_host_info_recv(subreq, state, ++ &state->hosts->entry_count, ++ &state->hosts->entries, ++ &state->hosts->group_count, ++ &state->hosts->groups); ++ state->hosts->entry_subdir = DESKPROFILE_HOSTS_SUBDIR; ++ state->hosts->group_subdir = DESKPROFILE_HOSTGROUPS_SUBDIR; ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = ipa_get_host_attrs(state->ipa_options, ++ state->hosts->entry_count, ++ state->hosts->entries, ++ &state->ipa_host); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host.\n"); ++ goto done; ++ } ++ ++ subreq = ipa_deskprofile_get_config_send(state, ++ state->ev, ++ sdap_id_op_handle(state->sdap_op), ++ state->sdap_ctx->opts, ++ state->ipa_options); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_fetch_deskprofile_config_done, req); ++ return; ++ ++done: ++ tevent_req_error(req, ret); ++} ++ ++static void ++ipa_fetch_deskprofile_config_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct ipa_fetch_deskprofile_state *state; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_fetch_deskprofile_state); ++ ++ ret = ipa_deskprofile_get_config_recv(subreq, state, &state->config); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_store_custom(state->be_ctx->domain, IPA_DESKPROFILE_PRIORITY, ++ DESKPROFILE_CONFIG_SUBDIR, state->config); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save Desktop Profile policy\n"); ++ goto done; ++ } ++ ++ subreq = ipa_deskprofile_rule_info_send(state, ++ state->ev, ++ sdap_id_op_handle(state->sdap_op), ++ state->sdap_ctx->opts, ++ state->search_bases, ++ state->ipa_host, ++ state->be_ctx->domain, ++ state->username); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_fetch_deskprofile_rules_done, req); ++ return; ++ ++done: ++ tevent_req_error(req, ret); ++} ++ ++static void ++ipa_fetch_deskprofile_rules_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct ipa_fetch_deskprofile_state *state; ++ int dp_error; ++ errno_t ret; ++ bool found; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_fetch_deskprofile_state); ++ ++ ret = ipa_deskprofile_rule_info_recv(subreq, ++ state, ++ &state->rules->entry_count, ++ &state->rules->entries); ++ state->rules->entry_subdir = DESKPROFILE_RULES_SUBDIR; ++ talloc_zfree(subreq); ++ if (ret == ENOENT) { ++ /* Set ret to EOK so we can safely call sdap_id_op_done. */ ++ ret = EOK; ++ found = false; ++ } else if (ret == EOK) { ++ found = true; ++ } else { ++ goto done; ++ } ++ ++ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = ipa_fetch_deskprofile_retry(req); ++ if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } else if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* For now, let's completely purge the previous stored ++ * rules before saving the new ones */ ++ ret = ipa_common_purge_rules(state->be_ctx->domain, ++ DESKPROFILE_RULES_SUBDIR); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to remove Desktop Profile rules\n"); ++ goto done; ++ } ++ ++ if (!found) { ++ ret = ENOENT; ++ goto done; ++ } ++ ++ ret = ipa_common_save_rules(state->be_ctx->domain, ++ state->hosts, NULL, state->rules, ++ &state->session_ctx->last_update); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save Desktop Profile rules\n"); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ++ipa_fetch_deskprofile_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++struct ipa_pam_session_handler_state { ++ struct tevent_context *ev; ++ struct be_ctx *be_ctx; ++ struct ipa_session_ctx *session_ctx; ++ struct pam_data *pd; ++ ++ /* Those attributes are used for: ++ * - saving the deskprofile rules to the disk; ++ * - deleting the deskprofile rules from the disk; ++ * - contacting the deskprofile client that everything is ready; ++ */ ++ char *shortname; ++ char *domain; ++ char *user_dir; ++ uid_t uid; ++ gid_t gid; ++}; ++ ++static errno_t ++ipa_pam_session_handler_get_deskprofile_user_info( ++ TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *username, ++ char **_shortname, ++ char **_domain, ++ char **_user_dir, ++ uid_t *uid, ++ gid_t *gid); ++static void ipa_pam_session_handler_done(struct tevent_req *subreq); ++static errno_t ++ipa_pam_session_handler_save_deskprofile_rules( ++ struct be_ctx *be_ctx, ++ struct sss_domain_info *domain, ++ const char *username, /* fully-qualified */ ++ const char *user_dir, ++ const char *hostname, ++ uid_t uid, ++ gid_t gid); ++static errno_t ++ipa_pam_session_handler_notify_deskprofile_client(uid_t uid, ++ const char *user_dir, ++ uint16_t prio); ++ ++ ++struct tevent_req * ++ipa_pam_session_handler_send(TALLOC_CTX *mem_ctx, ++ struct ipa_session_ctx *session_ctx, ++ struct pam_data *pd, ++ struct dp_req_params *params) ++{ ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct ipa_pam_session_handler_state *state; ++ errno_t ret; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving Desktop Profile rules\n"); ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_pam_session_handler_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->pd = pd; ++ state->ev = params->ev; ++ state->be_ctx = params->be_ctx; ++ state->session_ctx = session_ctx; ++ ++ /* Get all the user info that will be needed in order the delete the ++ * user's deskprofile directory from the disk, create the user's directory, ++ * save the fetched rules to the disk and notify the deskprofile client ++ * that this operation is done. */ ++ ret = ipa_pam_session_handler_get_deskprofile_user_info( ++ state, ++ state->be_ctx->domain, ++ pd->user, ++ &state->shortname, ++ &state->domain, ++ &state->user_dir, ++ &state->uid, ++ &state->gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_get_user_info() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ state->pd->pam_status = PAM_SESSION_ERR; ++ goto done; ++ } ++ ++ /* As no proper merging mechanism has been implemented yet ... ++ * let's just remove the user directory stored in the disk as it's ++ * going to be created again in case there's any rule fetched. */ ++ ret = ipa_deskprofile_rules_remove_user_dir(state->user_dir); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_deskprofile_rules_remove_user_dir() failed.\n"); ++ state->pd->pam_status = PAM_SESSION_ERR; ++ goto done; ++ } ++ ++ subreq = ipa_fetch_deskprofile_send(state, state->ev, state->be_ctx, ++ state->session_ctx, pd->user); ++ if (subreq == NULL) { ++ state->pd->pam_status = PAM_SESSION_ERR; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_pam_session_handler_done, req); ++ return req; ++ ++done: ++ tevent_req_done(req); ++ tevent_req_post(req, params->ev); ++ ++ return req; ++} ++ ++static void ++ipa_pam_session_handler_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct ipa_pam_session_handler_state *state; ++ const char *hostname; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_pam_session_handler_state); ++ ++ ret = ipa_fetch_deskprofile_recv(subreq); ++ talloc_free(subreq); ++ ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_IMPORTANT_INFO, "No Desktop Profile rules found\n"); ++ state->pd->pam_status = PAM_SUCCESS; ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to fetch Desktop Profile rules [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ state->pd->pam_status = PAM_SYSTEM_ERR; ++ goto done; ++ } ++ ++ hostname = dp_opt_get_string(state->session_ctx->ipa_options, IPA_HOSTNAME); ++ ret = ipa_pam_session_handler_save_deskprofile_rules(state->be_ctx, ++ state->be_ctx->domain, ++ state->pd->user, ++ state->user_dir, ++ hostname, ++ state->uid, ++ state->gid); ++ ++ state->pd->pam_status = (ret == EOK) ? PAM_SUCCESS : PAM_SESSION_ERR; ++ ++done: ++ /* TODO For backward compatibility we always return EOK to DP now. */ ++ tevent_req_done(req); ++} ++ ++errno_t ++ipa_pam_session_handler_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct pam_data **_data) ++{ ++ struct ipa_pam_session_handler_state *state = NULL; ++ ++ state = tevent_req_data(req, struct ipa_pam_session_handler_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_data = talloc_steal(mem_ctx, state->pd); ++ ++ return EOK; ++} ++ ++static errno_t ++ipa_pam_session_handler_get_deskprofile_user_info(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *username, ++ char **_shortname, ++ char **_domain, ++ char **_user_dir, ++ uid_t *_uid, ++ gid_t *_gid) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *res = NULL; ++ char *shortname; ++ char *domain_name; ++ char *user_dir; ++ uid_t uid; ++ gid_t gid; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, username, ++ &shortname, &domain_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Failed to parse \"%s\" [%d]: %s\n", ++ username, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ user_dir = talloc_asprintf(tmp_ctx, IPA_DESKPROFILE_RULES_USER_DIR"/%s/%s", ++ domain_name, shortname); ++ if (user_dir == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_getpwnam(tmp_ctx, domain, username, &res); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_getpwnam() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (res->count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sysdb_getpwnam() got more users than expected. " ++ "Expected [%d], got [%d]\n", 1, res->count); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0); ++ gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0); ++ if (uid == 0 || gid == 0) { ++ /* As IPA doesn't handle root users ou groups, we know for sure that's ++ * something wrong in case we get uid = 0 or gid = 0. ++ */ ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++ *_shortname = talloc_steal(mem_ctx, shortname); ++ *_domain = talloc_steal(mem_ctx, domain_name); ++ *_user_dir = talloc_steal(mem_ctx, user_dir); ++ *_uid = uid; ++ *_gid = gid; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ipa_pam_session_handler_save_deskprofile_rules( ++ struct be_ctx *be_ctx, ++ struct sss_domain_info *domain, ++ const char *username, /* fully-qualified */ ++ const char *user_dir, ++ const char *hostname, ++ uid_t uid, ++ gid_t gid) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char **attrs_get_cached_rules; ++ size_t rule_count; ++ struct sysdb_attrs **rules; ++ uint16_t priority; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ /* Get Desktop Profile priority from sysdb */ ++ ret = deskprofile_get_cached_priority(be_ctx->domain, &priority); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "deskprofile_get_cached_priority() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ++ /* Get Desktop Profile rules from sysdb */ ++ attrs_get_cached_rules = deskprofile_get_attrs_to_get_cached_rules(tmp_ctx); ++ if (attrs_get_cached_rules == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "deskprofile_get_attrs_get_cached_rules() failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ipa_common_get_cached_rules(tmp_ctx, be_ctx->domain, ++ IPA_DESKPROFILE_RULE, ++ DESKPROFILE_RULES_SUBDIR, ++ attrs_get_cached_rules, ++ &rule_count, ++ &rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Could not retrieve Desktop Profile rules from the cache\n"); ++ goto done; ++ } ++ ++ /* Create the user directory where the rules are going to be stored */ ++ ret = ipa_deskprofile_rules_create_user_dir(username, uid, gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot create the user directory [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Save the rules to the disk */ ++ for (size_t i = 0; i < rule_count; i++) { ++ ret = ipa_deskprofile_rules_save_rule_to_disk(tmp_ctx, ++ priority, ++ rules[i], ++ domain, ++ hostname, ++ username, ++ uid, ++ gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to save a Desktop Profile Rule to disk [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ /* Notify FleetCommander that our side is done */ ++ ret = ipa_pam_session_handler_notify_deskprofile_client(uid, ++ user_dir, ++ priority); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ipa_pam_session_handler_notify_deskprofile_client() " ++ "failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static DBusConnection * ++ipa_deskprofile_client_connect(void) ++{ ++ DBusConnection *conn; ++ DBusError error; ++ ++ dbus_error_init(&error); ++ conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); ++ if (dbus_error_is_set(&error)) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to connect to the FleetCommanderClient bus [%s]: %s\n", ++ error.name, error.message); ++ conn = NULL; ++ goto done; ++ } ++ ++done: ++ dbus_error_free(&error); ++ return conn; ++} ++ ++static errno_t ++ipa_pam_session_handler_notify_deskprofile_client(uid_t uid, ++ const char *user_dir, ++ uint16_t prio) ++{ ++ DBusConnection *conn = NULL; ++ DBusMessage *msg = NULL; ++ DBusError error; ++ errno_t ret; ++ bool dbus_ret; ++ ++ dbus_error_init(&error); ++ ++ conn = ipa_deskprofile_client_connect(); ++ if (conn == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ ++ msg = sbus_create_message(NULL, ++ SSS_FLEETCOMMANDERCLIENT_BUS, ++ SSS_FLEETCOMMANDERCLIENT_PATH, ++ SSS_FLEETCOMMANDERCLIENT_IFACE, ++ "ProcessSSSDFiles", ++ DBUS_TYPE_UINT32, &uid, ++ DBUS_TYPE_STRING, &user_dir, ++ DBUS_TYPE_UINT16, &prio); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus Message!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ dbus_ret = dbus_connection_send(conn, msg, NULL); ++ if (dbus_ret == FALSE) { ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (msg != NULL) { ++ dbus_message_unref(msg); ++ } ++ ++ if (conn != NULL) { ++ dbus_connection_unref(conn); ++ } ++ ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_session.h b/src/providers/ipa/ipa_session.h +new file mode 100644 +index 0000000000000000000000000000000000000000..aac99844df0c0d158b63ad67bd89896611891551 +--- /dev/null ++++ b/src/providers/ipa/ipa_session.h +@@ -0,0 +1,52 @@ ++/* ++ SSSD ++ ++ IPA Backend Module -- Session Management ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_SESSION_H_ ++#define IPA_SESSION_H_ ++ ++#include "providers/ldap/ldap_common.h" ++ ++struct ipa_session_ctx { ++ struct sdap_id_ctx *sdap_ctx; ++ struct dp_option *ipa_options; ++ time_t last_update; ++ ++ struct sdap_attr_map *host_map; ++ struct sdap_attr_map *hostgroup_map; ++ struct sdap_search_base **deskprofile_search_bases; ++ struct sdap_search_base **host_search_bases; ++}; ++ ++struct tevent_req * ++ipa_pam_session_handler_send(TALLOC_CTX *mem_ctx, ++ struct ipa_session_ctx *session_ctx, ++ struct pam_data *pd, ++ struct dp_req_params *params); ++ ++errno_t ++ipa_pam_session_handler_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct pam_data **_data); ++ ++#endif /* IPA_SESSION_H_ */ +diff --git a/src/responder/ifp/ifp_components.c b/src/responder/ifp/ifp_components.c +index 0cd6ba59f866b30a7bb979fbf179b7043de3d5d0..a4cc649c21e4f7d35f5703886916653f8c2d5786 100644 +--- a/src/responder/ifp/ifp_components.c ++++ b/src/responder/ifp/ifp_components.c +@@ -590,7 +590,8 @@ void ifp_backend_get_providers(struct sbus_request *dbus_req, + CONFDB_DOMAIN_AUTOFS_PROVIDER, + CONFDB_DOMAIN_SELINUX_PROVIDER, + CONFDB_DOMAIN_HOSTID_PROVIDER, +- CONFDB_DOMAIN_SUBDOMAINS_PROVIDER}; ++ CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, ++ CONFDB_DOMAIN_SESSION_PROVIDER}; + int num_providers = sizeof(providers) / sizeof(providers[0]); + errno_t ret; + int i; +-- +2.14.1 + diff --git a/0054-HBAC-Fix-tevent-hierarchy-in-ipa_hbac_rule_info_send.patch b/0054-HBAC-Fix-tevent-hierarchy-in-ipa_hbac_rule_info_send.patch new file mode 100644 index 0000000..6507655 --- /dev/null +++ b/0054-HBAC-Fix-tevent-hierarchy-in-ipa_hbac_rule_info_send.patch @@ -0,0 +1,132 @@ +From b054e7d8c43b024ee33e9343b4a15e124861f68c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 00:09:43 +0200 +Subject: [PATCH 54/93] HBAC: Fix tevent hierarchy in ipa_hbac_rule_info_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The first thing a _send() function should o is call +`tevent_req_create()` in order to create both the state and the request +and then use the state as context for temporary data. + +Also, `tevent_req_create()` should be only function returning NULL from +the _send function, while all the other calls should goto immediate and +return the proper error, as they have a valid request. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 39 +++++++++++++++----------------------- + 1 file changed, 15 insertions(+), 24 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index c860905cc5544100be22ef74379895b3adb94173..b8d45351994e7af1c31558238de8b5910a6ee943 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -60,35 +60,32 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + size_t i; + struct tevent_req *req = NULL; + struct ipa_hbac_rule_state *state; +- TALLOC_CTX *tmp_ctx; + const char *host_dn; + char *host_dn_clean; + char *host_group_clean; + char *rule_filter; + const char **memberof_list; + ++ req = tevent_req_create(mem_ctx, &state, struct ipa_hbac_rule_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n"); ++ return NULL; ++ } ++ + if (ipa_host == NULL) { ++ ret = EINVAL; + DEBUG(SSSDBG_CRIT_FAILURE, "Missing host\n"); +- return NULL; ++ goto immediate; + } + +- tmp_ctx = talloc_new(mem_ctx); +- if (tmp_ctx == NULL) return NULL; +- + ret = sysdb_attrs_get_string(ipa_host, SYSDB_ORIG_DN, &host_dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify IPA hostname\n"); +- goto error; ++ goto immediate; + } + +- ret = sss_filter_sanitize(tmp_ctx, host_dn, &host_dn_clean); +- if (ret != EOK) goto error; +- +- req = tevent_req_create(mem_ctx, &state, struct ipa_hbac_rule_state); +- if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n"); +- goto error; +- } ++ ret = sss_filter_sanitize(state, host_dn, &host_dn_clean); ++ if (ret != EOK) goto immediate; + + state->ev = ev; + state->sh = sh; +@@ -116,7 +113,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + state->attrs[13] = IPA_HOST_CATEGORY; + state->attrs[14] = NULL; + +- rule_filter = talloc_asprintf(tmp_ctx, ++ rule_filter = talloc_asprintf(state, + "(&(objectclass=%s)" + "(%s=%s)(%s=%s)" + "(|(%s=%s)(%s=%s)", +@@ -132,12 +129,12 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + + /* Add all parent groups of ipa_hostname to the filter */ + ret = sysdb_attrs_get_string_array(ipa_host, SYSDB_ORIG_MEMBEROF, +- tmp_ctx, &memberof_list); ++ state, &memberof_list); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify.\n"); + } if (ret == ENOENT) { + /* This host is not a member of any hostgroups */ +- memberof_list = talloc_array(tmp_ctx, const char *, 1); ++ memberof_list = talloc_array(state, const char *, 1); + if (memberof_list == NULL) { + ret = ENOMEM; + goto immediate; +@@ -146,7 +143,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + } + + for (i = 0; memberof_list[i]; i++) { +- ret = sss_filter_sanitize(tmp_ctx, ++ ret = sss_filter_sanitize(state, + memberof_list[i], + &host_group_clean); + if (ret != EOK) goto immediate; +@@ -176,7 +173,6 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- talloc_free(tmp_ctx); + return req; + + immediate: +@@ -186,12 +182,7 @@ immediate: + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); +- talloc_free(tmp_ctx); + return req; +- +-error: +- talloc_free(tmp_ctx); +- return NULL; + } + + static errno_t +-- +2.14.1 + diff --git a/0055-HBAC-Document-ipa_hbac_rule_info_next-s-behaviour.patch b/0055-HBAC-Document-ipa_hbac_rule_info_next-s-behaviour.patch new file mode 100644 index 0000000..47815ed --- /dev/null +++ b/0055-HBAC-Document-ipa_hbac_rule_info_next-s-behaviour.patch @@ -0,0 +1,42 @@ +From 9d98e98ab37d86323034e7bc342f196b81fa07bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 00:19:56 +0200 +Subject: [PATCH 55/93] HBAC: Document ipa_hbac_rule_info_next()'s behaviour +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's add a comment on ipa_hbac_rule_info_send() in order to have +cleaner why ret is set to EINVAL when ipa_hbac_rule_info_next() returns +EOK. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index b8d45351994e7af1c31558238de8b5910a6ee943..cb5a716aa809ebd80891cb8508bc136a788e49f1 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -166,6 +166,14 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + + ret = ipa_hbac_rule_info_next(req, state); + if (ret == EOK) { ++ /* ipa_hbac_rule_info_next should always have a search base when called ++ * for the first time. ++ * ++ * For the subsequent iterations, not finding any more search bases is ++ * fine though (thus the function returns EOK). ++ * ++ * As, here, it's the first case happening, let's return EINVAL. ++ */ + ret = EINVAL; + } + +-- +2.14.1 + diff --git a/0056-HBAC-Remove-a-cosmetic-extra-space-from-an-if-clause.patch b/0056-HBAC-Remove-a-cosmetic-extra-space-from-an-if-clause.patch new file mode 100644 index 0000000..df6e070 --- /dev/null +++ b/0056-HBAC-Remove-a-cosmetic-extra-space-from-an-if-clause.patch @@ -0,0 +1,32 @@ +From c9e104f17b6c4cf5741dea9fdbe864619125fab1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 00:22:42 +0200 +Subject: [PATCH 56/93] HBAC: Remove a cosmetic extra space from an if clause +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index cb5a716aa809ebd80891cb8508bc136a788e49f1..404778da338f872c2b51c3d3539e7394e97385ab 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -201,7 +201,7 @@ ipa_hbac_rule_info_next(struct tevent_req *req, + struct sdap_search_base *base; + + base = state->search_bases[state->search_base_iter]; +- if (base == NULL) { ++ if (base == NULL) { + return EOK; + } + +-- +2.14.1 + diff --git a/0057-HBAC-Improve-readability-of-ipa_hbac_rule_info_send.patch b/0057-HBAC-Improve-readability-of-ipa_hbac_rule_info_send.patch new file mode 100644 index 0000000..7093bac --- /dev/null +++ b/0057-HBAC-Improve-readability-of-ipa_hbac_rule_info_send.patch @@ -0,0 +1,58 @@ +From dd6a4fb9ae4825caf4ccb835f8b8221c96bbb6f5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 08:02:32 +0200 +Subject: [PATCH 57/93] HBAC: Improve readability of ipa_hbac_rule_info_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move an if condition inside another if condition in order to make the +readability a little bit more clear that those checks are about the same +return code. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index 404778da338f872c2b51c3d3539e7394e97385ab..d188971aa85dacf928657f5402dd96f66a6a521e 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -165,19 +165,18 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + state->rules_filter = talloc_steal(state, rule_filter); + + ret = ipa_hbac_rule_info_next(req, state); +- if (ret == EOK) { +- /* ipa_hbac_rule_info_next should always have a search base when called +- * for the first time. +- * +- * For the subsequent iterations, not finding any more search bases is +- * fine though (thus the function returns EOK). +- * +- * As, here, it's the first case happening, let's return EINVAL. +- */ +- ret = EINVAL; +- } +- + if (ret != EAGAIN) { ++ if (ret == EOK) { ++ /* ipa_hbac_rule_info_next should always have a search base when ++ * called for the first time. ++ * ++ * For the subsequent iterations, not finding any more search bases ++ * is fine though (thus the function returns EOK). ++ * ++ * As, here, it's the first case happening, let's return EINVAL. ++ */ ++ ret = EINVAL; ++ } + goto immediate; + } + +-- +2.14.1 + diff --git a/0058-HBAC-Enforce-coding-style-on-ipa_hbac_rule_info_send.patch b/0058-HBAC-Enforce-coding-style-on-ipa_hbac_rule_info_send.patch new file mode 100644 index 0000000..bb4244a --- /dev/null +++ b/0058-HBAC-Enforce-coding-style-on-ipa_hbac_rule_info_send.patch @@ -0,0 +1,35 @@ +From 4b37ee7d370003514916c793046577ea4b6e736b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 00:27:36 +0200 +Subject: [PATCH 58/93] HBAC: Enforce coding style on ipa_hbac_rule_info_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use if-else if-else statements instead of using severel different if +statements. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index d188971aa85dacf928657f5402dd96f66a6a521e..5a52a8362662ac6457f3578dc25e74aec2e4ddd4 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -132,7 +132,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + state, &memberof_list); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify.\n"); +- } if (ret == ENOENT) { ++ } else if (ret == ENOENT) { + /* This host is not a member of any hostgroups */ + memberof_list = talloc_array(state, const char *, 1); + if (memberof_list == NULL) { +-- +2.14.1 + diff --git a/0059-HBAC-Enforce-coding-style-ipa_hbac_rule_info_recv.patch b/0059-HBAC-Enforce-coding-style-ipa_hbac_rule_info_recv.patch new file mode 100644 index 0000000..454af3d --- /dev/null +++ b/0059-HBAC-Enforce-coding-style-ipa_hbac_rule_info_recv.patch @@ -0,0 +1,61 @@ +From 684a13e8de1526257ca2e40b6bf2e05585d4eaca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 3 Aug 2017 00:32:59 +0200 +Subject: [PATCH 59/93] HBAC: Enforce coding style ipa_hbac_rule_info_recv() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +By convention, the output variables are prefixed with a underscore. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 8 ++++---- + src/providers/ipa/ipa_hbac_rules.h | 4 ++-- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index 5a52a8362662ac6457f3578dc25e74aec2e4ddd4..2a30750b6b54a1e68ae435f12d8bf21d178025f0 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -297,16 +297,16 @@ fail: + errno_t + ipa_hbac_rule_info_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, +- size_t *rule_count, +- struct sysdb_attrs ***rules) ++ size_t *_rule_count, ++ struct sysdb_attrs ***_rules) + { + struct ipa_hbac_rule_state *state = + tevent_req_data(req, struct ipa_hbac_rule_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + +- *rule_count = state->rule_count; +- *rules = talloc_steal(mem_ctx, state->rules); ++ *_rule_count = state->rule_count; ++ *_rules = talloc_steal(mem_ctx, state->rules); + + return EOK; + } +diff --git a/src/providers/ipa/ipa_hbac_rules.h b/src/providers/ipa/ipa_hbac_rules.h +index 732ea483e5385d20a7874370fa7b07270e562b98..d8e5a147c948461c63af9a379b21815ecd015bd4 100644 +--- a/src/providers/ipa/ipa_hbac_rules.h ++++ b/src/providers/ipa/ipa_hbac_rules.h +@@ -35,7 +35,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + errno_t + ipa_hbac_rule_info_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, +- size_t *rule_count, +- struct sysdb_attrs ***rules); ++ size_t *_rule_count, ++ struct sysdb_attrs ***_rules); + + #endif /* IPA_HBAC_RULES_H_ */ +-- +2.14.1 + diff --git a/0060-HBAC-Add-a-debug-message-in-case-ipa_hbac_rule_info_.patch b/0060-HBAC-Add-a-debug-message-in-case-ipa_hbac_rule_info_.patch new file mode 100644 index 0000000..98ee8a4 --- /dev/null +++ b/0060-HBAC-Add-a-debug-message-in-case-ipa_hbac_rule_info_.patch @@ -0,0 +1,32 @@ +From 85a93ca67ae020607006cd035170c9360fb0a450 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 16 Aug 2017 08:16:46 +0200 +Subject: [PATCH 60/93] HBAC: Add a debug message in case + ipa_hbac_rule_info_next() fails +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index 2a30750b6b54a1e68ae435f12d8bf21d178025f0..62501615150c52fe823f756a5dfbe2eb9a5a1a97 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -175,6 +175,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, + * + * As, here, it's the first case happening, let's return EINVAL. + */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "No search base found\n"); + ret = EINVAL; + } + goto immediate; +-- +2.14.1 + diff --git a/0061-HBAC-Not-having-rules-should-not-be-logged-as-error.patch b/0061-HBAC-Not-having-rules-should-not-be-logged-as-error.patch new file mode 100644 index 0000000..d98e41a --- /dev/null +++ b/0061-HBAC-Not-having-rules-should-not-be-logged-as-error.patch @@ -0,0 +1,34 @@ +From 85517b57685809ff96818bbd3e3b4678ac74b461 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 16 Aug 2017 08:19:43 +0200 +Subject: [PATCH 61/93] HBAC: Not having rules should not be logged as error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's tone down the debug level to TRACE_FUNC instead of MINOR_FAILURE. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_hbac_rules.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index 62501615150c52fe823f756a5dfbe2eb9a5a1a97..0634a277e244fad98a84789ad5ab630ae632413f 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -281,7 +281,7 @@ ipa_hbac_rule_info_done(struct tevent_req *subreq) + } else if (ret != EOK) { + goto fail; + } else if (ret == EOK && state->rule_count == 0) { +- DEBUG(SSSDBG_MINOR_FAILURE, "No rules apply to this host\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "No rules apply to this host\n"); + tevent_req_error(req, ENOENT); + return; + } +-- +2.14.1 + diff --git a/0062-DESKPROFILE-Add-ipa_deskprofile_request_interval.patch b/0062-DESKPROFILE-Add-ipa_deskprofile_request_interval.patch new file mode 100644 index 0000000..673f0f1 --- /dev/null +++ b/0062-DESKPROFILE-Add-ipa_deskprofile_request_interval.patch @@ -0,0 +1,211 @@ +From 4a311702045b065a97a0c0fc0ccc7a1fc84b38cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 17 Aug 2017 19:49:22 +0200 +Subject: [PATCH 62/93] DESKPROFILE: Add ipa_deskprofile_request_interval +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This option has been added to avoid contacting the Data Provider when no +rules were found in the previous request. + +By adding this configurable option we avoid contacting the Data Provider +too often in the case described above and also when the server doesn't +support Desktop Profile's integration. + +Resolves: https://pagure.io/SSSD/sssd/issue/3482 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +--- + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.d/sssd-ipa.conf | 1 + + src/man/sssd-ipa.5.xml | 14 ++++++++++++++ + src/providers/ipa/ipa_common.h | 1 + + src/providers/ipa/ipa_opts.c | 1 + + src/providers/ipa/ipa_session.c | 33 ++++++++++++++++++++++++++++++++- + src/providers/ipa/ipa_session.h | 2 ++ + 8 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 2a19b60a987c5f2c5c59ac2466f8f6821803e146..8c56e4efa4ae7c648f670bb6a67290b6e835f581 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -220,6 +220,7 @@ option_strings = { + 'ipa_group_override_object_class': _("Objectclass for group override objects"), + 'ipa_deskprofile_search_base': _("Search base for Desktop Profile related objects"), + 'ipa_deskprofile_refresh': _("The amount of time in seconds between lookups of the Desktop Profile rules against the IPA server"), ++ 'ipa_deskprofile_request_interval': _("The amount of time in minutes between lookups of Desktop Profiles rules against the IPA server when the last request did not find any rule"), + + # [provider/ad] + 'ad_domain' : _('Active Directory domain'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 3ebd39e93cec6d1ddf547d7ebdb49884e637f8c7..ae60c73c871e1ac18a26124232e1f9f7c9f8fabb 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -440,6 +440,7 @@ option = ipa_anchor_uuid + option = ipa_automount_location + option = ipa_backup_server + option = ipa_deskprofile_refresh ++option = ipa_deskprofile_request_interval + option = ipa_deskprofile_search_base + option = ipa_domain + option = ipa_dyndns_iface +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index 8178b123e3b42cb92029db8b879d26f1fd16cf3e..ab9634c7a69026099fcc8f59aa26a89a43671f0a 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -195,6 +195,7 @@ ldap_autofs_search_base = str, None, false + + [provider/ipa/session] + ipa_deskprofile_refresh = int, None, false ++ipa_deskprofile_request_interval = int, None, false + ipa_host_object_class = str, None, false + ipa_host_name = str, None, false + ipa_host_fqdn = str, None, false +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index 4d1c3c8a11dea956c31be690f5bdceea94252fd2..4cf07142c53798ea154032bdc560a8160e1c585a 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -476,6 +476,20 @@ + + + ++ ++ ipa_deskprofile_request_interval (integer) ++ ++ ++ The amount of time between lookups of the Desktop ++ Profile rules against the IPA server in case the ++ last request did not return any rule. ++ ++ ++ Default: 60 (minutes) ++ ++ ++ ++ + + ipa_hbac_refresh (integer) + +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 5b3507cd47aab75a4a7bbc16a8146d82411f2d16..5197a9af08f86e042244c495cc37e728fae63cc5 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -58,6 +58,7 @@ enum ipa_basic_opt { + IPA_KRB5_CONFD_PATH, + IPA_DESKPROFILE_SEARCH_BASE, + IPA_DESKPROFILE_REFRESH, ++ IPA_DESKPROFILE_REQUEST_INTERVAL, + + IPA_OPTS_BASIC /* opts counter */ + }; +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index 4836445dad82c4d3ecaecc32d22cb6f9730f0fcb..09b78f726caa4efa4106ad741066018565f1ace1 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -50,6 +50,7 @@ struct dp_option ipa_basic_opts[] = { + { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING }, + { "ipa_deskprofile_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ipa_deskprofile_refresh", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER }, ++ { "ipa_deskprofile_request_interval", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, + DP_OPTION_TERMINATOR + }; + +diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c +index 7adf8b6d7dfef9b2c29c1ee42f47842131773e90..8559284c9b453129400626e0cf93e70275e80301 100644 +--- a/src/providers/ipa/ipa_session.c ++++ b/src/providers/ipa/ipa_session.c +@@ -42,6 +42,8 @@ + #define SSS_FLEETCOMMANDERCLIENT_PATH "/org/freedesktop/FleetCommanderClient" + #define SSS_FLEETCOMMANDERCLIENT_IFACE "org.freedesktop.FleetCommanderClient" + ++#define MINUTE_IN_SECONDS 60 ++ + struct ipa_fetch_deskprofile_state { + struct tevent_context *ev; + struct be_ctx *be_ctx; +@@ -80,6 +82,8 @@ ipa_fetch_deskprofile_send(TALLOC_CTX *mem_ctx, + struct tevent_req *req; + time_t now; + time_t refresh_interval; ++ time_t request_interval; ++ time_t next_request; + bool offline; + errno_t ret; + +@@ -122,13 +126,34 @@ ipa_fetch_deskprofile_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + ++ now = time(NULL); ++ ++ request_interval = dp_opt_get_int(state->ipa_options, ++ IPA_DESKPROFILE_REQUEST_INTERVAL); ++ /* This value is in minutes ... */ ++ request_interval *= MINUTE_IN_SECONDS; ++ ++ if (state->session_ctx->no_rules_found && ++ now < session_ctx->last_request + request_interval) { ++ next_request = (session_ctx->last_request + request_interval - now); ++ /* This value is in seconds ... */ ++ next_request /= 60; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "No rules were found in the last request.\n" ++ "Next request will happen in any login after %"PRIu64" minutes\n", ++ next_request); ++ ret = ENOENT; ++ goto immediately; ++ } ++ ++ state->session_ctx->no_rules_found = false; ++ + offline = be_is_offline(be_ctx); + DEBUG(SSSDBG_TRACE_ALL, "Connection status is [%s].\n", + offline ? "offline" : "online"); + + refresh_interval = dp_opt_get_int(state->ipa_options, + IPA_DESKPROFILE_REFRESH); +- now = time(NULL); + + if (offline || now < session_ctx->last_update + refresh_interval) { + DEBUG(SSSDBG_TRACE_FUNC, +@@ -540,6 +565,10 @@ ipa_pam_session_handler_done(struct tevent_req *subreq) + + if (ret == ENOENT) { + DEBUG(SSSDBG_IMPORTANT_INFO, "No Desktop Profile rules found\n"); ++ if (!state->session_ctx->no_rules_found) { ++ state->session_ctx->no_rules_found = true; ++ state->session_ctx->last_request = time(NULL); ++ } + state->pd->pam_status = PAM_SUCCESS; + goto done; + } else if (ret != EOK) { +@@ -550,6 +579,8 @@ ipa_pam_session_handler_done(struct tevent_req *subreq) + goto done; + } + ++ state->session_ctx->last_request = time(NULL); ++ + hostname = dp_opt_get_string(state->session_ctx->ipa_options, IPA_HOSTNAME); + ret = ipa_pam_session_handler_save_deskprofile_rules(state->be_ctx, + state->be_ctx->domain, +diff --git a/src/providers/ipa/ipa_session.h b/src/providers/ipa/ipa_session.h +index aac99844df0c0d158b63ad67bd89896611891551..0c4d54f8555dd1eeaca43299500b12b1d81b872f 100644 +--- a/src/providers/ipa/ipa_session.h ++++ b/src/providers/ipa/ipa_session.h +@@ -31,6 +31,8 @@ struct ipa_session_ctx { + struct sdap_id_ctx *sdap_ctx; + struct dp_option *ipa_options; + time_t last_update; ++ time_t last_request; ++ bool no_rules_found; + + struct sdap_attr_map *host_map; + struct sdap_attr_map *hostgroup_map; +-- +2.14.1 + diff --git a/0063-NEGCACHE-Add-some-comments-about-each-step-of-sss_nc.patch b/0063-NEGCACHE-Add-some-comments-about-each-step-of-sss_nc.patch new file mode 100644 index 0000000..6c461d5 --- /dev/null +++ b/0063-NEGCACHE-Add-some-comments-about-each-step-of-sss_nc.patch @@ -0,0 +1,61 @@ +From b54d79cf3c8017e186b5ea7cdc383746233db39b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 15:28:41 +0200 +Subject: [PATCH 63/93] NEGCACHE: Add some comments about each step of + sss_ncache_prepopulate() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The comments help to understand which part of the code is dealing with +users or groups of specific or non-specific domain filters. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/negcache.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index 084c47aa8a0cfec88edf8e3e30e94299792feeb5..376c3e6565f218067b57f564ffab06f40e0ae0ca 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -786,7 +786,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + return ENOMEM; + } + +- /* Populate domain-specific negative cache entries */ ++ /* Populate domain-specific negative cache user entries */ + for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { + conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, + dom->name); +@@ -844,6 +844,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ /* Populate non domain-specific negative cache user entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_USERS, &filter_list); + if (ret == ENOENT) { +@@ -920,6 +921,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ /* Populate domain-specific negative cache group entries */ + filter_set = false; + for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { + conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name); +@@ -970,6 +972,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ /* Populate non domain-specific negative cache group entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_GROUPS, &filter_list); + if (ret == ENOENT) { +-- +2.14.1 + diff --git a/0064-NEGCACHE-Always-add-root-to-the-negative-cache.patch b/0064-NEGCACHE-Always-add-root-to-the-negative-cache.patch new file mode 100644 index 0000000..ffb2877 --- /dev/null +++ b/0064-NEGCACHE-Always-add-root-to-the-negative-cache.patch @@ -0,0 +1,170 @@ +From 1e7b7da3aa56060c26f8ba1c08318cdee77753ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 15:46:10 +0200 +Subject: [PATCH 64/93] NEGCACHE: Always add "root" to the negative cache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current code only adds "root" to the negative cache in case there's +any other user or group set up in to be added. + +As SSSD doesn't handle "root", it should *always* be added to the +negative cache. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/negcache.c | 88 +++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 34 deletions(-) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index 376c3e6565f218067b57f564ffab06f40e0ae0ca..fc5ae76bce2daf0575d19c89fcd4682f771cc0a2 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -771,8 +771,8 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + struct resp_ctx *rctx) + { + errno_t ret; +- bool filter_set = false; + char **filter_list = NULL; ++ char **default_list = NULL; + char *name = NULL; + struct sss_domain_info *dom = NULL; + struct sss_domain_info *domain_list = rctx->domains; +@@ -801,7 +801,6 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + &filter_list); + if (ret == ENOENT) continue; + if (ret != EOK) goto done; +- filter_set = true; + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +@@ -847,22 +846,9 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + /* Populate non domain-specific negative cache user entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_USERS, &filter_list); +- if (ret == ENOENT) { +- if (!filter_set) { +- filter_list = talloc_array(tmpctx, char *, 2); +- if (!filter_list) { +- ret = ENOMEM; +- goto done; +- } +- filter_list[0] = talloc_strdup(tmpctx, "root"); +- if (!filter_list[0]) { +- ret = ENOMEM; +- goto done; +- } +- filter_list[1] = NULL; +- } ++ if (ret != EOK && ret != ENOENT) { ++ goto done; + } +- else if (ret != EOK) goto done; + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +@@ -922,7 +908,6 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + + /* Populate domain-specific negative cache group entries */ +- filter_set = false; + for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { + conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name); + if (!conf_path) { +@@ -935,7 +920,6 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + CONFDB_NSS_FILTER_GROUPS, &filter_list); + if (ret == ENOENT) continue; + if (ret != EOK) goto done; +- filter_set = true; + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name(tmpctx, dom->names, filter_list[i], +@@ -975,22 +959,9 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + /* Populate non domain-specific negative cache group entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_GROUPS, &filter_list); +- if (ret == ENOENT) { +- if (!filter_set) { +- filter_list = talloc_array(tmpctx, char *, 2); +- if (!filter_list) { +- ret = ENOMEM; +- goto done; +- } +- filter_list[0] = talloc_strdup(tmpctx, "root"); +- if (!filter_list[0]) { +- ret = ENOMEM; +- goto done; +- } +- filter_list[1] = NULL; +- } ++ if (ret != EOK && ret != ENOENT) { ++ goto done; + } +- else if (ret != EOK) goto done; + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +@@ -1049,6 +1020,55 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ /* SSSD doesn't handle "root", thus it'll be added to the negative cache ++ * nonetheless what's already added there. */ ++ default_list = talloc_array(tmpctx, char *, 2); ++ if (default_list == NULL) { ++ ret= ENOMEM; ++ goto done; ++ } ++ default_list[0] = talloc_strdup(tmpctx, "root"); ++ if (default_list[0] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ default_list[1] = NULL; ++ ++ /* Populate negative cache users and groups entries for the ++ * "default_list" */ ++ for (i = 0; (default_list != NULL && default_list[i] != NULL); i++) { ++ for (dom = domain_list; ++ dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { ++ fqname = sss_create_internal_fqname(tmpctx, ++ default_list[i], ++ dom->name); ++ if (fqname == NULL) { ++ continue; ++ } ++ ++ ret = sss_ncache_set_user(ncache, true, dom, fqname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to store permanent user filter for" ++ " [%s:%s] (%d [%s])\n", ++ dom->name, default_list[i], ++ ret, strerror(ret)); ++ continue; ++ } ++ ++ ret = sss_ncache_set_group(ncache, true, dom, fqname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to store permanent group filter for" ++ " [%s:%s] (%d [%s])\n", ++ dom->name, default_list[i], ++ ret, strerror(ret)); ++ continue; ++ } ++ } ++ } ++ + ret = EOK; + + done: +-- +2.14.1 + diff --git a/0065-TEST_NEGCACHE-Test-that-root-is-always-added-to-ncac.patch b/0065-TEST_NEGCACHE-Test-that-root-is-always-added-to-ncac.patch new file mode 100644 index 0000000..2c9dddf --- /dev/null +++ b/0065-TEST_NEGCACHE-Test-that-root-is-always-added-to-ncac.patch @@ -0,0 +1,43 @@ +From e54764d62bfcc48770d9b2578132979aa58636e5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 16 Aug 2017 10:45:19 +0200 +Subject: [PATCH 65/93] TEST_NEGCACHE: Test that "root" is always added to + ncache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Simply modify test_sss_ncache_prepopulate() in order to ensure that +"root" user and group are always added to the negative cache, no matter +whether they're set as part of the filter_users or filter_groups +options. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/tests/cmocka/test_negcache.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c +index d608c20ad3248c80e68029c8c27b826395a61ddc..163e4653e0aa423eb5ccc4206734dec3a40050e6 100644 +--- a/src/tests/cmocka/test_negcache.c ++++ b/src/tests/cmocka/test_negcache.c +@@ -630,6 +630,12 @@ static void test_sss_ncache_prepopulate(void **state) + + ret = check_group_in_ncache(ncache, dom, "testgroup3@somedomain"); + assert_int_equal(ret, ENOENT); ++ ++ ret = check_user_in_ncache(ncache, dom, "root"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_group_in_ncache(ncache, dom, "root"); ++ assert_int_equal(ret, EEXIST); + } + + static void test_sss_ncache_default_domain_suffix(void **state) +-- +2.14.1 + diff --git a/0066-NEGCACHE-Descend-to-all-subdomains-when-adding-user-.patch b/0066-NEGCACHE-Descend-to-all-subdomains-when-adding-user-.patch new file mode 100644 index 0000000..9716f04 --- /dev/null +++ b/0066-NEGCACHE-Descend-to-all-subdomains-when-adding-user-.patch @@ -0,0 +1,50 @@ +From 9908bdc9755e744c3e2c7c746a4edf95f9083ef5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 12:15:42 +0200 +Subject: [PATCH 66/93] NEGCACHE: Descend to all subdomains when adding + user/groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a user or group is added to the negative cache, we should descend +to all subdomains as well. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/negcache.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index fc5ae76bce2daf0575d19c89fcd4682f771cc0a2..00487a2245b12f084714c60d850dc837d43d9d43 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -887,7 +887,9 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + continue; + } + } else { +- for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { ++ for (dom = domain_list; ++ dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { + fqname = sss_create_internal_fqname(tmpctx, name, dom->name); + if (fqname == NULL) { + continue; +@@ -1000,7 +1002,9 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + continue; + } + } else { +- for (dom = domain_list; dom; dom = get_next_domain(dom, 0)) { ++ for (dom = domain_list; ++ dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { + fqname = sss_create_internal_fqname(tmpctx, name, dom->name); + if (fqname == NULL) { + continue; +-- +2.14.1 + diff --git a/0067-CACHE_REQ-Don-t-error-out-when-searching-by-id-0.patch b/0067-CACHE_REQ-Don-t-error-out-when-searching-by-id-0.patch new file mode 100644 index 0000000..05f3305 --- /dev/null +++ b/0067-CACHE_REQ-Don-t-error-out-when-searching-by-id-0.patch @@ -0,0 +1,43 @@ +From 8888d7a46371ddd2c2514c3e81b58bb1090902a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 13:35:20 +0200 +Subject: [PATCH 67/93] CACHE_REQ: Don't error out when searching by id = 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This code path can be easily triggered by calling `id 0` and SSSD should +not error out in this case. + +Previous patches in this series already add uid and gid 0 to the +negative cache and we can properly handle this situation. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/cache_req/cache_req_data.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c +index 5ab1493b81dbcd1529f1124a2bb1f99d3ae82281..8726e139ffeaaf876f162f6048c86c2145db8662 100644 +--- a/src/responder/common/cache_req/cache_req_data.c ++++ b/src/responder/common/cache_req/cache_req_data.c +@@ -119,12 +119,6 @@ cache_req_data_create(TALLOC_CTX *mem_ctx, + case CACHE_REQ_USER_BY_ID: + case CACHE_REQ_GROUP_BY_ID: + case CACHE_REQ_OBJECT_BY_ID: +- if (input->id == 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0!\n"); +- ret = ERR_INTERNAL; +- goto done; +- } +- + data->id = input->id; + break; + case CACHE_REQ_OBJECT_BY_SID: +-- +2.14.1 + diff --git a/0068-NSS-Don-t-error-out-when-deleting-an-entry-which-has.patch b/0068-NSS-Don-t-error-out-when-deleting-an-entry-which-has.patch new file mode 100644 index 0000000..654fdd8 --- /dev/null +++ b/0068-NSS-Don-t-error-out-when-deleting-an-entry-which-has.patch @@ -0,0 +1,45 @@ +From 431c7508e0d256b9c712cb9dcb9aa4cb635f4a0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 13:40:58 +0200 +Subject: [PATCH 68/93] NSS: Don't error out when deleting an entry which has + id = 0 from the memcache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This code path can be easily triggered by calling `id 0` after applying +the previous patch in this series and SSSD should not error out in this +case. + +As SSSD doesn't handle "root", this entry never will be part of the +memcache and EOK can be safely returned there. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nss_get_object.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c +index 9058793ea2d72b57003a7219414af6a0f0c5b89e..e56480af5e3369963d2e8bb17d74d1603af8e014 100644 +--- a/src/responder/nss/nss_get_object.c ++++ b/src/responder/nss/nss_get_object.c +@@ -125,6 +125,12 @@ memcache_delete_entry(struct nss_ctx *nss_ctx, + name, dom->name); + continue; + } ++ } else if (id == 0) { ++ /* ++ * As "root" is not handled by SSSD, let's just return EOK here ++ * instead of erroring out. ++ */ ++ return EOK; + } else if (id != 0) { + ret = memcache_delete_entry_by_id(nss_ctx, id, type); + if (ret != EOK) { +-- +2.14.1 + diff --git a/0069-NEGCACHE-Add-root-s-uid-gid-to-ncache.patch b/0069-NEGCACHE-Add-root-s-uid-gid-to-ncache.patch new file mode 100644 index 0000000..c238517 --- /dev/null +++ b/0069-NEGCACHE-Add-root-s-uid-gid-to-ncache.patch @@ -0,0 +1,57 @@ +From 3ad33ca77044f9a9d18f7def271b0beb180e567b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 14 Aug 2017 13:31:45 +0200 +Subject: [PATCH 69/93] NEGCACHE: Add root's uid/gid to ncache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As "root" is not handled by SSSD, let's add its uid and gid to the +negative cache as well. The reason it's added without specifying a +domain is to follow how the negative cache is used by cache req's code +when searching something by id. + +As the negative cache check for uid/gid, in the cache req code, is done +after resolving the name, we can save one LDAP call to the data +provider. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/negcache.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index 00487a2245b12f084714c60d850dc837d43d9d43..b751d89ee9e67eea32ec4ed0935fcd67d3e92f47 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -1073,6 +1073,23 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ /* Also add "root" uid and gid to the negative cache */ ++ ret = sss_ncache_set_uid(ncache, true, NULL, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to store permanent uid filter for root (0) " ++ "(%d [%s])\n", ++ ret, strerror(ret)); ++ } ++ ++ ret = sss_ncache_set_gid(ncache, true, NULL, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to store permanent gid filter for root (0) " ++ "(%d [%s])\n", ++ ret, strerror(ret)); ++ } ++ + ret = EOK; + + done: +-- +2.14.1 + diff --git a/0070-TEST_NEGCACHE-Ensure-root-s-uid-and-gid-are-always-a.patch b/0070-TEST_NEGCACHE-Ensure-root-s-uid-and-gid-are-always-a.patch new file mode 100644 index 0000000..e7bf0e1 --- /dev/null +++ b/0070-TEST_NEGCACHE-Ensure-root-s-uid-and-gid-are-always-a.patch @@ -0,0 +1,67 @@ +From b4b3d0642120ca05f63959fe2f317a6b93031929 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 16 Aug 2017 10:51:47 +0200 +Subject: [PATCH 70/93] TEST_NEGCACHE: Ensure root's uid and gid are always + added to ncache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to do so two new functions have been introduced and +test_sss_ncache_prepopulate() has been modified in order to ensure that +root's uid and gid are always added to the negative cache. + +Related: https://pagure.io/SSSD/sssd/issue/3460 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/tests/cmocka/test_negcache.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c +index 163e4653e0aa423eb5ccc4206734dec3a40050e6..ba39f778d5ddc6a4e1708aef66fc2aa1c809f150 100644 +--- a/src/tests/cmocka/test_negcache.c ++++ b/src/tests/cmocka/test_negcache.c +@@ -564,6 +564,24 @@ static int check_group_in_ncache(struct sss_nc_ctx *ctx, + return ret; + } + ++static int check_uid_in_ncache(struct sss_nc_ctx *ctx, ++ uid_t uid) ++{ ++ int ret; ++ ++ ret = sss_ncache_check_uid(ctx, NULL, uid); ++ return ret; ++} ++ ++static int check_gid_in_ncache(struct sss_nc_ctx *ctx, ++ gid_t gid) ++{ ++ int ret; ++ ++ ret = sss_ncache_check_gid(ctx, NULL, gid); ++ return ret; ++} ++ + static void test_sss_ncache_prepopulate(void **state) + { + int ret; +@@ -636,6 +654,12 @@ static void test_sss_ncache_prepopulate(void **state) + + ret = check_group_in_ncache(ncache, dom, "root"); + assert_int_equal(ret, EEXIST); ++ ++ ret = check_uid_in_ncache(ncache, 0); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_gid_in_ncache(ncache, 0); ++ assert_int_equal(ret, EEXIST); + } + + static void test_sss_ncache_default_domain_suffix(void **state) +-- +2.14.1 + diff --git a/0071-TESTS-Add-wrappers-to-request-a-user-or-a-group-by-I.patch b/0071-TESTS-Add-wrappers-to-request-a-user-or-a-group-by-I.patch new file mode 100644 index 0000000..8cf58bb --- /dev/null +++ b/0071-TESTS-Add-wrappers-to-request-a-user-or-a-group-by-I.patch @@ -0,0 +1,150 @@ +From 137e105ac8ca3476d2f74d24ae13860774937000 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 22 Aug 2017 12:25:31 +0200 +Subject: [PATCH 71/93] TESTS: Add wrappers to request a user or a group by ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/tests/intg/sssd_group.py | 43 ++++++++++++++++++++++++++++++++++++++++++- + src/tests/intg/sssd_passwd.py | 43 ++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 84 insertions(+), 2 deletions(-) + +diff --git a/src/tests/intg/sssd_group.py b/src/tests/intg/sssd_group.py +index ab873a726d4c1c35ed00fe4c431566ecef648880..32d12cfae4dcc0bb560f168dcf4ac327deac3065 100644 +--- a/src/tests/intg/sssd_group.py ++++ b/src/tests/intg/sssd_group.py +@@ -52,6 +52,27 @@ def getgrnam_r(name, result_p, buffer_p, buflen): + return (int(res), int(errno[0]), result_p) + + ++def getgrgid_r(gid, result_p, buffer_p, buflen): ++ """ ++ ctypes wrapper for: ++ enum nss_status _nss_sss_getgrgid_r(gid_t gid, ++ struct passwd *result, ++ char *buffer, ++ size_t buflen, ++ int *errnop) ++ """ ++ func = nss_sss_ctypes_loader("_nss_sss_getgrgid_r") ++ func.restype = c_int ++ func.argtypes = [c_ulong, POINTER(Group), ++ c_char_p, c_ulong, POINTER(c_int)] ++ ++ errno = POINTER(c_int)(c_int(0)) ++ ++ res = func(gid, result_p, buffer_p, buflen, errno) ++ ++ return (int(res), int(errno[0]), result_p) ++ ++ + def set_group_dict(res, result_p): + if res != NssReturnCode.SUCCESS: + return dict() +@@ -72,7 +93,7 @@ def set_group_dict(res, result_p): + + def call_sssd_getgrnam(name): + """ +- A Python wrapper to retrieve a group. Returns: ++ A Python wrapper to retrieve a group by name. Returns: + (res, group_dict) + if res is NssReturnCode.SUCCESS, then group_dict contains the keys + corresponding to the C passwd structure fields. Otherwise, the dictionary +@@ -88,3 +109,23 @@ def call_sssd_getgrnam(name): + + group_dict = set_group_dict(res, result_p) + return res, group_dict ++ ++ ++def call_sssd_getgrgid(gid): ++ """ ++ A Python wrapper to retrieve a group by GID. Returns: ++ (res, group_dict) ++ if res is NssReturnCode.SUCCESS, then group_dict contains the keys ++ corresponding to the C passwd structure fields. Otherwise, the dictionary ++ is empty and errno indicates the error code ++ """ ++ result = Group() ++ result_p = POINTER(Group)(result) ++ buff = create_string_buffer(GROUP_BUFLEN) ++ ++ res, errno, result_p = getgrgid_r(gid, result_p, buff, GROUP_BUFLEN) ++ if errno != 0: ++ raise SssdNssError(errno, "getgrgid_r") ++ ++ group_dict = set_group_dict(res, result_p) ++ return res, group_dict +diff --git a/src/tests/intg/sssd_passwd.py b/src/tests/intg/sssd_passwd.py +index f285b4971d0d9e826bf6cb38ebefeaf1b4422187..e97b0c11b02b8cdd5d67229f19c34f9569c049bd 100644 +--- a/src/tests/intg/sssd_passwd.py ++++ b/src/tests/intg/sssd_passwd.py +@@ -70,6 +70,27 @@ def getpwnam_r(name, result_p, buffer_p, buflen): + return (int(res), int(errno[0]), result_p) + + ++def getpwuid_r(uid, result_p, buffer_p, buflen): ++ """ ++ ctypes wrapper for: ++ enum nss_status _nss_sss_getpwuid_r(uid_t uid, ++ struct passwd *result, ++ char *buffer, ++ size_t buflen, ++ int *errnop) ++ """ ++ func = nss_sss_ctypes_loader("_nss_sss_getpwuid_r") ++ func.restype = c_int ++ func.argtypes = [c_ulong, POINTER(Passwd), ++ c_char_p, c_ulong, POINTER(c_int)] ++ ++ errno = POINTER(c_int)(c_int(0)) ++ ++ res = func(uid, result_p, buffer_p, buflen, errno) ++ ++ return (int(res), int(errno[0]), result_p) ++ ++ + def setpwent(): + """ + ctypes wrapper for: +@@ -134,7 +155,7 @@ def getpwent(): + + def call_sssd_getpwnam(name): + """ +- A Python wrapper to retrieve a user. Returns: ++ A Python wrapper to retrieve a user by name. Returns: + (res, user_dict) + if res is NssReturnCode.SUCCESS, then user_dict contains the keys + corresponding to the C passwd structure fields. Otherwise, the dictionary +@@ -152,6 +173,26 @@ def call_sssd_getpwnam(name): + return res, user_dict + + ++def call_sssd_getpwuid(uid): ++ """ ++ A Python wrapper to retrieve a user by UID. Returns: ++ (res, user_dict) ++ if res is NssReturnCode.SUCCESS, then user_dict contains the keys ++ corresponding to the C passwd structure fields. Otherwise, the dictionary ++ is empty and errno indicates the error code ++ """ ++ result = Passwd() ++ result_p = POINTER(Passwd)(result) ++ buff = create_string_buffer(PASSWD_BUFLEN) ++ ++ res, errno, result_p = getpwuid_r(uid, result_p, buff, PASSWD_BUFLEN) ++ if errno != 0: ++ raise SssdNssError(errno, "getpwuid_r") ++ ++ user_dict = set_user_dict(res, result_p) ++ return res, user_dict ++ ++ + def call_sssd_enumeration(): + """ + enumerate users from sssd module only +-- +2.14.1 + diff --git a/0072-TESTS-Add-files-provider-tests-that-request-a-user-a.patch b/0072-TESTS-Add-files-provider-tests-that-request-a-user-a.patch new file mode 100644 index 0000000..c497927 --- /dev/null +++ b/0072-TESTS-Add-files-provider-tests-that-request-a-user-a.patch @@ -0,0 +1,204 @@ +From 5883b99fa0d13368f6e79fdb40b6637d36ed1801 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 22 Aug 2017 12:25:58 +0200 +Subject: [PATCH 72/93] TESTS: Add files provider tests that request a user and + group by ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/tests/intg/test_files_provider.py | 97 ++++++++++++++++++++++++++++++++--- + 1 file changed, 91 insertions(+), 6 deletions(-) + +diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py +index b26977e0610b85e1ba015d3dd98596f356004fa8..e507ea10d78b9b35ee57178e78f4621372d0c2e5 100644 +--- a/src/tests/intg/test_files_provider.py ++++ b/src/tests/intg/test_files_provider.py +@@ -29,8 +29,10 @@ import pytest + import ent + import sssd_id + from sssd_nss import NssReturnCode +-from sssd_passwd import call_sssd_getpwnam, call_sssd_enumeration +-from sssd_group import call_sssd_getgrnam ++from sssd_passwd import (call_sssd_getpwnam, ++ call_sssd_enumeration, ++ call_sssd_getpwuid) ++from sssd_group import call_sssd_getgrnam, call_sssd_getgrgid + from files_ops import passwd_ops_setup, group_ops_setup + from util import unindent + +@@ -258,6 +260,14 @@ def sssd_getpwnam_sync(name): + return call_sssd_getpwnam(name) + + ++def sssd_getpwuid_sync(uid): ++ ret = poll_canary(call_sssd_getpwnam, CANARY["name"]) ++ if ret is False: ++ return NssReturnCode.NOTFOUND, None ++ ++ return call_sssd_getpwuid(uid) ++ ++ + def sssd_getgrnam_sync(name): + ret = poll_canary(call_sssd_getgrnam, CANARY_GR["name"]) + if ret is False: +@@ -266,6 +276,14 @@ def sssd_getgrnam_sync(name): + return call_sssd_getgrnam(name) + + ++def sssd_getgrgid_sync(name): ++ ret = poll_canary(call_sssd_getgrnam, CANARY_GR["name"]) ++ if ret is False: ++ return NssReturnCode.NOTFOUND, None ++ ++ return call_sssd_getgrgid(name) ++ ++ + def sssd_id_sync(name): + sssd_getpwnam_sync(CANARY["name"]) + res, _, groups = sssd_id.get_user_groups(name) +@@ -307,6 +325,15 @@ def check_group(exp_group, delay=1.0): + assert found_group == exp_group + + ++def check_group_by_gid(exp_group, delay=1.0): ++ if delay > 0: ++ time.sleep(delay) ++ ++ res, found_group = sssd_getgrgid_sync(exp_group["gid"]) ++ assert res == NssReturnCode.SUCCESS ++ assert found_group == exp_group ++ ++ + def check_group_list(exp_groups_list): + for exp_group in exp_groups_list: + check_group(exp_group) +@@ -349,6 +376,16 @@ def test_getpwnam_after_start(add_user_with_canary, files_domain_only): + assert user == USER1 + + ++def test_getpwuid_after_start(add_user_with_canary, files_domain_only): ++ """ ++ Test that after startup without any additional operations, a user ++ can be resolved through sssd ++ """ ++ res, user = sssd_getpwuid_sync(USER1["uid"]) ++ assert res == NssReturnCode.SUCCESS ++ assert user == USER1 ++ ++ + def test_user_overriden(add_user_with_canary, files_domain_only): + """ + Test that user override works with files domain only +@@ -373,8 +410,8 @@ def test_group_overriden(add_group_with_canary, files_domain_only): + """ + # Override + subprocess.check_call(["sss_override", "group-add", GROUP1["name"], +- "-n", OV_GROUP1["name"], +- "-g", str(OV_GROUP1["gid"])]) ++ "-n", OV_GROUP1["name"], ++ "-g", str(OV_GROUP1["gid"])]) + + restart_sssd() + +@@ -383,12 +420,20 @@ def test_group_overriden(add_group_with_canary, files_domain_only): + + def test_getpwnam_neg(files_domain_only): + """ +- Test that a nonexistant user cannot be resolved ++ Test that a nonexistant user cannot be resolved by name + """ + res, _ = call_sssd_getpwnam("nosuchuser") + assert res == NssReturnCode.NOTFOUND + + ++def test_getpwuid_neg(files_domain_only): ++ """ ++ Test that a nonexistant user cannot be resolved by UID ++ """ ++ res, _ = call_sssd_getpwuid(12345) ++ assert res == NssReturnCode.NOTFOUND ++ ++ + def test_root_does_not_resolve(files_domain_only): + """ + SSSD currently does not resolve the root user even though it can +@@ -401,6 +446,18 @@ def test_root_does_not_resolve(files_domain_only): + assert res == NssReturnCode.NOTFOUND + + ++def test_uid_zero_does_not_resolve(files_domain_only): ++ """ ++ SSSD currently does not resolve the UID 0 even though it can ++ be resolved through the NSS interface ++ """ ++ nss_root = pwd.getpwuid(0) ++ assert nss_root is not None ++ ++ res, _ = call_sssd_getpwuid(0) ++ assert res == NssReturnCode.NOTFOUND ++ ++ + def test_add_remove_add_file_user(setup_pw_with_canary, files_domain_only): + """ + Test that removing a user is detected and the user +@@ -522,11 +579,19 @@ def test_incomplete_user_fail(setup_pw_with_canary, files_domain_only): + def test_getgrnam_after_start(add_group_with_canary, files_domain_only): + """ + Test that after startup without any additional operations, a group +- can be resolved through sssd ++ can be resolved through sssd by name + """ + check_group(GROUP1) + + ++def test_getgrgid_after_start(add_group_with_canary, files_domain_only): ++ """ ++ Test that after startup without any additional operations, a group ++ can be resolved through sssd by GID ++ """ ++ check_group_by_gid(GROUP1) ++ ++ + def test_getgrnam_neg(files_domain_only): + """ + Test that a nonexistant group cannot be resolved +@@ -535,6 +600,14 @@ def test_getgrnam_neg(files_domain_only): + assert res == NssReturnCode.NOTFOUND + + ++def test_getgrgid_neg(files_domain_only): ++ """ ++ Test that a nonexistant group cannot be resolved ++ """ ++ res, user = sssd_getgrgid_sync(123456) ++ assert res == NssReturnCode.NOTFOUND ++ ++ + def test_root_group_does_not_resolve(files_domain_only): + """ + SSSD currently does not resolve the root group even though it can +@@ -547,6 +620,18 @@ def test_root_group_does_not_resolve(files_domain_only): + assert res == NssReturnCode.NOTFOUND + + ++def test_gid_zero_does_not_resolve(files_domain_only): ++ """ ++ SSSD currently does not resolve the group with GID 0 even though it ++ can be resolved through the NSS interface ++ """ ++ nss_root = grp.getgrgid(0) ++ assert nss_root is not None ++ ++ res, user = call_sssd_getgrgid(0) ++ assert res == NssReturnCode.NOTFOUND ++ ++ + def test_add_remove_add_file_group(setup_gr_with_canary, files_domain_only): + """ + Test that removing a group is detected and the group +-- +2.14.1 + diff --git a/0073-TESTS-Add-regression-tests-to-try-if-resolving-root-.patch b/0073-TESTS-Add-regression-tests-to-try-if-resolving-root-.patch new file mode 100644 index 0000000..7ebb0b7 --- /dev/null +++ b/0073-TESTS-Add-regression-tests-to-try-if-resolving-root-.patch @@ -0,0 +1,64 @@ +From 6c3841099addb84bf3e9a2f85e96dffae1b94623 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 22 Aug 2017 11:48:15 +0200 +Subject: [PATCH 73/93] TESTS: Add regression tests to try if resolving root + and ID 0 fails as expected +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/tests/intg/test_ldap.py | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py +index 7906508e14114a57408305b6735b9db5caab8d00..f2467f1ffe9890049ad73bba6432102d029510e8 100644 +--- a/src/tests/intg/test_ldap.py ++++ b/src/tests/intg/test_ldap.py +@@ -34,6 +34,9 @@ import ldap_ent + import sssd_id + import sssd_ldb + from util import unindent ++from sssd_nss import NssReturnCode ++from sssd_passwd import call_sssd_getpwnam, call_sssd_getpwuid ++from sssd_group import call_sssd_getgrnam, call_sssd_getgrgid + + LDAP_BASE_DN = "dc=example,dc=com" + INTERACTIVE_TIMEOUT = 4 +@@ -1102,10 +1105,14 @@ def sanity_nss_filter_cached(request, ldap_conn): + ent_list.add_user("user1", 1001, 2001) + ent_list.add_user("user2", 1002, 2002) + ent_list.add_user("user3", 1003, 2003) ++ ent_list.add_user("root", 1004, 2004) ++ ent_list.add_user("zerouid", 0, 0) + + ent_list.add_group_bis("group1", 2001) + ent_list.add_group_bis("group2", 2002) + ent_list.add_group_bis("group3", 2003) ++ ent_list.add_group_bis("root", 2004) ++ ent_list.add_group_bis("zerogid", 0) + + create_ldap_fixture(request, ldap_conn, ent_list) + conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ +@@ -1148,3 +1155,17 @@ def test_nss_filters_cached(ldap_conn, sanity_nss_filter_cached): + time.sleep(2) + with pytest.raises(KeyError): + grp.getgrgid(2002) ++ ++ # test that root is always filtered even if filter_users contains other ++ # entries. This is a regression test for upstream ticket #3460 ++ res, _ = call_sssd_getpwnam("root") ++ assert res == NssReturnCode.NOTFOUND ++ ++ res, _ = call_sssd_getgrnam("root") ++ assert res == NssReturnCode.NOTFOUND ++ ++ res, _ = call_sssd_getpwuid(0) ++ assert res == NssReturnCode.NOTFOUND ++ ++ res, _ = call_sssd_getgrgid(0) ++ assert res == NssReturnCode.NOTFOUND +-- +2.14.1 + diff --git a/0074-localauth-plugin-change-return-code-of-sss_an2ln.patch b/0074-localauth-plugin-change-return-code-of-sss_an2ln.patch new file mode 100644 index 0000000..a930db1 --- /dev/null +++ b/0074-localauth-plugin-change-return-code-of-sss_an2ln.patch @@ -0,0 +1,38 @@ +From 3f94a979eebd1c9496b49b4e07b7823550dec97e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 23 Aug 2017 17:06:20 +0200 +Subject: [PATCH 74/93] localauth plugin: change return code of sss_an2ln +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It is expected that the an2ln plugin function returns KRB5_LNAME_NOTRANS +to indicate that no mapping can be determined and other an2ln methods +can be tried. Currently SSSD's localauth plugin returns +KRB5_PLUGIN_NO_HANDLE which sould only be used for the userok plugin +function. + +Resolves https://pagure.io/SSSD/sssd/issue/3459 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + src/krb5_plugin/sssd_krb5_localauth_plugin.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/krb5_plugin/sssd_krb5_localauth_plugin.c b/src/krb5_plugin/sssd_krb5_localauth_plugin.c +index 13ab07d1315430f11f7bbc916f25d2c837bec78c..60567d783949b0e8b5537f6d662ff392dc848b32 100644 +--- a/src/krb5_plugin/sssd_krb5_localauth_plugin.c ++++ b/src/krb5_plugin/sssd_krb5_localauth_plugin.c +@@ -137,7 +137,7 @@ static krb5_error_code sss_an2ln(krb5_context context, + &nss_errno); + if (nss_status != NSS_STATUS_SUCCESS) { + if (nss_status == NSS_STATUS_NOTFOUND) { +- ret = KRB5_PLUGIN_NO_HANDLE; ++ ret = KRB5_LNAME_NOTRANS; + } else { + ret = EIO; + } +-- +2.14.1 + diff --git a/0075-tests-add-unit-tests-for-krb5-localauth-plugin.patch b/0075-tests-add-unit-tests-for-krb5-localauth-plugin.patch new file mode 100644 index 0000000..f4f4dea --- /dev/null +++ b/0075-tests-add-unit-tests-for-krb5-localauth-plugin.patch @@ -0,0 +1,258 @@ +From b4e45531b3e98efce868d8a01ebd2dbe54348217 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 23 Aug 2017 17:11:03 +0200 +Subject: [PATCH 75/93] tests: add unit tests for krb5 localauth plugin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + Makefile.am | 18 ++ + src/tests/cmocka/test_sssd_krb5_localauth_plugin.c | 197 +++++++++++++++++++++ + 2 files changed, 215 insertions(+) + create mode 100644 src/tests/cmocka/test_sssd_krb5_localauth_plugin.c + +diff --git a/Makefile.am b/Makefile.am +index 6cda729d381948d27fae702a557b5f3aab423683..9fc3dfcd10ab67fa63370fb5b81b93be6bd6400d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -324,6 +324,10 @@ non_interactive_cmocka_based_tests += \ + $(NULL) + endif + ++if BUILD_KRB5_LOCALAUTH_PLUGIN ++non_interactive_cmocka_based_tests += test_sssd_krb5_localauth_plugin ++endif # BUILD_KRB5_LOCALAUTH_PLUGIN ++ + endif # HAVE_CMOCKA + + check_PROGRAMS = \ +@@ -3521,6 +3525,20 @@ tcurl_test_tool_LDADD = \ + $(NULL) + endif + ++if BUILD_KRB5_LOCALAUTH_PLUGIN ++test_sssd_krb5_localauth_plugin_SOURCES = \ ++ src/tests/cmocka/test_sssd_krb5_localauth_plugin.c \ ++ src/krb5_plugin/sssd_krb5_localauth_plugin.c \ ++ $(NULL) ++test_sssd_krb5_localauth_plugin_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NULL) ++test_sssd_krb5_localauth_plugin_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(KRB5_LIBS) \ ++ $(NULL) ++endif ++ + ##################### + # Integration tests # + ##################### +diff --git a/src/tests/cmocka/test_sssd_krb5_localauth_plugin.c b/src/tests/cmocka/test_sssd_krb5_localauth_plugin.c +new file mode 100644 +index 0000000000000000000000000000000000000000..36e9f8b2992e4cc99cf541e4829f4e9af63ca875 +--- /dev/null ++++ b/src/tests/cmocka/test_sssd_krb5_localauth_plugin.c +@@ -0,0 +1,197 @@ ++/* ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ Test for the MIT Kerberos localauth plugin ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "tests/cmocka/common_mock.h" ++ ++struct _nss_sss_getpwnam_r_test_data { ++ uid_t uid; ++ const char *name; ++ enum nss_status status; ++}; ++ ++enum nss_status _nss_sss_getpwnam_r(const char *name, struct passwd *result, ++ char *buffer, size_t buflen, int *errnop) ++{ ++ struct _nss_sss_getpwnam_r_test_data *test_data; ++ ++ assert_non_null(name); ++ assert_non_null(result); ++ assert_non_null(buffer); ++ assert_int_not_equal(buflen, 0); ++ assert_non_null(errnop); ++ ++ test_data = sss_mock_ptr_type(struct _nss_sss_getpwnam_r_test_data *); ++ ++ result->pw_uid = test_data->uid; ++ if (test_data->name != NULL) { ++ assert_true(buflen > strlen(test_data->name)); ++ strncpy(buffer, test_data->name, buflen); ++ result->pw_name = buffer; ++ } ++ ++ return test_data->status; ++} ++ ++krb5_error_code ++localauth_sssd_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++ ++void test_localauth_sssd_initvt(void **state) ++{ ++ krb5_error_code kerr; ++ struct krb5_localauth_vtable_st vtable = { 0 }; ++ ++ kerr = localauth_sssd_initvt(NULL, 0, 0, (krb5_plugin_vtable) &vtable); ++ assert_int_equal(kerr, KRB5_PLUGIN_VER_NOTSUPP); ++ ++ kerr = localauth_sssd_initvt(NULL, 1, 1, (krb5_plugin_vtable) &vtable); ++ assert_int_equal(kerr, 0); ++ assert_string_equal(vtable.name, "sssd"); ++ assert_null(vtable.init); ++ assert_null(vtable.fini); ++ assert_non_null(vtable.an2ln); ++ assert_non_null(vtable.userok); ++ assert_non_null(vtable.free_string); ++} ++ ++void test_sss_userok(void **state) ++{ ++ krb5_error_code kerr; ++ struct krb5_localauth_vtable_st vtable = { 0 }; ++ krb5_context krb5_ctx; ++ krb5_principal princ; ++ size_t c; ++ ++ struct test_data { ++ struct _nss_sss_getpwnam_r_test_data d1; ++ struct _nss_sss_getpwnam_r_test_data d2; ++ krb5_error_code kerr; ++ } test_data[] = { ++ {{ 1234, NULL, NSS_STATUS_SUCCESS}, { 1234, NULL, NSS_STATUS_SUCCESS}, ++ 0}, ++ /* second _nss_sss_getpwnam_r() is never called because the first one ++ * alread returned an error */ ++ {{ 1234, NULL, NSS_STATUS_NOTFOUND}, { 0, NULL, 0}, ++ KRB5_PLUGIN_NO_HANDLE}, ++ {{ 1234, NULL, NSS_STATUS_SUCCESS}, { 1234, NULL, NSS_STATUS_NOTFOUND}, ++ KRB5_PLUGIN_NO_HANDLE}, ++ {{ 1234, NULL, NSS_STATUS_SUCCESS}, { 4321, NULL, NSS_STATUS_SUCCESS}, ++ KRB5_PLUGIN_NO_HANDLE}, ++ /* second _nss_sss_getpwnam_r() is never called because the first one ++ * alread returned an error */ ++ {{ 1234, NULL, NSS_STATUS_UNAVAIL}, { 0, NULL, 0}, ++ KRB5_PLUGIN_NO_HANDLE}, ++ {{ 1234, NULL, NSS_STATUS_SUCCESS}, { 1234, NULL, NSS_STATUS_TRYAGAIN}, ++ KRB5_PLUGIN_NO_HANDLE}, ++ {{ 0, NULL, 0 }, {0 , NULL, 0}, 0} ++ }; ++ ++ kerr = krb5_init_context(&krb5_ctx); ++ assert_int_equal(kerr, 0); ++ ++ kerr = localauth_sssd_initvt(krb5_ctx, 1, 1, (krb5_plugin_vtable) &vtable); ++ assert_int_equal(kerr, 0); ++ ++ kerr = krb5_parse_name(krb5_ctx, "name@REALM", &princ); ++ assert_int_equal(kerr, 0); ++ ++ ++ for (c = 0; test_data[c].d1.uid != 0; c++) { ++ will_return(_nss_sss_getpwnam_r, &test_data[c].d1); ++ if (test_data[c].d2.uid != 0) { ++ will_return(_nss_sss_getpwnam_r, &test_data[c].d2); ++ } ++ kerr = vtable.userok(krb5_ctx, NULL, princ, "name"); ++ assert_int_equal(kerr, test_data[c].kerr); ++ } ++ ++ krb5_free_principal(krb5_ctx, princ); ++ krb5_free_context(krb5_ctx); ++} ++ ++void test_sss_an2ln(void **state) ++{ ++ krb5_error_code kerr; ++ struct krb5_localauth_vtable_st vtable = { 0 }; ++ krb5_context krb5_ctx; ++ krb5_principal princ; ++ size_t c; ++ char *lname; ++ ++ struct test_data { ++ struct _nss_sss_getpwnam_r_test_data d; ++ krb5_error_code kerr; ++ } test_data[] = { ++ { { 0, "my_name", NSS_STATUS_SUCCESS}, 0}, ++ { { 0, "my_name", NSS_STATUS_NOTFOUND}, KRB5_LNAME_NOTRANS}, ++ { { 0, "my_name", NSS_STATUS_UNAVAIL}, EIO}, ++ { { 0, NULL, 0 } , 0} ++ }; ++ ++ kerr = krb5_init_context(&krb5_ctx); ++ assert_int_equal(kerr, 0); ++ ++ kerr = localauth_sssd_initvt(krb5_ctx, 1, 1, (krb5_plugin_vtable) &vtable); ++ assert_int_equal(kerr, 0); ++ ++ kerr = krb5_parse_name(krb5_ctx, "name@REALM", &princ); ++ assert_int_equal(kerr, 0); ++ ++ ++ for (c = 0; test_data[c].d.name != NULL; c++) { ++ will_return(_nss_sss_getpwnam_r, &test_data[c].d); ++ kerr = vtable.an2ln(krb5_ctx, NULL, NULL, NULL, princ, &lname); ++ assert_int_equal(kerr, test_data[c].kerr); ++ if (kerr == 0) { ++ assert_string_equal(lname, test_data[c].d.name); ++ vtable.free_string(krb5_ctx, NULL, lname); ++ } ++ } ++ ++ krb5_free_principal(krb5_ctx, princ); ++ krb5_free_context(krb5_ctx); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_localauth_sssd_initvt), ++ cmocka_unit_test(test_sss_userok), ++ cmocka_unit_test(test_sss_an2ln), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +-- +2.14.1 + diff --git a/0076-CONFDB-Set-a-default-value-for-subdomain_refresh_int.patch b/0076-CONFDB-Set-a-default-value-for-subdomain_refresh_int.patch new file mode 100644 index 0000000..c6088bb --- /dev/null +++ b/0076-CONFDB-Set-a-default-value-for-subdomain_refresh_int.patch @@ -0,0 +1,62 @@ +From b4195db089bc481161b37cd129d0876571f633b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 29 Aug 2017 19:08:53 +0200 +Subject: [PATCH 76/93] CONFDB: Set a default value for + subdomain_refresh_interval in case an invalid value is set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The code as it was seemed wrong as when an invalid value as set we +neither error out nor set a default valid value there. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/confdb/confdb.c | 13 +++++++++++-- + src/confdb/confdb.h | 1 + + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index 286dbb24377c6d0fdf2c2d070da04918c591ce05..fd73abe5b79fcb1ba38f7a9d1db86bc3206bb481 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1419,11 +1419,20 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + + ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval, +- CONFDB_DOMAIN_SUBDOMAIN_REFRESH, 14400); +- if (ret != EOK || domain->subdomain_refresh_interval == 0) { ++ CONFDB_DOMAIN_SUBDOMAIN_REFRESH, ++ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE); ++ if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Invalid value for [%s]\n", CONFDB_DOMAIN_SUBDOMAIN_REFRESH); + goto done; ++ } else if (domain->subdomain_refresh_interval == 0) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Invalid value for [%s]. Setting up the default value: %d\n", ++ CONFDB_DOMAIN_SUBDOMAIN_REFRESH, ++ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE); ++ ++ domain->subdomain_refresh_interval = ++ CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE; + } + + ret = init_cached_auth_timeout(cdb, res->msgs[0], +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index da725fb667afea6747d22d1d3a4315fb7a7bace2..4abc95b8183f1b430f770b55e8af0e43f65889a3 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -207,6 +207,7 @@ + #define CONFDB_DOMAIN_DEFAULT_SUBDOMAIN_HOMEDIR "/home/%d/%u" + #define CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS "ignore_group_members" + #define CONFDB_DOMAIN_SUBDOMAIN_REFRESH "subdomain_refresh_interval" ++#define CONFDB_DOMAIN_SUBDOMAIN_REFRESH_DEFAULT_VALUE 14400 + + #define CONFDB_DOMAIN_USER_CACHE_TIMEOUT "entry_cache_user_timeout" + #define CONFDB_DOMAIN_GROUP_CACHE_TIMEOUT "entry_cache_group_timeout" +-- +2.14.1 + diff --git a/0077-CONFDB-Do-not-crash-with-an-invalid-domain_type-or-c.patch b/0077-CONFDB-Do-not-crash-with-an-invalid-domain_type-or-c.patch new file mode 100644 index 0000000..fd6544b --- /dev/null +++ b/0077-CONFDB-Do-not-crash-with-an-invalid-domain_type-or-c.patch @@ -0,0 +1,44 @@ +From 9787bc5890865be73a6caedaa22b3fae1e3aa671 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 29 Aug 2017 10:52:45 +0200 +Subject: [PATCH 77/93] CONFDB: Do not crash with an invalid domain_type or + case_sensitive value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the domain_type parameter contained an invalid value, the error +branch wouldn't have set the 'ret' parameter to an error condition, +which might crash sssd. + +The same problem occured with CONFDB_DOMAIN_CASE_SENSITIVE + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Lukáš Slebodník +--- + src/confdb/confdb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index fd73abe5b79fcb1ba38f7a9d1db86bc3206bb481..69d1c7915ec213a946bb22987ffddcc15fee8c01 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1345,6 +1345,7 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } else { + DEBUG(SSSDBG_FATAL_FAILURE, + "Invalid value for %s\n", CONFDB_DOMAIN_CASE_SENSITIVE); ++ ret = EINVAL; + goto done; + } + } else { +@@ -1414,6 +1415,7 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } else { + DEBUG(SSSDBG_FATAL_FAILURE, + "Invalid value %s for [%s]\n", tmp, CONFDB_DOMAIN_TYPE); ++ ret = EINVAL; + goto done; + } + } +-- +2.14.1 + diff --git a/0078-SDAP-Add-a-debug-message-to-explain-why-a-backend-wa.patch b/0078-SDAP-Add-a-debug-message-to-explain-why-a-backend-wa.patch new file mode 100644 index 0000000..a1d5202 --- /dev/null +++ b/0078-SDAP-Add-a-debug-message-to-explain-why-a-backend-wa.patch @@ -0,0 +1,39 @@ +From 362b8a94c0ffaa63af3a5a5772c29303be009640 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 28 Aug 2017 13:17:49 +0200 +Subject: [PATCH 78/93] SDAP: Add a debug message to explain why a backend was + marked offline +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This new debug message may help us when debugging the cases where a +backend was marked offline but it shouldn't be. + +Related: https://pagure.io/SSSD/sssd/issue/2976 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/providers/ldap/sdap_id_op.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c +index 3a3de3643711fc2e604b876f401a88b486f941d5..85622663598d3091f735d56b5c81f9b36506a085 100644 +--- a/src/providers/ldap/sdap_id_op.c ++++ b/src/providers/ldap/sdap_id_op.c +@@ -608,6 +608,10 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) + + default: + /* do not attempt to retry on errors like ENOMEM */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Marking the backend \"%s\" offline [%d]: %s\n", ++ conn_cache->id_conn->id_ctx->be->domain->name, ++ ret, sss_strerror(ret)); + can_retry = false; + is_offline = true; + be_mark_offline(conn_cache->id_conn->id_ctx->be); +-- +2.14.1 + diff --git a/0079-SDAP-Don-t-call-be_mark_offline-because-sdap_id_conn.patch b/0079-SDAP-Don-t-call-be_mark_offline-because-sdap_id_conn.patch new file mode 100644 index 0000000..da2be57 --- /dev/null +++ b/0079-SDAP-Don-t-call-be_mark_offline-because-sdap_id_conn.patch @@ -0,0 +1,44 @@ +From 5a117d36030f589cc04430ea1c6c328a8fdb903f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 28 Aug 2017 16:38:40 +0200 +Subject: [PATCH 79/93] SDAP: Don't call be_mark_offline() because + sdap_id_conn_data_set_expire_timer() failed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Marking the whole backend as offline because +sdap_id_conn_data_set_expire_timer() failed doesn't look any right and +from now on let's avoiding doing so. + +Related: https://pagure.io/SSSD/sssd/issue/2976 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +--- + src/providers/ldap/sdap_id_op.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c +index 85622663598d3091f735d56b5c81f9b36506a085..e7ff5464c06fdc3df9bce40315e91af2cc3b85d1 100644 +--- a/src/providers/ldap/sdap_id_op.c ++++ b/src/providers/ldap/sdap_id_op.c +@@ -592,6 +592,14 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) + } + } + ret = sdap_id_conn_data_set_expire_timer(conn_data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "sdap_id_conn_data_set_expire_timer() failed [%d]: %s", ++ ret, sss_strerror(ret)); ++ /* Avoid causing the whole backend to be marked as offline because ++ * this operation failed. */ ++ ret = EOK; ++ } + sdap_steal_server_opts(conn_cache->id_conn->id_ctx, &srv_opts); + } + +-- +2.14.1 + diff --git a/0080-PYTHON-Define-constants-as-bytes-instead-of-strings.patch b/0080-PYTHON-Define-constants-as-bytes-instead-of-strings.patch new file mode 100644 index 0000000..675b4a4 --- /dev/null +++ b/0080-PYTHON-Define-constants-as-bytes-instead-of-strings.patch @@ -0,0 +1,49 @@ +From 9375eae59550437c85ada9212be430a4242b25a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 30 Aug 2017 14:13:51 +0200 +Subject: [PATCH 80/93] PYTHON: Define constants as bytes instead of strings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using python3 getsidbyname() and getnamebysid() expect the key as +bytes instead of strings, and currently those are defined as strings. +So, in order to avoid people working around this by doing +`pysss_nss_idmap.SID_KEY.encode('utf-8')` let's make their life easier +and properly have those constants defined as bytes. + +Resolves: https://pagure.io/SSSD/sssd/issue/3491 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Michal Židek +Reviewed-by: Jakub Hrozek +--- + src/python/pysss_nss_idmap.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/python/pysss_nss_idmap.c b/src/python/pysss_nss_idmap.c +index 2e5851c7a6e48629fd93e428aada499fcbe36ebb..be7fa297edf99674505b44820e36c9126dee61da 100644 +--- a/src/python/pysss_nss_idmap.c ++++ b/src/python/pysss_nss_idmap.c +@@ -533,10 +533,17 @@ initpysss_nss_idmap(void) + PyModule_AddIntConstant(module, "ID_GROUP", SSS_ID_TYPE_GID); + PyModule_AddIntConstant(module, "ID_BOTH", SSS_ID_TYPE_BOTH); + ++#ifdef IS_PY3K ++ PyModule_AddObject(module, "SID_KEY", PyBytes_FromString(SSS_SID_KEY)); ++ PyModule_AddObject(module, "NAME_KEY", PyBytes_FromString(SSS_NAME_KEY)); ++ PyModule_AddObject(module, "ID_KEY", PyBytes_FromString(SSS_ID_KEY)); ++ PyModule_AddObject(module, "TYPE_KEY", PyBytes_FromString(SSS_TYPE_KEY)); ++#else + PyModule_AddStringConstant(module, "SID_KEY", SSS_SID_KEY); + PyModule_AddStringConstant(module, "NAME_KEY", SSS_NAME_KEY); + PyModule_AddStringConstant(module, "ID_KEY", SSS_ID_KEY); + PyModule_AddStringConstant(module, "TYPE_KEY", SSS_TYPE_KEY); ++#endif + + #ifdef IS_PY3K + return module; +-- +2.14.1 + diff --git a/0081-IPA-format-fixes.patch b/0081-IPA-format-fixes.patch new file mode 100644 index 0000000..38cd72b --- /dev/null +++ b/0081-IPA-format-fixes.patch @@ -0,0 +1,50 @@ +From 0475a98d313b8380e7fbf98ee0821a65f8140589 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 29 Aug 2017 15:29:19 +0200 +Subject: [PATCH 81/93] IPA: format fixes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are format warnings when compiling on 32bit. One is about time_t +where %ld should be used and the other is about size_t where %zu should +be used. + +Related to https://pagure.io/SSSD/sssd/issue/2995 + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ipa/ipa_deskprofile_rules_util.c | 2 +- + src/providers/ipa/ipa_session.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.c b/src/providers/ipa/ipa_deskprofile_rules_util.c +index 1f5b7f9c5244c5863dec4096e2af58914425c37c..53c433145666af00a994420ccd1a926b11937fc9 100644 +--- a/src/providers/ipa/ipa_deskprofile_rules_util.c ++++ b/src/providers/ipa/ipa_deskprofile_rules_util.c +@@ -891,7 +891,7 @@ deskprofile_get_cached_priority(struct sss_domain_info *domain, + if (resp_count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, + "sysdb_search_custom_by_name() got more attributes than " +- "expected. Expected (%d), got (%"PRIu64")\n", 1, resp_count); ++ "expected. Expected (1), got (%zu)\n", resp_count); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c +index 8559284c9b453129400626e0cf93e70275e80301..3c7dd33c30ac6331319fc62cac466c4fbf04c0a5 100644 +--- a/src/providers/ipa/ipa_session.c ++++ b/src/providers/ipa/ipa_session.c +@@ -140,7 +140,7 @@ ipa_fetch_deskprofile_send(TALLOC_CTX *mem_ctx, + next_request /= 60; + DEBUG(SSSDBG_TRACE_FUNC, + "No rules were found in the last request.\n" +- "Next request will happen in any login after %"PRIu64" minutes\n", ++ "Next request will happen in any login after %ld minutes\n", + next_request); + ret = ENOENT; + goto immediately; +-- +2.14.1 + diff --git a/0082-SPEC-rhel8-will-have-python3-as-well.patch b/0082-SPEC-rhel8-will-have-python3-as-well.patch new file mode 100644 index 0000000..8ef2878 --- /dev/null +++ b/0082-SPEC-rhel8-will-have-python3-as-well.patch @@ -0,0 +1,29 @@ +From fa0d29fe3c5b5fd07ce9e665f18b7aa335d73c9c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 1 Sep 2017 10:52:04 +0200 +Subject: [PATCH 82/93] SPEC: rhel8 will have python3 as well +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +--- + contrib/sssd.spec.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 942d57f8eae88eec477e1e344412f1a92404e0f0..cdab9874b43b87ac897e80ef7e81630a132a15d9 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -97,7 +97,7 @@ + %global with_cifs_utils_plugin_option --disable-cifs-idmap-plugin + %endif + +-%if (0%{?fedora}) ++%if (0%{?fedora} || 0%{?rhel} > 7) + %global with_python3 1 + %else + %global with_python3_option --without-python3-bindings +-- +2.14.1 + diff --git a/0083-SPEC-Fix-unowned-directory.patch b/0083-SPEC-Fix-unowned-directory.patch new file mode 100644 index 0000000..a0c0f32 --- /dev/null +++ b/0083-SPEC-Fix-unowned-directory.patch @@ -0,0 +1,34 @@ +From 8302d6da81f950d498d8a7c70aa0e56376055057 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 1 Sep 2017 10:53:09 +0200 +Subject: [PATCH 83/93] SPEC: Fix unowned directory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://fedoraproject.org/wiki/Packaging:UnownedDirectories + +sh$ rpm -qf /usr/lib64/sssd/conf/ /usr/lib64/sssd/conf/sssd.conf +file /usr/lib64/sssd/conf is not owned by any package +sssd-common-1.15.3-2.fc27.x86_64 + +Reviewed-by: Pavel Březina +--- + contrib/sssd.spec.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index cdab9874b43b87ac897e80ef7e81630a132a15d9..43b853bb523bb212316f3d0046da6b88e4505ad2 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -981,6 +981,7 @@ done + %config(noreplace) %{_sysconfdir}/rwtab.d/sssd + %dir %{_datadir}/sssd + %{_sysconfdir}/pam.d/sssd-shadowutils ++%dir %{_libdir}/%{name}/conf + %{_libdir}/%{name}/conf/sssd.conf + + %{_datadir}/sssd/cfg_rules.ini +-- +2.14.1 + diff --git a/0084-IPA-Only-attempt-migration-for-the-joined-domain.patch b/0084-IPA-Only-attempt-migration-for-the-joined-domain.patch new file mode 100644 index 0000000..4fd1ef0 --- /dev/null +++ b/0084-IPA-Only-attempt-migration-for-the-joined-domain.patch @@ -0,0 +1,63 @@ +From 45e322191c7aa9390798b64ccb158ee800489945 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 13 Jun 2017 12:26:51 +0200 +Subject: [PATCH 84/93] IPA: Only attempt migration for the joined domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After the recent changes in commit a5e134b22aa27ff6cd66a7ff47089788ebc098a1 +to fix ticket #3394, the PAM_CRED_ERR error would try to start migration +for any account. Further down the request, a sysdb search would try to find +the user in the joined domain only because the migration code presumes the +user is in the IPA domain which would error out and return System Error +to the PAM client. + +This patch changes the migration somewhat to only attempt the migration +for IPA users. + +Reviewed-by: Pavel Březina +--- + src/providers/ipa/ipa_auth.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c +index 80a9987277d7a298f703a8efb584ca428b67c94f..ef89c7177f2250547beb785d8cec836f893b039a 100644 +--- a/src/providers/ipa/ipa_auth.c ++++ b/src/providers/ipa/ipa_auth.c +@@ -172,6 +172,7 @@ struct ipa_pam_auth_handler_state { + struct ipa_auth_ctx *auth_ctx; + struct be_ctx *be_ctx; + struct pam_data *pd; ++ struct sss_domain_info *dom; + }; + + static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq); +@@ -201,6 +202,14 @@ ipa_pam_auth_handler_send(TALLOC_CTX *mem_ctx, + state->ev = params->ev; + state->auth_ctx = auth_ctx; + state->be_ctx = params->be_ctx; ++ state->dom = find_domain_by_name(state->be_ctx->domain, ++ state->pd->domain, ++ true); ++ if (state->dom == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Uknown domain %s\n", state->pd->domain); ++ pd->pam_status = PAM_SYSTEM_ERR; ++ goto immediately; ++ } + + pd->pam_status = PAM_SYSTEM_ERR; + +@@ -248,7 +257,8 @@ static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq) + } + + if (state->pd->cmd == SSS_PAM_AUTHENTICATE +- && state->pd->pam_status == PAM_CRED_ERR) { ++ && state->pd->pam_status == PAM_CRED_ERR ++ && !IS_SUBDOMAIN(state->dom)) { + realm = dp_opt_get_string(state->auth_ctx->ipa_options, IPA_KRB5_REALM); + subreq = get_password_migration_flag_send(state, state->ev, + state->auth_ctx->sdap_id_ctx, +-- +2.14.1 + diff --git a/0085-SECRETS-Remove-unused-declarations.patch b/0085-SECRETS-Remove-unused-declarations.patch new file mode 100644 index 0000000..ea5b594 --- /dev/null +++ b/0085-SECRETS-Remove-unused-declarations.patch @@ -0,0 +1,31 @@ +From 2d40ce078a9071ac23353848d0849fbbbd600049 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 30 May 2017 12:19:53 +0200 +Subject: [PATCH 85/93] SECRETS: Remove unused declarations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Lukáš Slebodník +--- + src/responder/secrets/secsrv.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index 3d23c405b3017be83ebc840da5ad253e5269fc7b..0575cbabab07769d2b17f2c0b815004a11b49f90 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -32,8 +32,6 @@ + + #define SEC_NET_TIMEOUT 5 + +-struct resctx; +- + struct sec_ctx { + struct resolv_ctx *resctx; + struct resp_ctx *rctx; +-- +2.14.1 + diff --git a/0086-SECRETS-Do-not-link-with-c-ares.patch b/0086-SECRETS-Do-not-link-with-c-ares.patch new file mode 100644 index 0000000..2fb5be3 --- /dev/null +++ b/0086-SECRETS-Do-not-link-with-c-ares.patch @@ -0,0 +1,91 @@ +From 9ef185255126b9ed415fa334f585a11c5be4fb1a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 5 Jun 2017 15:19:13 +0200 +Subject: [PATCH 86/93] SECRETS: Do not link with c-ares +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since we started using libcurl for the proxy provider, there is no point +in initializing or linking against c-ares. + +If we want to explicitly use a resolver in the future, we should use +libcurl callbacks. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 1 - + src/responder/secrets/proxy.c | 2 -- + src/responder/secrets/secsrv.c | 6 ------ + src/responder/secrets/secsrv.h | 3 --- + 4 files changed, 12 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 9fc3dfcd10ab67fa63370fb5b81b93be6bd6400d..273ecc72fba6793b4f46dbb11f6541e2e1bcc930 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1500,7 +1500,6 @@ sssd_secrets_SOURCES = \ + src/util/sss_iobuf.c \ + src/util/tev_curl.c \ + $(SSSD_RESPONDER_OBJ) \ +- $(SSSD_RESOLV_OBJ) \ + $(NULL) + sssd_secrets_LDADD = \ + $(HTTP_PARSER_LIBS) \ +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index a4e97f83ef406e71a1e6509a6b719c47afdfd5b8..a910b38534195e31e3370854b8b9118e8e310d36 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -29,7 +29,6 @@ + #define SEC_PROXY_TIMEOUT 5 + + struct proxy_context { +- struct resolv_ctx *resctx; + struct confdb_ctx *cdb; + struct tcurl_ctx *tcurl; + }; +@@ -585,7 +584,6 @@ int proxy_secrets_provider_handle(struct sec_ctx *sctx, + pctx = talloc(handle, struct proxy_context); + if (!pctx) return ENOMEM; + +- pctx->resctx = sctx->resctx; + pctx->cdb = sctx->rctx->cdb; + pctx->tcurl = tcurl_init(pctx, sctx->rctx->ev); + if (pctx->tcurl == NULL) { +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index b0467e90e65c28929ae0f16b70b58ed9d27560c2..ae2a658ae131e742466796cc47892a234e46f7d3 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -162,12 +162,6 @@ static int sec_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- ret = resolv_init(sctx, ev, SEC_NET_TIMEOUT, &sctx->resctx); +- if (ret != EOK) { +- /* not fatal for now */ +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize resolver library\n"); +- } +- + /* Set up file descriptor limits */ + responder_set_fd_limit(sctx->fd_limit); + +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index 0575cbabab07769d2b17f2c0b815004a11b49f90..1aad272da3ded1a2b3d2d8475ff3f2422c893483 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -30,10 +30,7 @@ + #include + #include + +-#define SEC_NET_TIMEOUT 5 +- + struct sec_ctx { +- struct resolv_ctx *resctx; + struct resp_ctx *rctx; + int fd_limit; + int containers_nest_level; +-- +2.14.1 + diff --git a/0087-SECRETS-Store-quotas-in-a-per-hive-configuration-str.patch b/0087-SECRETS-Store-quotas-in-a-per-hive-configuration-str.patch new file mode 100644 index 0000000..46eca9e --- /dev/null +++ b/0087-SECRETS-Store-quotas-in-a-per-hive-configuration-str.patch @@ -0,0 +1,158 @@ +From 7a162ca3ea0bf8ef6b13795a00baa28d17f6131d Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 30 May 2017 12:31:57 +0200 +Subject: [PATCH 87/93] SECRETS: Store quotas in a per-hive configuration + structure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds two new structures to hold the quotas and associate a quota with a hive. + +This is just an internal change for now, but will allow us to read quota +configuration from per-hive sections later. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/responder/secrets/local.c | 21 +++++++++------------ + src/responder/secrets/secsrv.c | 6 +++--- + src/responder/secrets/secsrv.h | 17 ++++++++++++++--- + 3 files changed, 26 insertions(+), 18 deletions(-) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 66401ef50d9114a9ab493f0e46d1ad38dd854365..0b879939f25487b0275d5144f5e27b2873b3fbae 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -34,9 +34,8 @@ + struct local_context { + struct ldb_context *ldb; + struct sec_data master_key; +- int containers_nest_level; +- int max_secrets; +- int max_payload_size; ++ ++ struct sec_quota *quota_secrets; + }; + + static int local_decrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx, +@@ -398,11 +397,11 @@ static int local_db_check_containers_nest_level(struct local_context *lctx, + /* We need do not care for the synthetic containers that constitute the + * base path (cn=,cn=user,cn=secrets). */ + nest_level = ldb_dn_get_comp_num(leaf_dn) - 3; +- if (nest_level > lctx->containers_nest_level) { ++ if (nest_level > lctx->quota_secrets->containers_nest_level) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot create a nested container of depth %d as the maximum" + "allowed number of nested containers is %d.\n", +- nest_level, lctx->containers_nest_level); ++ nest_level, lctx->quota_secrets->containers_nest_level); + + return ERR_SEC_INVALID_CONTAINERS_NEST_LEVEL; + } +@@ -430,10 +429,10 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + + ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, + attrs, LOCAL_SIMPLE_FILTER); +- if (res->count >= lctx->max_secrets) { ++ if (res->count >= lctx->quota_secrets->max_secrets) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot store any more secrets as the maximum allowed limit (%d) " +- "has been reached\n", lctx->max_secrets); ++ "has been reached\n", lctx->quota_secrets->max_secrets); + + ret = ERR_SEC_INVALID_TOO_MANY_SECRETS; + goto done; +@@ -451,14 +450,14 @@ static int local_check_max_payload_size(struct local_context *lctx, + { + int max_payload_size; + +- max_payload_size = lctx->max_payload_size * 1024; /* kb */ ++ max_payload_size = lctx->quota_secrets->max_payload_size * 1024; /* kb */ + if (payload_size > max_payload_size) { + DEBUG(SSSDBG_OP_FAILURE, + "Secrets' payload size [%d kb (%d)] exceeds the maximum allowed " + "payload size [%d kb (%d)]\n", + payload_size * 1024, /* kb */ + payload_size, +- lctx->max_payload_size, /* kb */ ++ lctx->quota_secrets->max_payload_size, /* kb */ + max_payload_size); + + return ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE; +@@ -1019,9 +1018,7 @@ int local_secrets_provider_handle(struct sec_ctx *sctx, + return EIO; + } + +- lctx->containers_nest_level = sctx->containers_nest_level; +- lctx->max_secrets = sctx->max_secrets; +- lctx->max_payload_size = sctx->max_payload_size; ++ lctx->quota_secrets = &sctx->sec_config.quota; + + lctx->master_key.data = talloc_size(lctx, MKEY_SIZE); + if (!lctx->master_key.data) return ENOMEM; +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index ae2a658ae131e742466796cc47892a234e46f7d3..e3a8c1476af8d9c2c8b87a11ca930e12f381ef94 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -52,7 +52,7 @@ static int sec_get_config(struct sec_ctx *sctx) + sctx->rctx->confdb_service_path, + CONFDB_SEC_CONTAINERS_NEST_LEVEL, + DEFAULT_SEC_CONTAINERS_NEST_LEVEL, +- &sctx->containers_nest_level); ++ &sctx->sec_config.quota.containers_nest_level); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +@@ -64,7 +64,7 @@ static int sec_get_config(struct sec_ctx *sctx) + sctx->rctx->confdb_service_path, + CONFDB_SEC_MAX_SECRETS, + DEFAULT_SEC_MAX_SECRETS, +- &sctx->max_secrets); ++ &sctx->sec_config.quota.max_secrets); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +@@ -76,7 +76,7 @@ static int sec_get_config(struct sec_ctx *sctx) + sctx->rctx->confdb_service_path, + CONFDB_SEC_MAX_PAYLOAD_SIZE, + DEFAULT_SEC_MAX_PAYLOAD_SIZE, +- &sctx->max_payload_size); ++ &sctx->sec_config.quota.max_payload_size); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index 1aad272da3ded1a2b3d2d8475ff3f2422c893483..629b027f6966dd221d21d16ccfc75c99881935f8 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -30,12 +30,23 @@ + #include + #include + ++struct sec_quota { ++ int max_secrets; ++ int max_payload_size; ++ int containers_nest_level; ++}; ++ ++struct sec_hive_config { ++ const char *confdb_section; ++ ++ struct sec_quota quota; ++}; ++ + struct sec_ctx { + struct resp_ctx *rctx; + int fd_limit; +- int containers_nest_level; +- int max_secrets; +- int max_payload_size; ++ ++ struct sec_hive_config sec_config; + + struct provider_handle **providers; + }; +-- +2.14.1 + diff --git a/0088-SECRETS-Read-the-quotas-for-cn-secrets-from-secrets-.patch b/0088-SECRETS-Read-the-quotas-for-cn-secrets-from-secrets-.patch new file mode 100644 index 0000000..083ea7a --- /dev/null +++ b/0088-SECRETS-Read-the-quotas-for-cn-secrets-from-secrets-.patch @@ -0,0 +1,439 @@ +From 4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 30 May 2017 12:51:19 +0200 +Subject: [PATCH 88/93] SECRETS: Read the quotas for cn=secrets from + [secrets/secrets] configuration subsection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch makes obsoletes the old way of configuring quotas for the +secrets responder. Instead, adds a new way of configuring each hive +separately in a configuration subsection, e.g. + +[secrets/secrets] +max_secrets = 123 + +The old way is still supported as a backwards-compatible method. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/config/cfg_rules.ini | 10 +++ + src/man/sssd-secrets.5.xml | 45 ++++++++++++- + src/responder/secrets/secsrv.c | 139 +++++++++++++++++++++++++++++++++-------- + src/tests/intg/test_secrets.py | 125 +++++++++++++++++++++++++++--------- + 4 files changed, 262 insertions(+), 57 deletions(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index ae60c73c871e1ac18a26124232e1f9f7c9f8fabb..a963eb49c9010924bda6a48c47d80c868ffd6ddd 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -12,6 +12,7 @@ section = secrets + section = kcm + section = session_recording + section_re = ^secrets/users/[0-9]\+$ ++section_re = ^secrets/secrets$ + section_re = ^domain/[^/\@]\+$ + section_re = ^domain/[^/\@]\+/[^/\@]\+$ + section_re = ^application/[^/\@]\+$ +@@ -256,6 +257,15 @@ option = max_secrets + option = max_payload_size + option = responder_idle_timeout + ++[rule/allowed_sec_hive_options] ++validator = ini_allowed_options ++section_re = ^secrets/secrets$ ++ ++# Secrets service - per-hive configuration ++option = containers_nest_level ++option = max_secrets ++option = max_payload_size ++ + [rule/allowed_sec_users_options] + validator = ini_allowed_options + section_re = ^secrets/users/[0-9]\+$ +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index 44a86c3fb56a8bdebebd01e9f49ad171986282a4..d50cb13d8a0dcbdb7919c1e38d6d5976dcc2abf1 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -57,6 +57,32 @@ + collide between users. Secrets can be stored inside + containers which can be nested. + ++ ++ Since the secrets responder can be used both externally to store ++ general secrets, as described in the rest of this man page, but ++ also internally by other SSSD components to store their secret ++ material, some configuration options, like quotas can be configured ++ per hive in a configuration subsection named after ++ the hive. The currently supported hives are: ++ ++ ++ secrets ++ secrets for general usage ++ ++ ++ kcm ++ ++ used by the ++ ++ sssd-kcm ++ 8 ++ ++ service. ++ ++ ++ ++ ++ + + + +@@ -144,6 +170,12 @@ systemctl enable sssd-secrets.service + + + ++ ++ ++ The following options affect only the secrets hive ++ and therefore should be set in a per-hive subsection. ++ ++ + + containers_nest_level (integer) + +@@ -161,7 +193,7 @@ systemctl enable sssd-secrets.service + + + This option specifies the maximum number of secrets that +- can be stored. ++ can be stored in the hive. + + + Default: 1024 +@@ -181,6 +213,17 @@ systemctl enable sssd-secrets.service + + + ++ ++ For example, to adjust quotas differently for both the secrets ++ and the kcm hives, configure the following: ++ ++[secrets/secrets] ++max_payload_size = 128 ++ ++[secrets/kcm] ++max_payload_size = 256 ++ ++ + + The following options are only applicable for configurations that + use the proxy provider. +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index e3a8c1476af8d9c2c8b87a11ca930e12f381ef94..db12cbbc3eb9317b6d449a5d2b2d370afebf247e 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -33,6 +33,100 @@ + #define DEFAULT_SEC_MAX_SECRETS 1024 + #define DEFAULT_SEC_MAX_PAYLOAD_SIZE 16 + ++static int sec_get_quota(struct sec_ctx *sctx, ++ const char *section_config_path, ++ int default_max_containers_nest_level, ++ int default_max_num_secrets, ++ int default_max_payload, ++ struct sec_quota *quota) ++{ ++ int ret; ++ ++ ret = confdb_get_int(sctx->rctx->cdb, ++ section_config_path, ++ CONFDB_SEC_CONTAINERS_NEST_LEVEL, ++ default_max_containers_nest_level, ++ "a->containers_nest_level); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get container nesting level for %s\n", ++ section_config_path); ++ return ret; ++ } ++ ++ ret = confdb_get_int(sctx->rctx->cdb, ++ section_config_path, ++ CONFDB_SEC_MAX_SECRETS, ++ default_max_num_secrets, ++ "a->max_secrets); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get maximum number of entries for %s\n", ++ section_config_path); ++ return ret; ++ } ++ ++ ret = confdb_get_int(sctx->rctx->cdb, ++ section_config_path, ++ CONFDB_SEC_MAX_PAYLOAD_SIZE, ++ default_max_payload, ++ "a->max_payload_size); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get payload's maximum size for an entry in %s\n", ++ section_config_path); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static int sec_get_hive_config(struct sec_ctx *sctx, ++ const char *hive_name, ++ struct sec_hive_config *hive_config, ++ int default_max_containers_nest_level, ++ int default_max_num_secrets, ++ int default_max_payload) ++{ ++ int ret; ++ TALLOC_CTX *tmp_ctx; ++ ++ tmp_ctx = talloc_new(sctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ hive_config->confdb_section = talloc_asprintf(sctx, ++ "config/secrets/%s", ++ hive_name); ++ if (hive_config->confdb_section == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sec_get_quota(sctx, ++ hive_config->confdb_section, ++ default_max_containers_nest_level, ++ default_max_num_secrets, ++ default_max_payload, ++ &hive_config->quota); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read quota settings for %s [%d]: %s\n", ++ hive_name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static int sec_get_config(struct sec_ctx *sctx) + { + int ret; +@@ -48,39 +142,32 @@ static int sec_get_config(struct sec_ctx *sctx) + goto fail; + } + +- ret = confdb_get_int(sctx->rctx->cdb, +- sctx->rctx->confdb_service_path, +- CONFDB_SEC_CONTAINERS_NEST_LEVEL, +- DEFAULT_SEC_CONTAINERS_NEST_LEVEL, +- &sctx->sec_config.quota.containers_nest_level); +- +- if (ret != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to get containers' maximum depth\n"); +- goto fail; +- } +- +- ret = confdb_get_int(sctx->rctx->cdb, +- sctx->rctx->confdb_service_path, +- CONFDB_SEC_MAX_SECRETS, +- DEFAULT_SEC_MAX_SECRETS, +- &sctx->sec_config.quota.max_secrets); +- ++ /* Read the global quota first -- this should be removed in a future release */ ++ /* Note that this sets the defaults for the sec_config quota to be used ++ * in sec_get_hive_config() ++ */ ++ ret = sec_get_quota(sctx, ++ sctx->rctx->confdb_service_path, ++ DEFAULT_SEC_CONTAINERS_NEST_LEVEL, ++ DEFAULT_SEC_MAX_SECRETS, ++ DEFAULT_SEC_MAX_PAYLOAD_SIZE, ++ &sctx->sec_config.quota); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to get maximum number of entries\n"); ++ "Failed to get legacy global quotas\n"); + goto fail; + } + +- ret = confdb_get_int(sctx->rctx->cdb, +- sctx->rctx->confdb_service_path, +- CONFDB_SEC_MAX_PAYLOAD_SIZE, +- DEFAULT_SEC_MAX_PAYLOAD_SIZE, +- &sctx->sec_config.quota.max_payload_size); +- ++ /* Read the per-hive configuration */ ++ ret = sec_get_hive_config(sctx, ++ "secrets", ++ &sctx->sec_config, ++ sctx->sec_config.quota.containers_nest_level, ++ sctx->sec_config.quota.max_secrets, ++ sctx->sec_config.quota.max_payload_size); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to get payload's maximum size for an entry\n"); ++ "Failed to get configuration of the secrets hive\n"); + goto fail; + } + +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index 32ea58ff017f01bc6a28f826d10dabff60761bcb..bb94ffb47666f964fae2764444f7d28f3b311145 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -169,36 +169,6 @@ def test_crd_ops(setup_for_secrets, secrets_cli): + cli.del_secret("foo") + assert str(err404.value).startswith("404") + +- # Don't allow storing more secrets after reaching the max +- # number of entries. +- MAX_SECRETS = 10 +- +- sec_value = "value" +- for x in range(MAX_SECRETS): +- cli.set_secret(str(x), sec_value) +- +- with pytest.raises(HTTPError) as err507: +- cli.set_secret(str(MAX_SECRETS), sec_value) +- assert str(err507.value).startswith("507") +- +- # Delete all stored secrets used for max secrets tests +- for x in range(MAX_SECRETS): +- cli.del_secret(str(x)) +- +- # Don't allow storing a secrets which has a payload larger +- # than max_payload_size +- KILOBYTE = 1024 +- MAX_PAYLOAD_SIZE = 2 * KILOBYTE +- +- sec_value = "x" * MAX_PAYLOAD_SIZE +- +- cli.set_secret("foo", sec_value) +- +- sec_value += "x" +- with pytest.raises(HTTPError) as err413: +- cli.set_secret("bar", sec_value) +- assert str(err413.value).startswith("413") +- + + def run_curlwrap_tool(args, exp_http_code): + cmd = subprocess.Popen(args, +@@ -434,3 +404,98 @@ def test_idle_timeout(setup_for_cli_timeout_test): + + nfds_post = get_num_fds(secpid) + assert nfds_pre == nfds_post ++ ++ ++def run_quota_test(cli, max_secrets, max_payload_size): ++ sec_value = "value" ++ for x in range(max_secrets): ++ cli.set_secret(str(x), sec_value) ++ ++ with pytest.raises(HTTPError) as err507: ++ cli.set_secret(str(max_secrets), sec_value) ++ assert str(err507.value).startswith("507") ++ ++ # Delete all stored secrets used for max secrets tests ++ for x in range(max_secrets): ++ cli.del_secret(str(x)) ++ ++ # Don't allow storing a secrets which has a payload larger ++ # than max_payload_size ++ KILOBYTE = 1024 ++ kb_payload_size = max_payload_size * KILOBYTE ++ ++ sec_value = "x" * kb_payload_size ++ ++ cli.set_secret("foo", sec_value) ++ ++ sec_value += "x" ++ with pytest.raises(HTTPError) as err413: ++ cli.set_secret("bar", sec_value) ++ assert str(err413.value).startswith("413") ++ ++ ++@pytest.fixture ++def setup_for_global_quota(request): ++ conf = unindent("""\ ++ [sssd] ++ domains = local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [secrets] ++ max_secrets = 10 ++ max_payload_size = 2 ++ """).format(**locals()) ++ ++ create_conf_fixture(request, conf) ++ create_sssd_secrets_fixture(request) ++ return None ++ ++ ++def test_global_quota(setup_for_global_quota, secrets_cli): ++ """ ++ Test that the deprecated configuration of quotas in the global ++ secrets section is still supported ++ """ ++ cli = secrets_cli ++ ++ # Don't allow storing more secrets after reaching the max ++ # number of entries. ++ run_quota_test(cli, 10, 2) ++ ++ ++@pytest.fixture ++def setup_for_secrets_quota(request): ++ conf = unindent("""\ ++ [sssd] ++ domains = local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [secrets] ++ max_secrets = 5 ++ max_payload_size = 1 ++ ++ [secrets/secrets] ++ max_secrets = 10 ++ max_payload_size = 2 ++ """).format(**locals()) ++ ++ create_conf_fixture(request, conf) ++ create_sssd_secrets_fixture(request) ++ return None ++ ++ ++def test_sec_quota(setup_for_secrets_quota, secrets_cli): ++ """ ++ Test that the new secrets/secrets section takes precedence. ++ """ ++ cli = secrets_cli ++ ++ # Don't allow storing more secrets after reaching the max ++ # number of entries. ++ run_quota_test(cli, 10, 2) +-- +2.14.1 + diff --git a/0089-SECRETS-Rename-local_db_req.basedn-to-local_db_req.r.patch b/0089-SECRETS-Rename-local_db_req.basedn-to-local_db_req.r.patch new file mode 100644 index 0000000..cd971c1 --- /dev/null +++ b/0089-SECRETS-Rename-local_db_req.basedn-to-local_db_req.r.patch @@ -0,0 +1,135 @@ +From 392f48c039d7a6d70bce6ae2d122042391653566 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 4 Apr 2017 14:45:30 +0200 +Subject: [PATCH 89/93] SECRETS: Rename local_db_req.basedn to + local_db_req.req_dn +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will make it possible to reuse the basedn name later for the "hive" +base DN in order to differentiate quotas for different hives. + +There is no functional change in this patch. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/responder/secrets/local.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 0b879939f25487b0275d5144f5e27b2873b3fbae..c833f1d27b42e4a453ac62d29d7649ff80200fba 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -206,7 +206,7 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx, + + struct local_db_req { + char *path; +- struct ldb_dn *basedn; ++ struct ldb_dn *req_dn; + }; + + #define LOCAL_SIMPLE_FILTER "(type=simple)" +@@ -231,9 +231,9 @@ static int local_db_get_simple(TALLOC_CTX *mem_ctx, + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=base\n", +- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); ++ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->req_dn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->req_dn, LDB_SCOPE_BASE, + attrs, "%s", LOCAL_SIMPLE_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -297,9 +297,9 @@ static int local_db_list_keys(TALLOC_CTX *mem_ctx, + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=subtree\n", +- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); ++ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->req_dn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_SUBTREE, ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->req_dn, LDB_SCOPE_SUBTREE, + attrs, "%s", LOCAL_SIMPLE_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -321,7 +321,7 @@ static int local_db_list_keys(TALLOC_CTX *mem_ctx, + } + + for (unsigned i = 0; i < res->count; i++) { +- keys[i] = local_dn_to_path(keys, lc_req->basedn, res->msgs[i]->dn); ++ keys[i] = local_dn_to_path(keys, lc_req->req_dn, res->msgs[i]->dn); + if (!keys[i]) { + ret = ENOMEM; + goto done; +@@ -483,7 +483,7 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, + ret = ENOMEM; + goto done; + } +- msg->dn = lc_req->basedn; ++ msg->dn = lc_req->req_dn; + + /* make sure containers exist */ + ret = local_db_check_containers(msg, lctx, msg->dn); +@@ -587,9 +587,9 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=base\n", +- LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(lc_req->basedn)); ++ LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(lc_req->req_dn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->req_dn, LDB_SCOPE_BASE, + attrs, LOCAL_CONTAINER_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -599,8 +599,8 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, + + if (res->count == 1) { + DEBUG(SSSDBG_TRACE_INTERNAL, +- "Searching for children of [%s]\n", ldb_dn_get_linearized(lc_req->basedn)); +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_ONELEVEL, ++ "Searching for children of [%s]\n", ldb_dn_get_linearized(lc_req->req_dn)); ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->req_dn, LDB_SCOPE_ONELEVEL, + attrs, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -612,13 +612,13 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, + ret = EEXIST; + DEBUG(SSSDBG_OP_FAILURE, + "Failed to remove '%s': Container is not empty\n", +- ldb_dn_get_linearized(lc_req->basedn)); ++ ldb_dn_get_linearized(lc_req->req_dn)); + + goto done; + } + } + +- ret = ldb_delete(lctx->ldb, lc_req->basedn); ++ ret = ldb_delete(lctx->ldb, lc_req->req_dn); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, + "ldb_delete returned %d: %s\n", ret, ldb_strerror(ret)); +@@ -645,7 +645,7 @@ static int local_db_create(TALLOC_CTX *mem_ctx, + ret = ENOMEM; + goto done; + } +- msg->dn = lc_req->basedn; ++ msg->dn = lc_req->req_dn; + + /* make sure containers exist */ + ret = local_db_check_containers(msg, lctx, msg->dn); +@@ -760,7 +760,7 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->basedn); ++ ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->req_dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to map request to local db DN\n"); +-- +2.14.1 + diff --git a/0090-SECRETS-Use-separate-quotas-for-kcm-and-secrets-hive.patch b/0090-SECRETS-Use-separate-quotas-for-kcm-and-secrets-hive.patch new file mode 100644 index 0000000..d86ea03 --- /dev/null +++ b/0090-SECRETS-Use-separate-quotas-for-kcm-and-secrets-hive.patch @@ -0,0 +1,318 @@ +From 197da163943868216f704fb34031e7d5576e8aee Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 4 Apr 2017 15:33:38 +0200 +Subject: [PATCH 90/93] SECRETS: Use separate quotas for /kcm and /secrets + hives +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This would differentiate between out-of-capacity errors for secrets and +for KCM as they are two independent trees as far as sssd-secrets is +concerned. + +The quotas for /kcm are also different in their defaults. For the /secrets +hive, we presume a large amount of small secrets. For the /kcm hive, we +presume a small amount of large secrets, because the secret is a ccache +which contains multiple credentials. + +The operations are also passed in a struct quota from the local request +context instead of local_context. The quota is assigned to the request +context when the hive is selected. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/config/cfg_rules.ini | 3 ++- + src/man/sssd-secrets.5.xml | 4 ++-- + src/responder/secrets/local.c | 46 ++++++++++++++++++++++++------------------ + src/responder/secrets/secsrv.c | 20 ++++++++++++++++++ + src/responder/secrets/secsrv.h | 1 + + 5 files changed, 51 insertions(+), 23 deletions(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index a963eb49c9010924bda6a48c47d80c868ffd6ddd..7590f1f5aa516c0af899371a1b7a826512469de3 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -13,6 +13,7 @@ section = kcm + section = session_recording + section_re = ^secrets/users/[0-9]\+$ + section_re = ^secrets/secrets$ ++section_re = ^secrets/kcm$ + section_re = ^domain/[^/\@]\+$ + section_re = ^domain/[^/\@]\+/[^/\@]\+$ + section_re = ^application/[^/\@]\+$ +@@ -259,7 +260,7 @@ option = responder_idle_timeout + + [rule/allowed_sec_hive_options] + validator = ini_allowed_options +-section_re = ^secrets/secrets$ ++section_re = ^secrets/\(secrets\|kcm\)$ + + # Secrets service - per-hive configuration + option = containers_nest_level +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index d50cb13d8a0dcbdb7919c1e38d6d5976dcc2abf1..ba77d623274237951de5d42bb8cff9f6d56f5fff 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -196,7 +196,7 @@ systemctl enable sssd-secrets.service + can be stored in the hive. + + +- Default: 1024 ++ Default: 1024 (secrets hive), 256 (kcm hive) + + + +@@ -208,7 +208,7 @@ systemctl enable sssd-secrets.service + a secret payload in kilobytes. + + +- Default: 16 ++ Default: 16 (secrets hive), 65536 (64 MiB) (kcm hive) + + + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index c833f1d27b42e4a453ac62d29d7649ff80200fba..58e70f8b6d00976ccc86d4fbf687417dd3c3c06a 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -36,6 +36,7 @@ struct local_context { + struct sec_data master_key; + + struct sec_quota *quota_secrets; ++ struct sec_quota *quota_kcm; + }; + + static int local_decrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx, +@@ -206,7 +207,9 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx, + + struct local_db_req { + char *path; ++ const char *basedn; + struct ldb_dn *req_dn; ++ struct sec_quota *quota; + }; + + #define LOCAL_SIMPLE_FILTER "(type=simple)" +@@ -389,7 +392,7 @@ done: + return ret; + } + +-static int local_db_check_containers_nest_level(struct local_context *lctx, ++static int local_db_check_containers_nest_level(struct local_db_req *lc_req, + struct ldb_dn *leaf_dn) + { + int nest_level; +@@ -397,11 +400,11 @@ static int local_db_check_containers_nest_level(struct local_context *lctx, + /* We need do not care for the synthetic containers that constitute the + * base path (cn=,cn=user,cn=secrets). */ + nest_level = ldb_dn_get_comp_num(leaf_dn) - 3; +- if (nest_level > lctx->quota_secrets->containers_nest_level) { ++ if (nest_level > lc_req->quota->containers_nest_level) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot create a nested container of depth %d as the maximum" + "allowed number of nested containers is %d.\n", +- nest_level, lctx->quota_secrets->containers_nest_level); ++ nest_level, lc_req->quota->containers_nest_level); + + return ERR_SEC_INVALID_CONTAINERS_NEST_LEVEL; + } +@@ -410,7 +413,8 @@ static int local_db_check_containers_nest_level(struct local_context *lctx, + } + + static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, +- struct local_context *lctx) ++ struct local_context *lctx, ++ struct local_db_req *lc_req) + { + TALLOC_CTX *tmp_ctx; + static const char *attrs[] = { NULL }; +@@ -421,7 +425,7 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +- dn = ldb_dn_new(tmp_ctx, lctx->ldb, "cn=secrets"); ++ dn = ldb_dn_new(tmp_ctx, lctx->ldb, lc_req->basedn); + if (!dn) { + ret = ENOMEM; + goto done; +@@ -429,11 +433,10 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + + ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, + attrs, LOCAL_SIMPLE_FILTER); +- if (res->count >= lctx->quota_secrets->max_secrets) { ++ if (res->count >= lc_req->quota->max_secrets) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot store any more secrets as the maximum allowed limit (%d) " +- "has been reached\n", lctx->quota_secrets->max_secrets); +- ++ "has been reached\n", lc_req->quota->max_secrets); + ret = ERR_SEC_INVALID_TOO_MANY_SECRETS; + goto done; + } +@@ -445,19 +448,19 @@ done: + return ret; + } + +-static int local_check_max_payload_size(struct local_context *lctx, ++static int local_check_max_payload_size(struct local_db_req *lc_req, + int payload_size) + { + int max_payload_size; + +- max_payload_size = lctx->quota_secrets->max_payload_size * 1024; /* kb */ ++ max_payload_size = lc_req->quota->max_payload_size * 1024; /* kb */ + if (payload_size > max_payload_size) { + DEBUG(SSSDBG_OP_FAILURE, + "Secrets' payload size [%d kb (%d)] exceeds the maximum allowed " + "payload size [%d kb (%d)]\n", + payload_size * 1024, /* kb */ + payload_size, +- lctx->quota_secrets->max_payload_size, /* kb */ ++ lc_req->quota->max_payload_size, /* kb */ + max_payload_size); + + return ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE; +@@ -494,7 +497,7 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = local_db_check_number_of_secrets(msg, lctx); ++ ret = local_db_check_number_of_secrets(msg, lctx, lc_req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_db_check_number_of_secrets failed [%d]: %s\n", +@@ -502,7 +505,7 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = local_check_max_payload_size(lctx, strlen(secret)); ++ ret = local_check_max_payload_size(lc_req, strlen(secret)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_check_max_payload_size failed [%d]: %s\n", +@@ -656,7 +659,7 @@ static int local_db_create(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = local_db_check_containers_nest_level(lctx, msg->dn); ++ ret = local_db_check_containers_nest_level(lc_req, msg->dn); + if (ret != EOK) goto done; + + ret = ldb_msg_add_string(msg, "type", "container"); +@@ -698,13 +701,13 @@ done: + } + + static int local_secrets_map_path(TALLOC_CTX *mem_ctx, +- struct ldb_context *ldb, ++ struct local_context *lctx, + struct sec_req_ctx *secreq, + struct local_db_req **_lc_req) + { + int ret; + struct local_db_req *lc_req; +- const char *basedn; ++ struct ldb_context *ldb = lctx->ldb; + + /* be strict for now */ + if (secreq->parsed_url.fragment != NULL) { +@@ -742,12 +745,14 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, + SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1) == 0) { + lc_req->path = talloc_strdup(lc_req, + secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1)); +- basedn = SECRETS_BASEDN; ++ lc_req->basedn = SECRETS_BASEDN; ++ lc_req->quota = lctx->quota_secrets; + } else if (strncmp(secreq->mapped_path, + SEC_KCM_BASEPATH, sizeof(SEC_KCM_BASEPATH) - 1) == 0) { + lc_req->path = talloc_strdup(lc_req, + secreq->mapped_path + (sizeof(SEC_KCM_BASEPATH) - 1)); +- basedn = KCM_BASEDN; ++ lc_req->basedn = KCM_BASEDN; ++ lc_req->quota = lctx->quota_kcm; + } else { + ret = EINVAL; + goto done; +@@ -760,7 +765,7 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->req_dn); ++ ret = local_db_dn(mem_ctx, ldb, lc_req->basedn, lc_req->path, &lc_req->req_dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to map request to local db DN\n"); +@@ -829,7 +834,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + } + DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type); + +- ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req); ++ ret = local_secrets_map_path(state, lctx, secreq, &lc_req); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot map request path to local path\n"); + goto done; +@@ -1019,6 +1024,7 @@ int local_secrets_provider_handle(struct sec_ctx *sctx, + } + + lctx->quota_secrets = &sctx->sec_config.quota; ++ lctx->quota_kcm = &sctx->kcm_config.quota; + + lctx->master_key.data = talloc_size(lctx, MKEY_SIZE); + if (!lctx->master_key.data) return ENOMEM; +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index db12cbbc3eb9317b6d449a5d2b2d370afebf247e..2fcdf8e6c74eaccc75f1017efdc854fa065baf74 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -30,9 +30,17 @@ + + #define DEFAULT_SEC_FD_LIMIT 2048 + #define DEFAULT_SEC_CONTAINERS_NEST_LEVEL 4 ++ + #define DEFAULT_SEC_MAX_SECRETS 1024 + #define DEFAULT_SEC_MAX_PAYLOAD_SIZE 16 + ++/* The number of secrets in the /kcm hive should be quite small, ++ * but the secret size must be large because one secret in the /kcm ++ * hive holds the whole ccache which consists of several credentials ++ */ ++#define DEFAULT_SEC_KCM_MAX_SECRETS 256 ++#define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536 ++ + static int sec_get_quota(struct sec_ctx *sctx, + const char *section_config_path, + int default_max_containers_nest_level, +@@ -171,6 +179,18 @@ static int sec_get_config(struct sec_ctx *sctx) + goto fail; + } + ++ ret = sec_get_hive_config(sctx, ++ "kcm", ++ &sctx->kcm_config, ++ DEFAULT_SEC_CONTAINERS_NEST_LEVEL, ++ DEFAULT_SEC_KCM_MAX_SECRETS, ++ DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get configuration of the secrets hive\n"); ++ goto fail; ++ } ++ + ret = confdb_get_int(sctx->rctx->cdb, sctx->rctx->confdb_service_path, + CONFDB_RESPONDER_CLI_IDLE_TIMEOUT, + CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT, +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index 629b027f6966dd221d21d16ccfc75c99881935f8..afc092764d02671eaf2cadd6a0f2f168ba7da806 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -47,6 +47,7 @@ struct sec_ctx { + int fd_limit; + + struct sec_hive_config sec_config; ++ struct sec_hive_config kcm_config; + + struct provider_handle **providers; + }; +-- +2.14.1 + diff --git a/0091-TESTS-Test-that-ccaches-can-be-stored-after-max_secr.patch b/0091-TESTS-Test-that-ccaches-can-be-stored-after-max_secr.patch new file mode 100644 index 0000000..9d6218f --- /dev/null +++ b/0091-TESTS-Test-that-ccaches-can-be-stored-after-max_secr.patch @@ -0,0 +1,109 @@ +From 0558f270b3fbb0780e2a94602d455022b89f5381 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 4 Apr 2017 15:34:17 +0200 +Subject: [PATCH 91/93] TESTS: Test that ccaches can be stored after + max_secrets is reached for regular non-ccache secrets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Test that even when we store the maximum number of secrets, we can still +store kerberos credentials, but only until we reach the max_secrets +limit as well. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/tests/intg/test_kcm.py | 52 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 51 insertions(+), 1 deletion(-) + +diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py +index 72a3458c8c598bae1fe929c062990da0bcbc3063..b65e1d5300bb8014aee2493795dc39ce799e9440 100644 +--- a/src/tests/intg/test_kcm.py ++++ b/src/tests/intg/test_kcm.py +@@ -23,12 +23,16 @@ import pytest + import socket + import time + import signal ++from requests import HTTPError + + import kdc + import krb5utils + import config + from util import unindent + from test_secrets import create_sssd_secrets_fixture ++from secrets import SecretsLocalClient ++ ++MAX_SECRETS = 10 + + + class KcmTestEnv(object): +@@ -109,7 +113,7 @@ def create_sssd_kcm_fixture(sock_path, request): + return kcm_pid + + +-def create_sssd_conf(kcm_path, ccache_storage): ++def create_sssd_conf(kcm_path, ccache_storage, max_secrets=MAX_SECRETS): + return unindent("""\ + [sssd] + domains = local +@@ -121,6 +125,9 @@ def create_sssd_conf(kcm_path, ccache_storage): + [kcm] + socket_path = {kcm_path} + ccache_storage = {ccache_storage} ++ ++ [secrets] ++ max_secrets = {max_secrets} + """).format(**locals()) + + +@@ -464,3 +471,46 @@ def test_kcm_sec_parallel_klist(setup_for_kcm_sec, + for p in processes: + rc = p.wait() + assert rc == 0 ++ ++ ++def get_secrets_socket(): ++ return os.path.join(config.RUNSTATEDIR, "secrets.socket") ++ ++ ++@pytest.fixture ++def secrets_cli(request): ++ sock_path = get_secrets_socket() ++ cli = SecretsLocalClient(sock_path=sock_path) ++ return cli ++ ++ ++def test_kcm_secrets_quota(setup_for_kcm_sec, ++ setup_secrets, ++ secrets_cli): ++ testenv = setup_for_kcm_sec ++ cli = secrets_cli ++ ++ # Make sure the secrets store is depleted first ++ sec_value = "value" ++ for i in range(MAX_SECRETS): ++ cli.set_secret(str(i), sec_value) ++ ++ with pytest.raises(HTTPError) as err507: ++ cli.set_secret(str(MAX_SECRETS), sec_value) ++ assert str(err507.value).startswith("507") ++ ++ # We should still be able to store KCM ccaches, but no more ++ # than MAX_SECRETS ++ for i in range(MAX_SECRETS): ++ princ = "%s%d" % ("kcmtest", i) ++ testenv.k5kdc.add_principal(princ, princ) ++ ++ for i in range(MAX_SECRETS-1): ++ princ = "%s%d" % ("kcmtest", i) ++ out, _, _ = testenv.k5util.kinit(princ, princ) ++ assert out == 0 ++ ++ # we stored 0 to MAX_SECRETS-1, storing another one must fail ++ princ = "%s%d" % ("kcmtest", MAX_SECRETS) ++ out, _, _ = testenv.k5util.kinit(princ, princ) ++ assert out != 0 +-- +2.14.1 + diff --git a/0092-SECRETS-Add-a-new-option-to-control-per-UID-limits.patch b/0092-SECRETS-Add-a-new-option-to-control-per-UID-limits.patch new file mode 100644 index 0000000..77fba57 --- /dev/null +++ b/0092-SECRETS-Add-a-new-option-to-control-per-UID-limits.patch @@ -0,0 +1,375 @@ +From 6b3bab516355fdf4cc81e6da9d87ec3818ab190f Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 5 Jun 2017 16:10:55 +0200 +Subject: [PATCH 92/93] SECRETS: Add a new option to control per-UID limits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new option max_uid_secrets that allows to set a limit of secrets +for this particular client so that the user cannot starve other users. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3363 + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/confdb/confdb.h | 1 + + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd-secrets.5.xml | 12 +++++ + src/responder/secrets/local.c | 93 ++++++++++++++++++++++++++++++++++++ + src/responder/secrets/secsrv.c | 23 ++++++++- + src/responder/secrets/secsrv.h | 1 + + src/tests/intg/test_secrets.py | 46 ++++++++++++++++++ + 9 files changed, 178 insertions(+), 1 deletion(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 4abc95b8183f1b430f770b55e8af0e43f65889a3..bcea99ae49a3fa5f0393ce6b2c215b5b2d4bc3fc 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -246,6 +246,7 @@ + #define CONFDB_SEC_CONF_ENTRY "config/secrets" + #define CONFDB_SEC_CONTAINERS_NEST_LEVEL "containers_nest_level" + #define CONFDB_SEC_MAX_SECRETS "max_secrets" ++#define CONFDB_SEC_MAX_UID_SECRETS "max_uid_secrets" + #define CONFDB_SEC_MAX_PAYLOAD_SIZE "max_payload_size" + + /* KCM Service */ +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 8c56e4efa4ae7c648f670bb6a67290b6e835f581..227f76180686d33cf87aeed55232f33eb02f138f 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -129,6 +129,7 @@ option_strings = { + 'provider': _('The provider where the secrets will be stored in'), + 'containers_nest_level': _('The maximum allowed number of nested containers'), + 'max_secrets': _('The maximum number of secrets that can be stored'), ++ 'max_uid_secrets': _('The maximum number of secrets that can be stored per UID'), + 'max_payload_size': _('The maximum payload size of a secret in kilobytes'), + # secrets - proxy + 'proxy_url': _('The URL Custodia server is listening on'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 7590f1f5aa516c0af899371a1b7a826512469de3..3e4ce46734a6686bb6ad38f52710def4f069d296 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -265,6 +265,7 @@ section_re = ^secrets/\(secrets\|kcm\)$ + # Secrets service - per-hive configuration + option = containers_nest_level + option = max_secrets ++option = max_uid_secrets + option = max_payload_size + + [rule/allowed_sec_users_options] +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 9eb6aeb83bbc1989cec7465e6442a1bf7762d9d8..792c42a1f01200d49c14dcba9516af0011e6e9c8 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -106,6 +106,7 @@ user_attributes = str, None, false + provider = str, None, false + containers_nest_level = int, None, false + max_secrets = int, None, false ++max_uid_secrets = int, None, false + max_payload_size = int, None, false + # Secrets service - proxy + proxy_url = str, None, false +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index ba77d623274237951de5d42bb8cff9f6d56f5fff..c74894c62ed70764ca680c3b1cfe7f903d280277 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -200,6 +200,18 @@ systemctl enable sssd-secrets.service + + + ++ ++ max_uid_secrets (integer) ++ ++ ++ This option specifies the maximum number of secrets that ++ can be stored per-UID in the hive. ++ ++ ++ Default: 256 (secrets hive), 64 (kcm hive) ++ ++ ++ + + max_payload_size (integer) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 58e70f8b6d00976ccc86d4fbf687417dd3c3c06a..5e491ba98fdc5612db0c303258513302c1f1d9e3 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -412,6 +412,85 @@ static int local_db_check_containers_nest_level(struct local_db_req *lc_req, + return EOK; + } + ++static struct ldb_dn *per_uid_container(TALLOC_CTX *mem_ctx, ++ struct ldb_dn *req_dn) ++{ ++ int user_comp; ++ int num_comp; ++ struct ldb_dn *uid_base_dn; ++ ++ uid_base_dn = ldb_dn_copy(mem_ctx, req_dn); ++ if (uid_base_dn == NULL) { ++ return NULL; ++ } ++ ++ /* Remove all the components up to the per-user base path which consists ++ * of three components: ++ * cn=,cn=users,cn=secrets ++ */ ++ user_comp = ldb_dn_get_comp_num(uid_base_dn) - 3; ++ ++ if (!ldb_dn_remove_child_components(uid_base_dn, user_comp)) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot remove child components\n"); ++ talloc_free(uid_base_dn); ++ return NULL; ++ } ++ ++ num_comp = ldb_dn_get_comp_num(uid_base_dn); ++ if (num_comp != 3) { ++ DEBUG(SSSDBG_OP_FAILURE, "Expected 3 components got %d\n", num_comp); ++ talloc_free(uid_base_dn); ++ return NULL; ++ } ++ ++ return uid_base_dn; ++} ++ ++static int local_db_check_peruid_number_of_secrets(TALLOC_CTX *mem_ctx, ++ struct local_context *lctx, ++ struct local_db_req *lc_req) ++{ ++ TALLOC_CTX *tmp_ctx; ++ static const char *attrs[] = { NULL }; ++ struct ldb_result *res = NULL; ++ struct ldb_dn *cli_basedn = NULL; ++ int ret; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ cli_basedn = per_uid_container(tmp_ctx, lc_req->req_dn); ++ if (cli_basedn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, cli_basedn, LDB_SCOPE_SUBTREE, ++ attrs, LOCAL_SIMPLE_FILTER); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "ldb_search returned %d: %s\n", ret, ldb_strerror(ret)); ++ goto done; ++ } ++ ++ if (res->count >= lc_req->quota->max_uid_secrets) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot store any more secrets for this client (basedn %s) " ++ "as the maximum allowed limit (%d) has been reached\n", ++ ldb_dn_get_linearized(cli_basedn), ++ lc_req->quota->max_uid_secrets); ++ ret = ERR_SEC_INVALID_TOO_MANY_SECRETS; ++ goto done; ++ } ++ ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + struct local_context *lctx, + struct local_db_req *lc_req) +@@ -433,6 +512,12 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + + ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, + attrs, LOCAL_SIMPLE_FILTER); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "ldb_search returned %d: %s\n", ret, ldb_strerror(ret)); ++ goto done; ++ } ++ + if (res->count >= lc_req->quota->max_secrets) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot store any more secrets as the maximum allowed limit (%d) " +@@ -505,6 +590,14 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = local_db_check_peruid_number_of_secrets(msg, lctx, lc_req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "local_db_check_number_of_secrets failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ + ret = local_check_max_payload_size(lc_req, strlen(secret)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index 2fcdf8e6c74eaccc75f1017efdc854fa065baf74..36b257c463ccaa1f552b2b4985932dc0d3b125aa 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -31,7 +31,8 @@ + #define DEFAULT_SEC_FD_LIMIT 2048 + #define DEFAULT_SEC_CONTAINERS_NEST_LEVEL 4 + +-#define DEFAULT_SEC_MAX_SECRETS 1024 ++#define DEFAULT_SEC_MAX_SECRETS 1024 ++#define DEFAULT_SEC_MAX_UID_SECRETS 256 + #define DEFAULT_SEC_MAX_PAYLOAD_SIZE 16 + + /* The number of secrets in the /kcm hive should be quite small, +@@ -39,12 +40,14 @@ + * hive holds the whole ccache which consists of several credentials + */ + #define DEFAULT_SEC_KCM_MAX_SECRETS 256 ++#define DEFAULT_SEC_KCM_MAX_UID_SECRETS 64 + #define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536 + + static int sec_get_quota(struct sec_ctx *sctx, + const char *section_config_path, + int default_max_containers_nest_level, + int default_max_num_secrets, ++ int default_max_num_uid_secrets, + int default_max_payload, + struct sec_quota *quota) + { +@@ -76,6 +79,19 @@ static int sec_get_quota(struct sec_ctx *sctx, + return ret; + } + ++ ret = confdb_get_int(sctx->rctx->cdb, ++ section_config_path, ++ CONFDB_SEC_MAX_UID_SECRETS, ++ default_max_num_uid_secrets, ++ "a->max_uid_secrets); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get maximum number of per-UID entries for %s\n", ++ section_config_path); ++ return ret; ++ } ++ + ret = confdb_get_int(sctx->rctx->cdb, + section_config_path, + CONFDB_SEC_MAX_PAYLOAD_SIZE, +@@ -97,6 +113,7 @@ static int sec_get_hive_config(struct sec_ctx *sctx, + struct sec_hive_config *hive_config, + int default_max_containers_nest_level, + int default_max_num_secrets, ++ int default_max_num_uid_secrets, + int default_max_payload) + { + int ret; +@@ -119,6 +136,7 @@ static int sec_get_hive_config(struct sec_ctx *sctx, + hive_config->confdb_section, + default_max_containers_nest_level, + default_max_num_secrets, ++ default_max_num_uid_secrets, + default_max_payload, + &hive_config->quota); + if (ret != EOK) { +@@ -158,6 +176,7 @@ static int sec_get_config(struct sec_ctx *sctx) + sctx->rctx->confdb_service_path, + DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + DEFAULT_SEC_MAX_SECRETS, ++ DEFAULT_SEC_MAX_UID_SECRETS, + DEFAULT_SEC_MAX_PAYLOAD_SIZE, + &sctx->sec_config.quota); + if (ret != EOK) { +@@ -172,6 +191,7 @@ static int sec_get_config(struct sec_ctx *sctx) + &sctx->sec_config, + sctx->sec_config.quota.containers_nest_level, + sctx->sec_config.quota.max_secrets, ++ sctx->sec_config.quota.max_uid_secrets, + sctx->sec_config.quota.max_payload_size); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +@@ -184,6 +204,7 @@ static int sec_get_config(struct sec_ctx *sctx) + &sctx->kcm_config, + DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + DEFAULT_SEC_KCM_MAX_SECRETS, ++ DEFAULT_SEC_KCM_MAX_UID_SECRETS, + DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index afc092764d02671eaf2cadd6a0f2f168ba7da806..afdd731fbd44d7bb280ffc0e55db9c39a926bf22 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -32,6 +32,7 @@ + + struct sec_quota { + int max_secrets; ++ int max_uid_secrets; + int max_payload_size; + int containers_nest_level; + }; +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index bb94ffb47666f964fae2764444f7d28f3b311145..957a0a8ff9ce5e966b77ddf048eefc282b2711b6 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -499,3 +499,49 @@ def test_sec_quota(setup_for_secrets_quota, secrets_cli): + # Don't allow storing more secrets after reaching the max + # number of entries. + run_quota_test(cli, 10, 2) ++ ++ ++@pytest.fixture ++def setup_for_uid_limit(request): ++ conf = unindent("""\ ++ [sssd] ++ domains = local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [secrets] ++ ++ [secrets/secrets] ++ max_secrets = 10 ++ max_uid_secrets = 5 ++ """).format(**locals()) ++ ++ create_conf_fixture(request, conf) ++ create_sssd_secrets_fixture(request) ++ return None ++ ++ ++def test_per_uid_limit(setup_for_uid_limit, secrets_cli): ++ """ ++ Test that per-UID limits are enforced even if the global limit would still ++ allow to store more secrets ++ """ ++ cli = secrets_cli ++ ++ # Don't allow storing more secrets after reaching the max ++ # number of entries. ++ MAX_UID_SECRETS = 5 ++ ++ sec_value = "value" ++ for i in range(MAX_UID_SECRETS): ++ cli.set_secret(str(i), sec_value) ++ ++ with pytest.raises(HTTPError) as err507: ++ cli.set_secret(str(MAX_UID_SECRETS), sec_value) ++ assert str(err507.value).startswith("507") ++ ++ # FIXME - at this point, it would be nice to test that another UID can ++ # still store secrets, but sadly socket_wrapper doesn't allow us to fake ++ # UIDs yet +-- +2.14.1 + diff --git a/0093-SECRETS-Support-0-as-unlimited-for-the-quotas.patch b/0093-SECRETS-Support-0-as-unlimited-for-the-quotas.patch new file mode 100644 index 0000000..adb4b27 --- /dev/null +++ b/0093-SECRETS-Support-0-as-unlimited-for-the-quotas.patch @@ -0,0 +1,251 @@ +From 109ed7ca1a82420798efdc6a9b019675a5bd0f4f Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 7 Jun 2017 17:20:43 +0200 +Subject: [PATCH 93/93] SECRETS: Support 0 as unlimited for the quotas +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a special value for all the quota-like settings that means 'no +limit'. + +Because the responder also had a global limit on the size of the +accepted body (64kiB), this patch also removes the hardcoded limit and +instead keep track of the biggest quota value on startup. + +Reviewed-by: Simo Sorce +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd-secrets.5.xml | 3 +- + src/responder/secrets/local.c | 16 ++++++++++ + src/responder/secrets/secsrv.c | 15 ++++++++++ + src/responder/secrets/secsrv.h | 1 + + src/responder/secrets/secsrv_cmd.c | 6 +++- + src/responder/secrets/secsrv_private.h | 2 +- + src/tests/intg/test_secrets.py | 55 ++++++++++++++++++++++++++++++++++ + 7 files changed, 95 insertions(+), 3 deletions(-) + +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index c74894c62ed70764ca680c3b1cfe7f903d280277..d43dcf21c6174f0e0780a76d831a1fd957358b51 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -173,7 +173,8 @@ systemctl enable sssd-secrets.service + + + The following options affect only the secrets hive +- and therefore should be set in a per-hive subsection. ++ and therefore should be set in a per-hive subsection. Setting the ++ option to 0 means "unlimited". + + + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 5e491ba98fdc5612db0c303258513302c1f1d9e3..5a8b67731137dd2597211dedf817b8a92a62aa05 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -397,6 +397,10 @@ static int local_db_check_containers_nest_level(struct local_db_req *lc_req, + { + int nest_level; + ++ if (lc_req->quota->containers_nest_level == 0) { ++ return EOK; ++ } ++ + /* We need do not care for the synthetic containers that constitute the + * base path (cn=,cn=user,cn=secrets). */ + nest_level = ldb_dn_get_comp_num(leaf_dn) - 3; +@@ -456,6 +460,10 @@ static int local_db_check_peruid_number_of_secrets(TALLOC_CTX *mem_ctx, + struct ldb_dn *cli_basedn = NULL; + int ret; + ++ if (lc_req->quota->max_uid_secrets == 0) { ++ return EOK; ++ } ++ + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; +@@ -501,6 +509,10 @@ static int local_db_check_number_of_secrets(TALLOC_CTX *mem_ctx, + struct ldb_dn *dn; + int ret; + ++ if (lc_req->quota->max_secrets == 0) { ++ return EOK; ++ } ++ + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +@@ -538,6 +550,10 @@ static int local_check_max_payload_size(struct local_db_req *lc_req, + { + int max_payload_size; + ++ if (lc_req->quota->max_payload_size == 0) { ++ return EOK; ++ } ++ + max_payload_size = lc_req->quota->max_payload_size * 1024; /* kb */ + if (payload_size > max_payload_size) { + DEBUG(SSSDBG_OP_FAILURE, +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index 36b257c463ccaa1f552b2b4985932dc0d3b125aa..2b661b165ef0c174557f53012b2dbaa236a6e359 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -146,6 +146,16 @@ static int sec_get_hive_config(struct sec_ctx *sctx, + goto done; + } + ++ if (hive_config->quota.max_payload_size == 0 ++ || (sctx->max_payload_size != 0 ++ && hive_config->quota.max_payload_size > sctx->max_payload_size)) { ++ /* If the quota is unlimited or it's larger than what ++ * we already have, save the total limit so we know how much to ++ * accept from clients ++ */ ++ sctx->max_payload_size = hive_config->quota.max_payload_size; ++ } ++ + ret = EOK; + + done: +@@ -168,6 +178,11 @@ static int sec_get_config(struct sec_ctx *sctx) + goto fail; + } + ++ /* Set the global max_payload to ridiculously small value so that either 0 (unlimited) ++ * or any sensible value overwrite it ++ */ ++ sctx->max_payload_size = 1; ++ + /* Read the global quota first -- this should be removed in a future release */ + /* Note that this sets the defaults for the sec_config quota to be used + * in sec_get_hive_config() +diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h +index afdd731fbd44d7bb280ffc0e55db9c39a926bf22..3023116402f8540dcf4436dcc0b6ea030d892468 100644 +--- a/src/responder/secrets/secsrv.h ++++ b/src/responder/secrets/secsrv.h +@@ -49,6 +49,7 @@ struct sec_ctx { + + struct sec_hive_config sec_config; + struct sec_hive_config kcm_config; ++ int max_payload_size; + + struct provider_handle **providers; + }; +diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c +index b88680c3d7c3105d160de5c78e6d981b852318b9..fa5970504d9f67c6341ebd8276da76f0b608fd55 100644 +--- a/src/responder/secrets/secsrv_cmd.c ++++ b/src/responder/secrets/secsrv_cmd.c +@@ -178,7 +178,8 @@ static void sec_append_string(TALLOC_CTX *memctx, char **dest, + static bool sec_too_much_data(struct sec_req_ctx *req, size_t length) + { + req->total_size += length; +- if (req->total_size > SEC_REQUEST_MAX_SIZE) { ++ if (req->max_payload_size > 0 ++ && req->total_size > req->max_payload_size) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Request too big, aborting client!\n"); + return true; +@@ -513,6 +514,8 @@ static void sec_recv(struct cli_ctx *cctx) + { + struct sec_proto_ctx *prctx; + struct sec_req_ctx *req; ++ struct sec_ctx *sec_ctx = talloc_get_type(cctx->rctx->pvt_ctx, ++ struct sec_ctx); + char buffer[SEC_PACKET_MAX_RECV_SIZE]; + struct sec_data data = { buffer, + SEC_PACKET_MAX_RECV_SIZE }; +@@ -531,6 +534,7 @@ static void sec_recv(struct cli_ctx *cctx) + return; + } + req->cctx = cctx; ++ req->max_payload_size = sec_ctx->max_payload_size; + cctx->state_ctx = req; + http_parser_init(&prctx->parser, HTTP_REQUEST); + prctx->parser.data = req; +diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h +index 2e68628f61a0a8e79cd48fb5a510221e6fc36c70..c4a0c5745e8db092d28cf1ef9cb397af0c7314cb 100644 +--- a/src/responder/secrets/secsrv_private.h ++++ b/src/responder/secrets/secsrv_private.h +@@ -75,6 +75,7 @@ struct sec_req_ctx { + bool complete; + + size_t total_size; ++ size_t max_payload_size; + + char *request_url; + char *mapped_path; +@@ -151,7 +152,6 @@ bool sec_req_has_header(struct sec_req_ctx *req, + const char *name, const char *value); + + /* secsrv_cmd.c */ +-#define SEC_REQUEST_MAX_SIZE 65536 + #define SEC_PACKET_MAX_RECV_SIZE 8192 + + int sec_send_data(int fd, struct sec_data *data); +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index 957a0a8ff9ce5e966b77ddf048eefc282b2711b6..15caa69582ea6fe5031df8150343412f0e68bd5e 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -545,3 +545,58 @@ def test_per_uid_limit(setup_for_uid_limit, secrets_cli): + # FIXME - at this point, it would be nice to test that another UID can + # still store secrets, but sadly socket_wrapper doesn't allow us to fake + # UIDs yet ++ ++ ++@pytest.fixture ++def setup_for_unlimited_quotas(request): ++ conf = unindent("""\ ++ [sssd] ++ domains = local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [secrets] ++ debug_level = 10 ++ ++ [secrets/secrets] ++ max_secrets = 0 ++ max_uid_secrets = 0 ++ max_payload_size = 0 ++ containers_nest_level = 0 ++ """).format(**locals()) ++ ++ create_conf_fixture(request, conf) ++ create_sssd_secrets_fixture(request) ++ return None ++ ++ ++def test_unlimited_quotas(setup_for_unlimited_quotas, secrets_cli): ++ """ ++ Test that setting quotas to zero disabled any checks and lets ++ store whatever. ++ """ ++ cli = secrets_cli ++ ++ # test much larger amount of secrets that we allow by default ++ sec_value = "value" ++ for i in range(2048): ++ cli.set_secret(str(i), sec_value) ++ ++ # test a much larger secret size than the default one ++ KILOBYTE = 1024 ++ payload_size = 32 * KILOBYTE ++ ++ sec_value = "x" * payload_size ++ cli.set_secret("foo", sec_value) ++ ++ fooval = cli.get_secret("foo") ++ assert fooval == sec_value ++ ++ # test a deep secret nesting structure ++ DEFAULT_CONTAINERS_NEST_LEVEL = 128 ++ container = "mycontainer" ++ for i in range(DEFAULT_CONTAINERS_NEST_LEVEL): ++ container += "%s/" % str(i) ++ cli.create_container(container) +-- +2.14.1 + diff --git a/sssd.spec b/sssd.spec index f5739db..624a808 100644 --- a/sssd.spec +++ b/sssd.spec @@ -32,7 +32,7 @@ Name: sssd Version: 1.15.3 -Release: 2%{?dist} +Release: 3%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -41,7 +41,99 @@ Source0: https://releases.pagure.org/SSSD/sssd/%{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### -Patch0501: 0501-libwbclient-sssd-update-interface-to-version-0.14.patch +Patch0001: 0001-Fix-minor-typos.patch +Patch0002: 0002-CACHE_REQ-Propagate-num_results-to-cache_req_state.patch +Patch0003: 0003-NSS-Move-shell-options-to-common-responder.patch +Patch0004: 0004-NSS-Move-nss_get_shell_override-to-responder-utils.patch +Patch0005: 0005-CONFIG-Add-session_recording-section.patch +Patch0006: 0006-BUILD-Support-configuring-session-recording-shell.patch +Patch0007: 0007-UTIL-Add-session-recording-conf-management-module.patch +Patch0008: 0008-RESPONDER-Add-session-recording-conf-loading.patch +Patch0009: 0009-DP-Add-session-recording-conf-loading.patch +Patch0010: 0010-SYSDB-Add-sessionRecording-attribute-macro.patch +Patch0011: 0011-DP-Load-override_space-into-be_ctx.patch +Patch0012: 0012-DP-Update-viewname-for-all-providers.patch +Patch0013: 0013-DP-Overlay-sessionRecording-attribute-on-initgr.patch +Patch0014: 0014-CACHE_REQ-Pull-sessionRecording-attrs-from-initgr.patch +Patch0015: 0015-NSS-Substitute-session-recording-shell.patch +Patch0016: 0016-PAM-Export-original-shell-to-tlog-rec-session.patch +Patch0017: 0017-INTG-Add-session-recording-tests.patch +Patch0018: 0018-MAN-Describe-session-recording-configuration.patch +Patch0019: 0019-SPEC-Use-language-file-for-sssd-kcm.patch +Patch0020: 0020-MAN-Don-t-tell-the-user-to-autostart-sssd-kcm.servic.patch +Patch0021: 0021-CACHE_REQ-Fix-warning-may-be-used-uninitialized.patch +Patch0022: 0022-INTG-Add-with-session-recording-bin-false-to-intgche.patch +Patch0023: 0023-Moving-headers-used-by-both-server-and-client-to-spe.patch +Patch0024: 0024-libwbclient-sssd-update-interface-to-version-0.14.patch +Patch0025: 0025-IFP-Do-not-fail-when-a-GHOST-group-is-not-found.patch +Patch0026: 0026-SHARED-Return-warning-back-about-minimal-header-file.patch +Patch0027: 0027-intg-Disable-add_remove-tests.patch +Patch0028: 0028-UTIL-Set-udp_preference_limit-0-in-krb5-snippet.patch +Patch0029: 0029-Fix-minor-typos.patch +Patch0030: 0030-Fix-minor-typos-in-docs.patch +Patch0031: 0031-SPEC-require-http-parser-only-on-rhel7.4.patch +Patch0032: 0032-intg-Increase-startup-timeouts-for-kcm-and-secrets.patch +Patch0033: 0033-sudo-add-a-threshold-option-to-reduce-size-of-rules-.patch +Patch0034: 0034-libwbclient-Change-return-code-for-wbcAuthenticateUs.patch +Patch0035: 0035-libwbclient-Fix-warning-statement-with-no-effect.patch +Patch0036: 0036-ldap_child-Removing-duplicate-log-message.patch +Patch0037: 0037-IFP-fix-typo-in-option-name-in-man-pages.patch +Patch0038: 0038-IFP-Filter-with-in-infopipe-group-methods.patch +Patch0039: 0039-IFP-Fix-of-limit-0-unlimited-result.patch +Patch0040: 0040-IFP-Change-ifp_list_ctx_remaining_capacity-return-ty.patch +Patch0041: 0041-IFP-Don-t-pre-allocate-the-amount-of-entries-request.patch +Patch0042: 0042-IPA_ACCESS-Remove-not-used-attribute.patch +Patch0043: 0043-IPA-Make-ipa_hbac_sysdb_save-more-generic.patch +Patch0044: 0044-IPA-Leave-only-HBAC-specific-defines-in-ipa_hbac_pri.patch +Patch0045: 0045-IPA_ACCESS-Make-hbac_get_cache_rules-more-generic.patch +Patch0046: 0046-IPA_ACCESS-Make-ipa_purge_hbac-more-generic.patch +Patch0047: 0047-IPA_RULES_COMMON-Introduce-ipa_common_save_rules.patch +Patch0048: 0048-IPA_RULES_COMMON-Introduce-ipa_common_get_hostgroupn.patch +Patch0049: 0049-IPA_ACCESS-Make-use-of-struct-ipa_common_entries.patch +Patch0050: 0050-IPA_COMMON-Introduce-ipa_get_host_attrs.patch +Patch0051: 0051-UTIL-move-files-selinux-.c-under-util-directory.patch +Patch0052: 0052-UTIL-Add-sss_create_dir.patch +Patch0053: 0053-DESKPROFILE-Introduce-the-new-IPA-session-provider.patch +Patch0054: 0054-HBAC-Fix-tevent-hierarchy-in-ipa_hbac_rule_info_send.patch +Patch0055: 0055-HBAC-Document-ipa_hbac_rule_info_next-s-behaviour.patch +Patch0056: 0056-HBAC-Remove-a-cosmetic-extra-space-from-an-if-clause.patch +Patch0057: 0057-HBAC-Improve-readability-of-ipa_hbac_rule_info_send.patch +Patch0058: 0058-HBAC-Enforce-coding-style-on-ipa_hbac_rule_info_send.patch +Patch0059: 0059-HBAC-Enforce-coding-style-ipa_hbac_rule_info_recv.patch +Patch0060: 0060-HBAC-Add-a-debug-message-in-case-ipa_hbac_rule_info_.patch +Patch0061: 0061-HBAC-Not-having-rules-should-not-be-logged-as-error.patch +Patch0062: 0062-DESKPROFILE-Add-ipa_deskprofile_request_interval.patch +Patch0063: 0063-NEGCACHE-Add-some-comments-about-each-step-of-sss_nc.patch +Patch0064: 0064-NEGCACHE-Always-add-root-to-the-negative-cache.patch +Patch0065: 0065-TEST_NEGCACHE-Test-that-root-is-always-added-to-ncac.patch +Patch0066: 0066-NEGCACHE-Descend-to-all-subdomains-when-adding-user-.patch +Patch0067: 0067-CACHE_REQ-Don-t-error-out-when-searching-by-id-0.patch +Patch0068: 0068-NSS-Don-t-error-out-when-deleting-an-entry-which-has.patch +Patch0069: 0069-NEGCACHE-Add-root-s-uid-gid-to-ncache.patch +Patch0070: 0070-TEST_NEGCACHE-Ensure-root-s-uid-and-gid-are-always-a.patch +Patch0071: 0071-TESTS-Add-wrappers-to-request-a-user-or-a-group-by-I.patch +Patch0072: 0072-TESTS-Add-files-provider-tests-that-request-a-user-a.patch +Patch0073: 0073-TESTS-Add-regression-tests-to-try-if-resolving-root-.patch +Patch0074: 0074-localauth-plugin-change-return-code-of-sss_an2ln.patch +Patch0075: 0075-tests-add-unit-tests-for-krb5-localauth-plugin.patch +Patch0076: 0076-CONFDB-Set-a-default-value-for-subdomain_refresh_int.patch +Patch0077: 0077-CONFDB-Do-not-crash-with-an-invalid-domain_type-or-c.patch +Patch0078: 0078-SDAP-Add-a-debug-message-to-explain-why-a-backend-wa.patch +Patch0079: 0079-SDAP-Don-t-call-be_mark_offline-because-sdap_id_conn.patch +Patch0080: 0080-PYTHON-Define-constants-as-bytes-instead-of-strings.patch +Patch0081: 0081-IPA-format-fixes.patch +Patch0082: 0082-SPEC-rhel8-will-have-python3-as-well.patch +Patch0083: 0083-SPEC-Fix-unowned-directory.patch +Patch0084: 0084-IPA-Only-attempt-migration-for-the-joined-domain.patch +Patch0085: 0085-SECRETS-Remove-unused-declarations.patch +Patch0086: 0086-SECRETS-Do-not-link-with-c-ares.patch +Patch0087: 0087-SECRETS-Store-quotas-in-a-per-hive-configuration-str.patch +Patch0088: 0088-SECRETS-Read-the-quotas-for-cn-secrets-from-secrets-.patch +Patch0089: 0089-SECRETS-Rename-local_db_req.basedn-to-local_db_req.r.patch +Patch0090: 0090-SECRETS-Use-separate-quotas-for-kcm-and-secrets-hive.patch +Patch0091: 0091-TESTS-Test-that-ccaches-can-be-stored-after-max_secr.patch +Patch0092: 0092-SECRETS-Add-a-new-option-to-control-per-UID-limits.patch +Patch0093: 0093-SECRETS-Support-0-as-unlimited-for-the-quotas.patch Patch0502: 0502-SYSTEMD-Use-capabilities.patch ### Dependencies ### @@ -64,6 +156,7 @@ Suggests: sssd-dbus = %{version}-%{release} %global pubconfpath %{sssdstatedir}/pubconf %global gpocachepath %{sssdstatedir}/gpo_cache %global secdbpath %{sssdstatedir}/secrets +%global deskprofilepath %{sssdstatedir}/deskprofile ### Build Dependencies ### @@ -858,6 +951,7 @@ done %{_mandir}/man5/sssd-files.5* %{_mandir}/man5/sssd-simple.5* %{_mandir}/man5/sssd-sudo.5* +%{_mandir}/man5/sssd-session-recording.5* %{_mandir}/man5/sssd-secrets.5* %{_mandir}/man8/sssd.8* %{_mandir}/man8/sss_cache.8* @@ -1236,6 +1330,9 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Fri Sep 01 2017 Lukas Slebodnik - 1.15.3-3 +- Backport few upstream patches/fixes + * Thu Jul 27 2017 Fedora Release Engineering - 1.15.3-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild