diff options
author | Pavel Březina <pbrezina@redhat.com> | 2016-03-29 12:38:25 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2016-06-20 14:48:47 +0200 |
commit | dea636af4d1902a081ee891f1b19ee2f8729d759 (patch) | |
tree | a4d66ceb2b32ddf3b69bee1f1e2412568eae655e /src/providers/ldap | |
parent | 62370340092503baeaf6587d7ffe4fe25bd9582d (diff) | |
download | sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.gz sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.xz sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.zip |
DP: Switch to new interface
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/providers/ldap')
-rw-r--r-- | src/providers/ldap/ldap_access.c | 122 | ||||
-rw-r--r-- | src/providers/ldap/ldap_auth.c | 619 | ||||
-rw-r--r-- | src/providers/ldap/ldap_common.c | 6 | ||||
-rw-r--r-- | src/providers/ldap/ldap_common.h | 62 | ||||
-rw-r--r-- | src/providers/ldap/ldap_id.c | 300 | ||||
-rw-r--r-- | src/providers/ldap/ldap_init.c | 780 | ||||
-rw-r--r-- | src/providers/ldap/sdap_access.h | 11 | ||||
-rw-r--r-- | src/providers/ldap/sdap_autofs.c | 217 | ||||
-rw-r--r-- | src/providers/ldap/sdap_autofs.h | 8 | ||||
-rw-r--r-- | src/providers/ldap/sdap_idmap.c | 2 | ||||
-rw-r--r-- | src/providers/ldap/sdap_online_check.c | 249 | ||||
-rw-r--r-- | src/providers/ldap/sdap_sudo.c | 233 | ||||
-rw-r--r-- | src/providers/ldap/sdap_sudo.h | 8 |
13 files changed, 1490 insertions, 1127 deletions
diff --git a/src/providers/ldap/ldap_access.c b/src/providers/ldap/ldap_access.c index eb60f720d..4ec4702f9 100644 --- a/src/providers/ldap/ldap_access.c +++ b/src/providers/ldap/ldap_access.c @@ -29,90 +29,100 @@ #include "src/providers/ldap/sdap_access.h" #include "providers/ldap/ldap_common.h" -static void sdap_access_reply(struct be_req *be_req, int pam_status) -{ +struct sdap_pam_access_handler_state { struct pam_data *pd; - pd = talloc_get_type(be_req_get_data(be_req), struct pam_data); - pd->pam_status = pam_status; - - if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED - || pam_status == PAM_ACCT_EXPIRED) { - be_req_terminate(be_req, DP_ERR_OK, pam_status, NULL); - } else { - be_req_terminate(be_req, DP_ERR_FATAL, pam_status, NULL); - } -} +}; + +static void sdap_pam_access_handler_done(struct tevent_req *subreq); -static void sdap_access_done(struct tevent_req *req); -void sdap_pam_access_handler(struct be_req *breq) +struct tevent_req * +sdap_pam_access_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_access_ctx *access_ctx, + struct pam_data *pd, + struct dp_req_params *params) { - struct be_ctx *be_ctx = be_req_get_be_ctx(breq); - struct pam_data *pd; + struct sdap_pam_access_handler_state *state; + struct tevent_req *subreq; struct tevent_req *req; - struct sdap_access_ctx *access_ctx; - struct sss_domain_info *dom; - pd = talloc_get_type(be_req_get_data(breq), struct pam_data); + req = tevent_req_create(mem_ctx, &state, + struct sdap_pam_access_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } - access_ctx = - talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data, - struct sdap_access_ctx); + state->pd = pd; - dom = be_ctx->domain; - if (strcasecmp(pd->domain, be_ctx->domain->name) != 0) { - /* Subdomain request, verify subdomain */ - dom = find_domain_by_name(be_ctx->domain, pd->domain, true); + subreq = sdap_access_send(state, params->ev, params->be_ctx, + params->domain, access_ctx, + access_ctx->id_ctx->conn, pd); + if (subreq == NULL) { + pd->pam_status = PAM_SYSTEM_ERR; + goto immediately; } - req = sdap_access_send(breq, be_ctx->ev, be_ctx, - dom, access_ctx, - access_ctx->id_ctx->conn, - pd); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to start sdap_access request\n"); - sdap_access_reply(breq, PAM_SYSTEM_ERR); - return; - } + tevent_req_set_callback(subreq, sdap_pam_access_handler_done, req); + + return req; + +immediately: + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); - tevent_req_set_callback(req, sdap_access_done, breq); + return req; } -static void sdap_access_done(struct tevent_req *req) +static void sdap_pam_access_handler_done(struct tevent_req *subreq) { + struct sdap_pam_access_handler_state *state; + struct tevent_req *req; errno_t ret; - int pam_status; - struct be_req *breq = - tevent_req_callback_data(req, struct be_req); - ret = sdap_access_recv(req); - talloc_zfree(req); + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_pam_access_handler_state); + + ret = sdap_access_recv(subreq); + talloc_free(subreq); switch (ret) { case EOK: - pam_status = PAM_SUCCESS; - break; - case ERR_ACCESS_DENIED: - pam_status = PAM_PERM_DENIED; + case ERR_PASSWORD_EXPIRED_WARN: + state->pd->pam_status = PAM_SUCCESS; break; case ERR_ACCOUNT_EXPIRED: - pam_status = PAM_ACCT_EXPIRED; + state->pd->pam_status = PAM_ACCT_EXPIRED; break; + case ERR_ACCESS_DENIED: case ERR_PASSWORD_EXPIRED: - pam_status = PAM_PERM_DENIED; - break; case ERR_PASSWORD_EXPIRED_REJECT: - pam_status = PAM_PERM_DENIED; - break; - case ERR_PASSWORD_EXPIRED_WARN: - pam_status = PAM_SUCCESS; + state->pd->pam_status = PAM_PERM_DENIED; break; case ERR_PASSWORD_EXPIRED_RENEW: - pam_status = PAM_NEW_AUTHTOK_REQD; + state->pd->pam_status = PAM_NEW_AUTHTOK_REQD; break; default: DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result.\n"); - pam_status = PAM_SYSTEM_ERR; + state->pd->pam_status = PAM_SYSTEM_ERR; break; } - sdap_access_reply(breq, pam_status); + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); +} + +errno_t +sdap_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data) +{ + struct sdap_pam_access_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_pam_access_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *_data = talloc_steal(mem_ctx, state->pd); + + return EOK; } diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 8d6a37b2c..107f6ded1 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -49,6 +49,7 @@ #include "providers/ldap/ldap_auth.h" #include "providers/ldap/sdap_access.h" + #define LDAP_PWEXPIRE_WARNING_TIME 0 static errno_t add_expired_warning(struct pam_data *pd, long exp_time) @@ -897,49 +898,215 @@ static errno_t auth_recv(struct tevent_req *req, TALLOC_CTX *memctx, return EOK; } -/* ==Perform-Password-Change===================== */ - -struct sdap_pam_chpass_state { - struct be_req *breq; +struct sdap_pam_auth_handler_state { struct pam_data *pd; - const char *username; - char *dn; - struct sdap_handle *sh; - - struct sdap_auth_ctx *ctx; + struct be_ctx *be_ctx; }; -static void sdap_auth4chpass_done(struct tevent_req *req); -static void sdap_pam_chpass_done(struct tevent_req *req); +static void sdap_pam_auth_handler_done(struct tevent_req *subreq); -void sdap_pam_chpass_handler(struct be_req *breq) +struct tevent_req * +sdap_pam_auth_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_auth_ctx *auth_ctx, + struct pam_data *pd, + struct dp_req_params *params) { - struct be_ctx *be_ctx = be_req_get_be_ctx(breq); - struct sdap_pam_chpass_state *state; - struct sdap_auth_ctx *ctx; + struct sdap_pam_auth_handler_state *state; struct tevent_req *subreq; + struct tevent_req *req; + + req = tevent_req_create(mem_ctx, &state, + struct sdap_pam_auth_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + state->pd = pd; + state->be_ctx = params->be_ctx; + pd->pam_status = PAM_SYSTEM_ERR; + + switch (pd->cmd) { + case SSS_PAM_AUTHENTICATE: + subreq = auth_send(state, params->ev, auth_ctx, + pd->user, pd->authtok, false); + if (subreq == NULL) { + pd->pam_status = PAM_SYSTEM_ERR; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_pam_auth_handler_done, req); + break; + case SSS_PAM_CHAUTHTOK_PRELIM: + subreq = auth_send(state, params->ev, auth_ctx, + pd->user, pd->authtok, true); + if (subreq == NULL) { + pd->pam_status = PAM_SYSTEM_ERR; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_pam_auth_handler_done, req); + break; + case SSS_PAM_CHAUTHTOK: + pd->pam_status = PAM_SYSTEM_ERR; + goto immediately; + + case SSS_PAM_ACCT_MGMT: + case SSS_PAM_SETCRED: + case SSS_PAM_OPEN_SESSION: + case SSS_PAM_CLOSE_SESSION: + pd->pam_status = PAM_SUCCESS; + goto immediately; + default: + pd->pam_status = PAM_MODULE_UNKNOWN; + goto immediately; + } + + return req; + +immediately: + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; +} + +static void sdap_pam_auth_handler_done(struct tevent_req *subreq) +{ + struct sdap_pam_auth_handler_state *state; + struct tevent_req *req; + enum pwexpire pw_expire_type; + void *pw_expire_data; + const char *password; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_pam_auth_handler_state); + + ret = auth_recv(subreq, state, NULL, NULL, + &pw_expire_type, &pw_expire_data); + talloc_free(subreq); + + if (ret == EOK) { + ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, state->pd, + state->be_ctx->domain->pwd_expiration_warning); + if (ret == EINVAL) { + /* Unknown password expiration type. */ + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + } + + switch (ret) { + case EOK: + state->pd->pam_status = PAM_SUCCESS; + break; + case ERR_AUTH_DENIED: + state->pd->pam_status = PAM_PERM_DENIED; + break; + case ERR_AUTH_FAILED: + state->pd->pam_status = PAM_AUTH_ERR; + break; + case ETIMEDOUT: + case ERR_NETWORK_IO: + state->pd->pam_status = PAM_AUTHINFO_UNAVAIL; + be_mark_offline(state->be_ctx); + break; + case ERR_ACCOUNT_EXPIRED: + state->pd->pam_status = PAM_ACCT_EXPIRED; + break; + case ERR_PASSWORD_EXPIRED: + state->pd->pam_status = PAM_NEW_AUTHTOK_REQD; + break; + case ERR_ACCOUNT_LOCKED: + state->pd->account_locked = true; + state->pd->pam_status = PAM_PERM_DENIED; + break; + default: + state->pd->pam_status = PAM_SYSTEM_ERR; + break; + } + + if (ret == EOK && state->be_ctx->domain->cache_credentials) { + ret = sss_authtok_get_password(state->pd->authtok, &password, NULL); + if (ret == EOK) { + ret = sysdb_cache_password(state->be_ctx->domain, state->pd->user, + password); + } + + /* password caching failures are not fatal errors */ + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password for %s\n", + state->pd->user); + } else { + DEBUG(SSSDBG_CONF_SETTINGS, "Password successfully cached for %s\n", + state->pd->user); + } + } + +done: + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); +} + +errno_t +sdap_pam_auth_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data) +{ + struct sdap_pam_auth_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_pam_auth_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *_data = talloc_steal(mem_ctx, state->pd); + + return EOK; +} + +struct sdap_pam_chpass_handler_state { + struct be_ctx *be_ctx; + struct tevent_context *ev; + struct sdap_auth_ctx *auth_ctx; struct pam_data *pd; - int dp_err = DP_ERR_FATAL; + struct sdap_handle *sh; + char *dn; +}; - ctx = talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data, - struct sdap_auth_ctx); - pd = talloc_get_type(be_req_get_data(breq), struct pam_data); +static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq); +static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq); +static void sdap_pam_chpass_handler_last_done(struct tevent_req *subreq); - if (be_is_offline(ctx->be)) { - DEBUG(SSSDBG_CONF_SETTINGS, - "Backend is marked offline, retry later!\n"); - pd->pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; +struct tevent_req * +sdap_pam_chpass_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_auth_ctx *auth_ctx, + struct pam_data *pd, + struct dp_req_params *params) +{ + struct sdap_pam_chpass_handler_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + + req = tevent_req_create(mem_ctx, &state, + struct sdap_pam_chpass_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; } + state->pd = pd; + state->be_ctx = params->be_ctx; + state->auth_ctx = auth_ctx; + state->ev = params->ev; + if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { DEBUG(SSSDBG_CONF_SETTINGS, "Password reset by root is not supported.\n"); pd->pam_status = PAM_PERM_DENIED; - dp_err = DP_ERR_OK; - goto done; + goto immediately; } DEBUG(SSSDBG_OP_FAILURE, @@ -950,52 +1117,50 @@ void sdap_pam_chpass_handler(struct be_req *breq) if (pd->cmd != SSS_PAM_CHAUTHTOK && pd->cmd != SSS_PAM_CHAUTHTOK_PRELIM) { DEBUG(SSSDBG_OP_FAILURE, "chpass target was called by wrong pam command.\n"); - goto done; + goto immediately; } - state = talloc_zero(breq, struct sdap_pam_chpass_state); - if (!state) goto done; + subreq = auth_send(state, params->ev, auth_ctx, + pd->user, pd->authtok, true); + if (subreq == NULL) { + pd->pam_status = PAM_SYSTEM_ERR; + goto immediately; + } - state->breq = breq; - state->pd = pd; - state->username = pd->user; - state->ctx = ctx; + tevent_req_set_callback(subreq, sdap_pam_chpass_handler_auth_done, req); - subreq = auth_send(breq, be_ctx->ev, ctx, - state->username, pd->authtok, true); - if (!subreq) goto done; + return req; - tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); - return; +immediately: + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); -done: - be_req_terminate(breq, dp_err, pd->pam_status, NULL); + return req; } -static void sdap_lastchange_done(struct tevent_req *req); -static void sdap_auth4chpass_done(struct tevent_req *req) +static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq) { - struct sdap_pam_chpass_state *state = - tevent_req_callback_data(req, struct sdap_pam_chpass_state); - struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq); - struct tevent_req *subreq; + struct sdap_pam_chpass_handler_state *state; + struct tevent_req *req; enum pwexpire pw_expire_type; void *pw_expire_data; - int dp_err = DP_ERR_FATAL; - int ret; size_t msg_len; uint8_t *msg; + errno_t ret; - ret = auth_recv(req, state, &state->sh, &state->dn, + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_pam_chpass_handler_state); + + ret = auth_recv(subreq, state, &state->sh, &state->dn, &pw_expire_type, &pw_expire_data); - talloc_zfree(req); + talloc_free(subreq); + if ((ret == EOK || ret == ERR_PASSWORD_EXPIRED) && state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - DEBUG(SSSDBG_TRACE_ALL, - "Initial authentication for change password operation " - "successful.\n"); + DEBUG(SSSDBG_TRACE_ALL, "Initial authentication for change " + "password operation successful.\n"); state->pd->pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; goto done; } @@ -1006,12 +1171,11 @@ static void sdap_auth4chpass_done(struct tevent_req *req) break; case PWEXPIRE_KERBEROS: ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), NULL, - be_ctx->domain->pwd_expiration_warning); + state->be_ctx->domain->pwd_expiration_warning); if (ret == ERR_PASSWORD_EXPIRED) { - DEBUG(SSSDBG_CRIT_FAILURE, - "LDAP provider cannot change kerberos " - "passwords.\n"); + DEBUG(SSSDBG_CRIT_FAILURE, "LDAP provider cannot change " + "kerberos passwords.\n"); state->pd->pam_status = PAM_SYSTEM_ERR; goto done; } @@ -1027,100 +1191,104 @@ static void sdap_auth4chpass_done(struct tevent_req *req) } switch (ret) { - case EOK: - case ERR_PASSWORD_EXPIRED: - DEBUG(SSSDBG_TRACE_LIBS, - "user [%s] successfully authenticated.\n", state->dn); - if (pw_expire_type == PWEXPIRE_SHADOW) { -/* TODO: implement async ldap modify request */ - DEBUG(SSSDBG_CRIT_FAILURE, - "Changing shadow password attributes not implemented.\n"); - state->pd->pam_status = PAM_MODULE_UNKNOWN; - goto done; - } else { - const char *password; - const char *new_password; - int timeout; - - ret = sss_authtok_get_password(state->pd->authtok, - &password, NULL); - if (ret) { - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - ret = sss_authtok_get_password(state->pd->newauthtok, - &new_password, NULL); - if (ret) { - state->pd->pam_status = PAM_SYSTEM_ERR; + case EOK: + case ERR_PASSWORD_EXPIRED: + DEBUG(SSSDBG_TRACE_LIBS, + "user [%s] successfully authenticated.\n", state->dn); + if (pw_expire_type == PWEXPIRE_SHADOW) { + /* TODO: implement async ldap modify request */ + DEBUG(SSSDBG_CRIT_FAILURE, + "Changing shadow password attributes not implemented.\n"); + state->pd->pam_status = PAM_MODULE_UNKNOWN; goto done; - } + } else { + const char *password; + const char *new_password; + int timeout; + + ret = sss_authtok_get_password(state->pd->authtok, + &password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + ret = sss_authtok_get_password(state->pd->newauthtok, + &new_password, NULL); + if (ret) { + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } - timeout = dp_opt_get_int(state->ctx->opts->basic, SDAP_OPT_TIMEOUT); + timeout = dp_opt_get_int(state->auth_ctx->opts->basic, + SDAP_OPT_TIMEOUT); + + subreq = sdap_exop_modify_passwd_send(state, state->ev, + state->sh, state->dn, + password, new_password, + timeout); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to change password for " + "%s\n", state->pd->user); + state->pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } - subreq = sdap_exop_modify_passwd_send(state, be_ctx->ev, - state->sh, state->dn, - password, new_password, - timeout); - if (!subreq) { - DEBUG(SSSDBG_OP_FAILURE, - "Failed to change password for %s\n", state->username); - goto done; + tevent_req_set_callback(subreq, + sdap_pam_chpass_handler_chpass_done, + req); + return; } - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); - return; - } - break; - case ERR_AUTH_DENIED: - case ERR_AUTH_FAILED: - state->pd->pam_status = PAM_AUTH_ERR; - ret = pack_user_info_chpass_error(state->pd, "Old password not accepted.", - &msg_len, &msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_user_info_chpass_error failed.\n"); - } else { - ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len, - msg); + break; + case ERR_AUTH_DENIED: + case ERR_AUTH_FAILED: + state->pd->pam_status = PAM_AUTH_ERR; + ret = pack_user_info_chpass_error(state->pd, "Old password not " + "accepted.", &msg_len, &msg); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + DEBUG(SSSDBG_CRIT_FAILURE, + "pack_user_info_chpass_error failed.\n"); + } else { + ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, + msg_len, msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } } + break; + case ETIMEDOUT: + case ERR_NETWORK_IO: + state->pd->pam_status = PAM_AUTHINFO_UNAVAIL; + be_mark_offline(state->be_ctx); + break; + default: + state->pd->pam_status = PAM_SYSTEM_ERR; + break; } - break; - case ETIMEDOUT: - case ERR_NETWORK_IO: - state->pd->pam_status = PAM_AUTHINFO_UNAVAIL; - be_mark_offline(be_ctx); - dp_err = DP_ERR_OFFLINE; - break; - default: - state->pd->pam_status = PAM_SYSTEM_ERR; - } - done: - be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL); + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); } -static void sdap_pam_chpass_done(struct tevent_req *req) +static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq) { - struct sdap_pam_chpass_state *state = - tevent_req_callback_data(req, struct sdap_pam_chpass_state); - struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq); - int dp_err = DP_ERR_FATAL; - int ret; + struct sdap_pam_chpass_handler_state *state; + struct tevent_req *req; char *user_error_message = NULL; char *lastchanged_name; - struct tevent_req *subreq; size_t msg_len; uint8_t *msg; + errno_t ret; - ret = sdap_exop_modify_passwd_recv(req, state, &user_error_message); - talloc_zfree(req); + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_pam_chpass_handler_state); + + ret = sdap_exop_modify_passwd_recv(subreq, state, &user_error_message); + talloc_free(subreq); switch (ret) { case EOK: state->pd->pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; break; case ERR_CHPASS_DENIED: state->pd->pam_status = PAM_NEW_AUTHTOK_REQD; @@ -1135,12 +1303,11 @@ static void sdap_pam_chpass_done(struct tevent_req *req) if (state->pd->pam_status != PAM_SUCCESS && user_error_message != NULL) { ret = pack_user_info_chpass_error(state->pd, user_error_message, - &msg_len, &msg); + &msg_len, &msg); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "pack_user_info_chpass_error failed.\n"); } else { - ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len, - msg); + ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len, msg); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); } @@ -1148,11 +1315,11 @@ static void sdap_pam_chpass_done(struct tevent_req *req) } if (state->pd->pam_status == PAM_SUCCESS && - dp_opt_get_bool(state->ctx->opts->basic, + dp_opt_get_bool(state->auth_ctx->opts->basic, SDAP_CHPASS_UPDATE_LAST_CHANGE)) { - lastchanged_name = state->ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name; + lastchanged_name = state->auth_ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name; - subreq = sdap_modify_shadow_lastchange_send(state, be_ctx->ev, + subreq = sdap_modify_shadow_lastchange_send(state, state->ev, state->sh, state->dn, lastchanged_name); if (subreq == NULL) { @@ -1160,181 +1327,51 @@ static void sdap_pam_chpass_done(struct tevent_req *req) goto done; } - tevent_req_set_callback(subreq, sdap_lastchange_done, state); + tevent_req_set_callback(subreq, sdap_pam_chpass_handler_last_done, req); return; } done: - be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL); + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); } -static void sdap_lastchange_done(struct tevent_req *req) +static void sdap_pam_chpass_handler_last_done(struct tevent_req *subreq) { - struct sdap_pam_chpass_state *state = - tevent_req_callback_data(req, struct sdap_pam_chpass_state); - int dp_err = DP_ERR_FATAL; + struct sdap_pam_chpass_handler_state *state; + struct tevent_req *req; errno_t ret; - ret = sdap_modify_shadow_lastchange_recv(req); + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_pam_chpass_handler_state); + + ret = sdap_modify_shadow_lastchange_recv(subreq); + talloc_free(subreq); + if (ret != EOK) { state->pd->pam_status = PAM_SYSTEM_ERR; goto done; } - dp_err = DP_ERR_OK; state->pd->pam_status = PAM_SUCCESS; done: - be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL); -} - -/* ==Perform-User-Authentication-and-Password-Caching===================== */ - -struct sdap_pam_auth_state { - struct be_req *breq; - struct pam_data *pd; -}; - -static void sdap_pam_auth_done(struct tevent_req *req); - -void sdap_pam_auth_handler(struct be_req *breq) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(breq); - struct sdap_pam_auth_state *state; - struct sdap_auth_ctx *ctx; - struct tevent_req *subreq; - struct pam_data *pd; - int dp_err = DP_ERR_FATAL; - - ctx = talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct sdap_auth_ctx); - pd = talloc_get_type(be_req_get_data(breq), struct pam_data); - - if (be_is_offline(ctx->be)) { - DEBUG(SSSDBG_CONF_SETTINGS, - "Backend is marked offline, retry later!\n"); - pd->pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; - } - - pd->pam_status = PAM_SYSTEM_ERR; - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK_PRELIM: - - state = talloc_zero(breq, struct sdap_pam_auth_state); - if (!state) goto done; - - state->breq = breq; - state->pd = pd; - - subreq = auth_send(breq, be_ctx->ev, ctx, - pd->user, pd->authtok, - pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false); - if (!subreq) goto done; - - tevent_req_set_callback(subreq, sdap_pam_auth_done, state); - return; - - case SSS_PAM_CHAUTHTOK: - break; - - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_SETCRED: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - pd->pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - break; - default: - pd->pam_status = PAM_MODULE_UNKNOWN; - dp_err = DP_ERR_OK; - } - -done: - be_req_terminate(breq, dp_err, pd->pam_status, NULL); + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); } -static void sdap_pam_auth_done(struct tevent_req *req) +errno_t +sdap_pam_chpass_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data) { - struct sdap_pam_auth_state *state = - tevent_req_callback_data(req, struct sdap_pam_auth_state); - struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq); - enum pwexpire pw_expire_type; - void *pw_expire_data; - const char *password; - int dp_err = DP_ERR_OK; - int ret; + struct sdap_pam_chpass_handler_state *state = NULL; - ret = auth_recv(req, state, NULL, NULL, - &pw_expire_type, &pw_expire_data); - talloc_zfree(req); + state = tevent_req_data(req, struct sdap_pam_chpass_handler_state); - if (ret == EOK) { - ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, state->pd, - be_ctx->domain->pwd_expiration_warning); - if (ret == EINVAL) { - /* Unknown password expiration type. */ - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - } - - switch (ret) { - case EOK: - state->pd->pam_status = PAM_SUCCESS; - break; - case ERR_AUTH_DENIED: - state->pd->pam_status = PAM_PERM_DENIED; - break; - case ERR_AUTH_FAILED: - state->pd->pam_status = PAM_AUTH_ERR; - break; - case ETIMEDOUT: - case ERR_NETWORK_IO: - state->pd->pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case ERR_ACCOUNT_EXPIRED: - state->pd->pam_status = PAM_ACCT_EXPIRED; - break; - case ERR_PASSWORD_EXPIRED: - state->pd->pam_status = PAM_NEW_AUTHTOK_REQD; - break; - case ERR_ACCOUNT_LOCKED: - state->pd->account_locked = true; - state->pd->pam_status = PAM_PERM_DENIED; - break; - default: - state->pd->pam_status = PAM_SYSTEM_ERR; - dp_err = DP_ERR_FATAL; - } - - if (ret == ETIMEDOUT || ret == ERR_NETWORK_IO) { - be_mark_offline(be_ctx); - dp_err = DP_ERR_OFFLINE; - goto done; - } - - if (ret == EOK && be_ctx->domain->cache_credentials) { + TEVENT_REQ_RETURN_ON_ERROR(req); - ret = sss_authtok_get_password(state->pd->authtok, &password, NULL); - if (ret == EOK) { - ret = sysdb_cache_password(be_ctx->domain, state->pd->user, - password); - } + *_data = talloc_steal(mem_ctx, state->pd); - /* password caching failures are not fatal errors */ - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password for %s\n", - state->pd->user); - } else { - DEBUG(SSSDBG_CONF_SETTINGS, "Password successfully cached for %s\n", - state->pd->user); - } - } - -done: - be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL); + return EOK; } diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index 27b62a635..c9f78ff8d 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -38,12 +38,6 @@ /* a fd the child process would log into */ int ldap_child_debug_fd = -1; -void sdap_handler_done(struct be_req *req, int dp_err, - int error, const char *errstr) -{ - return be_req_terminate(req, dp_err, error, errstr); -} - int ldap_id_setup_tasks(struct sdap_id_ctx *ctx) { return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom, diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index d50473c88..b39f67892 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -78,12 +78,15 @@ struct sdap_auth_ctx { struct sdap_service *chpass_service; }; -int sssm_ldap_id_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data); +struct tevent_req * +sdap_online_check_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + void *data, + struct dp_req_params *params); -void sdap_check_online(struct be_req *breq); -void sdap_do_online_check(struct be_req *be_req, struct sdap_id_ctx *ctx); +errno_t sdap_online_check_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data); struct tevent_req* sdap_reinit_cleanup_send(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, @@ -92,9 +95,15 @@ struct tevent_req* sdap_reinit_cleanup_send(TALLOC_CTX *mem_ctx, errno_t sdap_reinit_cleanup_recv(struct tevent_req *req); /* id */ -void sdap_account_info_handler(struct be_req *breq); -void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx, - struct sdap_id_conn_ctx *conn); +struct tevent_req * +sdap_account_info_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct be_acct_req *data, + struct dp_req_params *params); + +errno_t sdap_account_info_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data); /* Set up enumeration and/or cleanup */ int ldap_id_setup_tasks(struct sdap_id_ctx *ctx); @@ -121,20 +130,39 @@ sdap_handle_acct_req_recv(struct tevent_req *req, int *_dp_error, const char **_err, int *sdap_ret); -/* auth */ -void sdap_pam_auth_handler(struct be_req *breq); +struct tevent_req * +sdap_pam_auth_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_auth_ctx *auth_ctx, + struct pam_data *pd, + struct dp_req_params *params); + +errno_t +sdap_pam_auth_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); -/* chpass */ -void sdap_pam_chpass_handler(struct be_req *breq); +struct tevent_req * +sdap_pam_chpass_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_auth_ctx *auth_ctx, + struct pam_data *pd, + struct dp_req_params *params); -/* access */ -void sdap_pam_access_handler(struct be_req *breq); +errno_t +sdap_pam_chpass_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); /* autofs */ -void sdap_autofs_handler(struct be_req *breq); +struct tevent_req * +sdap_autofs_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_autofs_data *data, + struct dp_req_params *params); -void sdap_handler_done(struct be_req *req, int dp_err, - int error, const char *errstr); +errno_t +sdap_autofs_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data); int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, const char *service_name, const char *dns_service_name, diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c index ee5b374db..49ce9db48 100644 --- a/src/providers/ldap/ldap_id.c +++ b/src/providers/ldap/ldap_id.c @@ -1286,152 +1286,11 @@ int groups_by_user_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret return EOK; } -static void sdap_check_online_done(struct tevent_req *req); -void sdap_check_online(struct be_req *be_req) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); - struct sdap_id_ctx *ctx; - - ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - - return sdap_do_online_check(be_req, ctx); -} - -struct sdap_online_check_ctx { - struct be_req *be_req; - struct sdap_id_ctx *id_ctx; -}; - -void sdap_do_online_check(struct be_req *be_req, struct sdap_id_ctx *ctx) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); - struct tevent_req *req; - struct sdap_online_check_ctx *check_ctx; - errno_t ret; - - check_ctx = talloc_zero(be_req, struct sdap_online_check_ctx); - if (!check_ctx) { - ret = ENOMEM; - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed\n"); - goto fail; - } - check_ctx->id_ctx = ctx; - check_ctx->be_req = be_req; - - req = sdap_cli_connect_send(be_req, be_ctx->ev, ctx->opts, - be_ctx, ctx->conn->service, false, - CON_TLS_DFL, false); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "sdap_cli_connect_send failed.\n"); - ret = EIO; - goto fail; - } - tevent_req_set_callback(req, sdap_check_online_done, check_ctx); - - return; -fail: - sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL); -} - -static void sdap_check_online_reinit_done(struct tevent_req *req); - -static void sdap_check_online_done(struct tevent_req *req) -{ - struct sdap_online_check_ctx *check_ctx = tevent_req_callback_data(req, - struct sdap_online_check_ctx); - int ret; - int dp_err = DP_ERR_FATAL; - bool can_retry; - struct sdap_server_opts *srv_opts; - struct be_req *be_req; - struct sdap_id_ctx *id_ctx; - struct tevent_req *reinit_req = NULL; - bool reinit = false; - struct be_ctx *be_ctx; - - ret = sdap_cli_connect_recv(req, NULL, &can_retry, NULL, &srv_opts); - talloc_zfree(req); - - if (ret != EOK) { - if (!can_retry) { - dp_err = DP_ERR_OFFLINE; - } - } else { - dp_err = DP_ERR_OK; - - if (!check_ctx->id_ctx->srv_opts) { - srv_opts->max_user_value = 0; - srv_opts->max_group_value = 0; - srv_opts->max_service_value = 0; - srv_opts->max_sudo_value = 0; - } else if (strcmp(srv_opts->server_id, check_ctx->id_ctx->srv_opts->server_id) == 0 - && srv_opts->supports_usn - && check_ctx->id_ctx->srv_opts->last_usn > srv_opts->last_usn) { - check_ctx->id_ctx->srv_opts->max_user_value = 0; - check_ctx->id_ctx->srv_opts->max_group_value = 0; - check_ctx->id_ctx->srv_opts->max_service_value = 0; - check_ctx->id_ctx->srv_opts->max_sudo_value = 0; - check_ctx->id_ctx->srv_opts->last_usn = srv_opts->last_usn; - - reinit = true; - } - - sdap_steal_server_opts(check_ctx->id_ctx, &srv_opts); - } - - be_req = check_ctx->be_req; - be_ctx = be_req_get_be_ctx(be_req); - id_ctx = check_ctx->id_ctx; - talloc_free(check_ctx); - - if (reinit) { - DEBUG(SSSDBG_TRACE_FUNC, "Server reinitialization detected. " - "Cleaning cache.\n"); - reinit_req = sdap_reinit_cleanup_send(be_req, be_ctx, id_ctx); - if (reinit_req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " - "clean up.\n"); - /* not fatal */ - goto done; - } - - tevent_req_set_callback(reinit_req, sdap_check_online_reinit_done, - be_req); - return; - } - -done: - sdap_handler_done(be_req, dp_err, 0, NULL); -} - -static void sdap_check_online_reinit_done(struct tevent_req *req) -{ - struct be_req *be_req = NULL; - errno_t ret; - - be_req = tevent_req_callback_data(req, struct be_req); - ret = sdap_reinit_cleanup_recv(req); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " - "clean up [%d]: %s\n", ret, strerror(ret)); - /* not fatal */ - } else { - DEBUG(SSSDBG_TRACE_FUNC, "Reinitialization clean up completed\n"); - } - - sdap_handler_done(be_req, DP_ERR_OK, 0, NULL); -} - /* =Get-Account-Info-Call================================================= */ /* FIXME: embed this function in sssd_be and only call out * specific functions from modules ? */ -void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx, - struct sdap_id_conn_ctx *conn); - static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_id_ctx *ctx, @@ -1445,20 +1304,6 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, errno_t sdap_get_user_and_group_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret); -void sdap_account_info_handler(struct be_req *breq) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(breq); - struct sdap_id_ctx *ctx; - - ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data, struct sdap_id_ctx); - if (!ctx) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not get sdap ctx\n"); - return sdap_handler_done(breq, DP_ERR_FATAL, - EINVAL, "Invalid request data\n"); - } - return sdap_handle_account_info(breq, ctx, ctx->conn); -} - bool sdap_is_enum_request(struct be_acct_req *ar) { switch (ar->entry_type & BE_REQ_TYPE_MASK) { @@ -1757,66 +1602,6 @@ sdap_handle_acct_req_recv(struct tevent_req *req, return EOK; } -static void sdap_account_info_complete(struct tevent_req *req); - -void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx, - struct sdap_id_conn_ctx *conn) -{ - struct be_acct_req *ar; - struct tevent_req *req; - - if (be_is_offline(ctx->be)) { - return sdap_handler_done(breq, DP_ERR_OFFLINE, EAGAIN, "Offline"); - } - - ar = talloc_get_type(be_req_get_data(breq), struct be_acct_req); - if (ar == NULL) { - return sdap_handler_done(breq, DP_ERR_FATAL, - EINVAL, "Invalid private data"); - } - - if (sdap_is_enum_request(ar)) { - DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n"); - return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success"); - } - - req = sdap_handle_acct_req_send(breq, ctx->be, ar, ctx, - ctx->opts->sdom, conn, true); - if (req == NULL) { - return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory"); - } - tevent_req_set_callback(req, sdap_account_info_complete, breq); -} - -static void sdap_account_info_complete(struct tevent_req *req) -{ - const char *error_text; - const char *req_error_text; - struct be_req *breq = tevent_req_callback_data(req, struct be_req); - int ret, dp_error; - - ret = sdap_handle_acct_req_recv(req, &dp_error, &req_error_text, NULL); - talloc_zfree(req); - if (dp_error == DP_ERR_OK) { - if (ret == EOK) { - error_text = NULL; - } else { - DEBUG(SSSDBG_CRIT_FAILURE, - "Bug: dp_error is OK on failed request\n"); - dp_error = DP_ERR_FATAL; - error_text = req_error_text; - } - } else if (dp_error == DP_ERR_OFFLINE) { - error_text = "Offline"; - } else if (dp_error == DP_ERR_FATAL && ret == ENOMEM) { - error_text = "Out of memory"; - } else { - error_text = req_error_text; - } - - sdap_handler_done(breq, dp_error, ret, error_text); -} - struct get_user_and_group_state { struct tevent_context *ev; struct sdap_id_ctx *id_ctx; @@ -2012,3 +1797,88 @@ errno_t sdap_get_user_and_group_recv(struct tevent_req *req, return EOK; } + +struct sdap_account_info_handler_state { + struct dp_reply_std reply; +}; + +static void sdap_account_info_handler_done(struct tevent_req *subreq); + +struct tevent_req * +sdap_account_info_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct be_acct_req *data, + struct dp_req_params *params) +{ + struct sdap_account_info_handler_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, + struct sdap_account_info_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + if (sdap_is_enum_request(data)) { + DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n"); + ret = EOK; + goto immediately; + } + + subreq = sdap_handle_acct_req_send(state, params->be_ctx, data, id_ctx, + id_ctx->opts->sdom, id_ctx->conn, true); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_account_info_handler_done, req); + + return req; + +immediately: + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; +} + +static void sdap_account_info_handler_done(struct tevent_req *subreq) +{ + struct sdap_account_info_handler_state *state; + struct tevent_req *req; + const char *error_msg; + int dp_error; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_account_info_handler_state); + + ret = sdap_handle_acct_req_recv(subreq, &dp_error, &error_msg, NULL); + talloc_zfree(subreq); + + /* TODO For backward compatibility we always return EOK to DP now. */ + dp_reply_std_set(&state->reply, dp_error, ret, error_msg); + tevent_req_done(req); +} + +errno_t sdap_account_info_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data) +{ + struct sdap_account_info_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_account_info_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *data = state->reply; + + return EOK; +} diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c index cfd68d9b9..566924cbc 100644 --- a/src/providers/ldap/ldap_init.c +++ b/src/providers/ldap/ldap_init.c @@ -32,31 +32,10 @@ #include "providers/fail_over_srv.h" #include "providers/be_refresh.h" -static void sdap_shutdown(struct be_req *req); - -/* Id Handler */ -struct bet_ops sdap_id_ops = { - .handler = sdap_account_info_handler, - .finalize = sdap_shutdown, - .check_online = sdap_check_online -}; - -/* Auth Handler */ -struct bet_ops sdap_auth_ops = { - .handler = sdap_pam_auth_handler, - .finalize = sdap_shutdown -}; - -/* Chpass Handler */ -struct bet_ops sdap_chpass_ops = { - .handler = sdap_pam_chpass_handler, - .finalize = sdap_shutdown -}; - -/* Access Handler */ -struct bet_ops sdap_access_ops = { - .handler = sdap_pam_access_handler, - .finalize = sdap_shutdown +struct ldap_init_ctx { + struct sdap_options *options; + struct sdap_id_ctx *id_ctx; + struct sdap_auth_ctx *auth_ctx; }; /* Please use this only for short lists */ @@ -85,259 +64,193 @@ errno_t check_order_list_for_duplicates(char **list, return EOK; } -static int ldap_id_init_internal(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) +static errno_t ldap_init_auth_ctx(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct sdap_options *options, + struct sdap_auth_ctx **_auth_ctx) { - struct sdap_id_ctx *ctx = NULL; - const char *urls; - const char *backup_urls; - const char *dns_service_name; - const char *sasl_mech; - struct sdap_service *sdap_service; - struct sdap_options *opts = NULL; - int ret; - - /* If we're already set up, just return that */ - if(bectx->bet_info[BET_ID].mod_name && - strcmp("ldap", bectx->bet_info[BET_ID].mod_name) == 0) { - DEBUG(SSSDBG_TRACE_INTERNAL, - "Re-using sdap_id_ctx for this provider\n"); - *ops = bectx->bet_info[BET_ID].bet_ops; - *pvt_data = bectx->bet_info[BET_ID].pvt_bet_data; - return EOK; - } + struct sdap_auth_ctx *auth_ctx; - ret = ldap_get_options(bectx, bectx->domain, bectx->cdb, - bectx->conf_path, &opts); - if (ret != EOK) { - goto done; + auth_ctx = talloc(mem_ctx, struct sdap_auth_ctx); + if (auth_ctx == NULL) { + return ENOMEM; } - dns_service_name = dp_opt_get_string(opts->basic, - SDAP_DNS_SERVICE_NAME); - DEBUG(SSSDBG_CONF_SETTINGS, - "Service name for discovery set to %s\n", dns_service_name); + auth_ctx->be = be_ctx; + auth_ctx->opts = options; + auth_ctx->service = id_ctx->conn->service; + auth_ctx->chpass_service = NULL; - urls = dp_opt_get_string(opts->basic, SDAP_URI); - backup_urls = dp_opt_get_string(opts->basic, SDAP_BACKUP_URI); + *_auth_ctx = auth_ctx; - ret = sdap_service_init(bectx, bectx, "LDAP", - dns_service_name, urls, backup_urls, - &sdap_service); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Failed to initialize failover service!\n"); - goto done; - } + return EOK; +} - ctx = sdap_id_ctx_new(bectx, bectx, sdap_service); - if (!ctx) { - ret = ENOMEM; - goto done; +static errno_t init_chpass_service(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_options *opts, + struct sdap_service **_chpass_service) +{ + errno_t ret; + const char *urls; + const char *backup_urls; + const char *dns_service_name; + struct sdap_service *chpass_service; + + dns_service_name = dp_opt_get_string(opts->basic, + SDAP_CHPASS_DNS_SERVICE_NAME); + if (dns_service_name != NULL) { + DEBUG(SSSDBG_TRACE_LIBS, + "Service name for chpass discovery set to %s\n", + dns_service_name); } - ctx->opts = talloc_steal(ctx, opts); - sasl_mech = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_MECH); - if (sasl_mech && strcasecmp(sasl_mech, "GSSAPI") == 0) { - if (dp_opt_get_bool(ctx->opts->basic, SDAP_KRB5_KINIT)) { - ret = sdap_gssapi_init(ctx, ctx->opts->basic, - ctx->be, ctx->conn->service, - &ctx->krb5_service); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "sdap_gssapi_init failed [%d][%s].\n", - ret, strerror(ret)); - goto done; - } + urls = dp_opt_get_string(opts->basic, SDAP_CHPASS_URI); + backup_urls = dp_opt_get_string(opts->basic, SDAP_CHPASS_BACKUP_URI); + + if (urls != NULL || backup_urls != NULL || dns_service_name != NULL) { + ret = sdap_service_init(mem_ctx, + be_ctx, + "LDAP_CHPASS", + dns_service_name, + urls, + backup_urls, + &chpass_service); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to initialize failover service!\n"); + return ret; } + } else { + DEBUG(SSSDBG_TRACE_ALL, + "ldap_chpass_uri and ldap_chpass_dns_service_name not set, " + "using ldap_uri.\n"); + chpass_service = NULL; } - ret = setup_tls_config(ctx->opts->basic); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d][%s].\n", - ret, strerror(ret)); - goto done; - } + *_chpass_service = chpass_service; + return EOK; +} - /* Set up the ID mapping object */ - ret = sdap_idmap_init(ctx, ctx, &ctx->opts->idmap_ctx); - if (ret != EOK) goto done; +static errno_t get_access_order_list(TALLOC_CTX *mem_ctx, + const char *order, + char ***_order_list) +{ + errno_t ret; + char **order_list; + int order_list_len; - ret = sdap_setup_child(); + ret = split_on_separator(mem_ctx, order, ',', true, true, + &order_list, &order_list_len); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "setup_child failed [%d][%s].\n", - ret, strerror(ret)); + DEBUG(SSSDBG_CRIT_FAILURE, "split_on_separator failed.\n"); goto done; } - /* setup SRV lookup plugin */ - ret = be_fo_set_dns_srv_lookup_plugin(bectx, NULL); + ret = check_order_list_for_duplicates(order_list, false); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin " - "[%d]: %s\n", ret, strerror(ret)); + DEBUG(SSSDBG_CRIT_FAILURE, + "check_order_list_for_duplicates failed.\n"); goto done; } - /* setup periodical refresh of expired records */ - ret = sdap_refresh_init(bectx->refresh_ctx, ctx); - if (ret != EOK && ret != EEXIST) { - DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh " - "will not work [%d]: %s\n", ret, strerror(ret)); + if (order_list_len > LDAP_ACCESS_LAST) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Currently only [%d] different access rules are supported.\n", + LDAP_ACCESS_LAST); + ret = EINVAL; + goto done; } - *ops = &sdap_id_ops; - *pvt_data = ctx; - ret = EOK; + *_order_list = order_list; done: if (ret != EOK) { - talloc_free(opts); - talloc_free(ctx); + talloc_free(order_list); } + return ret; } -int sssm_ldap_id_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) +static errno_t check_expire_policy(struct sdap_options *opts) { - int ret; - struct sdap_id_ctx *ctx = NULL; - - ret = ldap_id_init_internal(bectx, ops, (void **) &ctx); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "ldap_id_init_internal failed [%d][%s].\n", - ret, strerror(ret)); - goto done; - } - - ret = ldap_id_setup_tasks(ctx); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "sdap_id_setup_tasks failed [%d][%s].\n", - ret, strerror(ret)); - goto done; + const char *expire_policy; + bool matched_policy = false; + const char *policies[] = {LDAP_ACCOUNT_EXPIRE_SHADOW, + LDAP_ACCOUNT_EXPIRE_AD, + LDAP_ACCOUNT_EXPIRE_NDS, + LDAP_ACCOUNT_EXPIRE_RHDS, + LDAP_ACCOUNT_EXPIRE_IPA, + LDAP_ACCOUNT_EXPIRE_389DS, + NULL}; + + expire_policy = dp_opt_get_cstring(opts->basic, + SDAP_ACCOUNT_EXPIRE_POLICY); + if (expire_policy == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Warning: LDAP access rule 'expire' is set, " + "but no ldap_account_expire_policy configured. " + "All domain users will be denied access.\n"); + return EOK; } - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); + for (unsigned i = 0; policies[i] != NULL; i++) { + if (strcasecmp(expire_policy, policies[i]) == 0) { + matched_policy = true; + break; + } } - return ret; -} - -int sssm_ldap_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - void *data; - struct sdap_id_ctx *id_ctx; - struct sdap_auth_ctx *ctx; - int ret; - ret = ldap_id_init_internal(bectx, ops, &data); - if (ret == EOK) { - id_ctx = talloc_get_type(data, struct sdap_id_ctx); - - ctx = talloc(bectx, struct sdap_auth_ctx); - if (!ctx) return ENOMEM; - - ctx->be = bectx; - ctx->opts = id_ctx->opts; - ctx->service = id_ctx->conn->service; - ctx->chpass_service = NULL; - - *ops = &sdap_auth_ops; - *pvt_data = ctx; + if (matched_policy == false) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Unsupported LDAP account expire policy [%s].\n", + expire_policy); + return EINVAL; } - return ret; + return EOK; } -int sssm_ldap_chpass_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) +static errno_t get_access_filter(TALLOC_CTX *mem_ctx, + struct sdap_options *opts, + const char **_filter) { - int ret; - void *data; - struct sdap_auth_ctx *ctx = NULL; - const char *urls; - const char *backup_urls; - const char *dns_service_name; - - ret = sssm_ldap_auth_init(bectx, ops, &data); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ldap_auth_init failed.\n"); - goto done; - } - - ctx = talloc_get_type(data, struct sdap_auth_ctx); + const char *filter; - dns_service_name = dp_opt_get_string(ctx->opts->basic, - SDAP_CHPASS_DNS_SERVICE_NAME); - if (dns_service_name) { - DEBUG(SSSDBG_TRACE_LIBS, - "Service name for chpass discovery set to %s\n", - dns_service_name); + filter = dp_opt_get_cstring(opts->basic, SDAP_ACCESS_FILTER); + if (filter == NULL) { + /* It's okay if this is NULL. In that case we will simply act + * like the 'deny' provider. + */ + DEBUG(SSSDBG_FATAL_FAILURE, + "Warning: LDAP access rule 'filter' is set, " + "but no ldap_access_filter configured. " + "All domain users will be denied access.\n"); + return EOK; } - urls = dp_opt_get_string(ctx->opts->basic, SDAP_CHPASS_URI); - backup_urls = dp_opt_get_string(ctx->opts->basic, SDAP_CHPASS_BACKUP_URI); - if (!urls && !backup_urls && !dns_service_name) { - DEBUG(SSSDBG_TRACE_ALL, - "ldap_chpass_uri and ldap_chpass_dns_service_name not set, " - "using ldap_uri.\n"); - ctx->chpass_service = NULL; - } else { - ret = sdap_service_init(ctx, ctx->be, "LDAP_CHPASS", dns_service_name, - urls, backup_urls, &ctx->chpass_service); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to initialize failover service!\n"); - goto done; - } + filter = sdap_get_access_filter(mem_ctx, filter); + if (filter == NULL) { + return ENOMEM; } + *_filter = filter; - *ops = &sdap_chpass_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - return ret; + return EOK; } -int sssm_ldap_access_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) +static errno_t set_access_rules(TALLOC_CTX *mem_ctx, + struct sdap_access_ctx *access_ctx, + struct sdap_options *opts) { - int ret; - struct sdap_access_ctx *access_ctx; - const char *filter; + errno_t ret; + char **order_list = NULL; const char *order; - char **order_list; - int order_list_len; size_t c; - const char *dummy; - - access_ctx = talloc_zero(bectx, struct sdap_access_ctx); - if(access_ctx == NULL) { - ret = ENOMEM; - goto done; - } - ret = ldap_id_init_internal(bectx, ops, (void **)&access_ctx->id_ctx); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "ldap_id_init_internal failed.\n"); - goto done; - } + /* To make sure that in case of failure it's safe to be freed */ + access_ctx->filter = NULL; order = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic, SDAP_ACCESS_ORDER); @@ -347,73 +260,28 @@ int sssm_ldap_access_init(struct be_ctx *bectx, order = "filter"; } - ret = split_on_separator(access_ctx, order, ',', true, true, - &order_list, &order_list_len); + ret = get_access_order_list(mem_ctx, order, &order_list); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "split_on_separator failed.\n"); - goto done; - } - - ret = check_order_list_for_duplicates(order_list, false); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "check_order_list_for_duplicates failed.\n"); - goto done; - } - - if (order_list_len > LDAP_ACCESS_LAST) { DEBUG(SSSDBG_CRIT_FAILURE, - "Currently only [%d] different access rules are supported.\n", - LDAP_ACCESS_LAST); - ret = EINVAL; + "get_access_order_list failed: [%d][%s].\n", + ret, sss_strerror(ret)); goto done; } for (c = 0; order_list[c] != NULL; c++) { + if (strcasecmp(order_list[c], LDAP_ACCESS_FILTER_NAME) == 0) { access_ctx->access_rule[c] = LDAP_ACCESS_FILTER; - - filter = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic, - SDAP_ACCESS_FILTER); - if (filter == NULL) { - /* It's okay if this is NULL. In that case we will simply act - * like the 'deny' provider. - */ - DEBUG(SSSDBG_FATAL_FAILURE, - "Warning: LDAP access rule 'filter' is set, " - "but no ldap_access_filter configured. " - "All domain users will be denied access.\n"); - } else { - access_ctx->filter = sdap_get_access_filter(access_ctx, - filter); - if (access_ctx->filter == NULL) { - ret = ENOMEM; - goto done; - } + if (get_access_filter(mem_ctx, opts, &access_ctx->filter) != EOK) { + goto done; } + } else if (strcasecmp(order_list[c], LDAP_ACCESS_EXPIRE_NAME) == 0) { access_ctx->access_rule[c] = LDAP_ACCESS_EXPIRE; - - dummy = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic, - SDAP_ACCOUNT_EXPIRE_POLICY); - if (dummy == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Warning: LDAP access rule 'expire' is set, " - "but no ldap_account_expire_policy configured. " - "All domain users will be denied access.\n"); - } else { - if (strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_SHADOW) != 0 && - strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_AD) != 0 && - strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_NDS) != 0 && - strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_RHDS) != 0 && - strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_IPA) != 0 && - strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_389DS) != 0) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Unsupported LDAP account expire policy [%s].\n", - dummy); - ret = EINVAL; - goto done; - } + if (check_expire_policy(opts) != EOK) { + goto done; } + } else if (strcasecmp(order_list[c], LDAP_ACCESS_SERVICE_NAME) == 0) { access_ctx->access_rule[c] = LDAP_ACCESS_SERVICE; } else if (strcasecmp(order_list[c], LDAP_ACCESS_HOST_NAME) == 0) { @@ -441,75 +309,327 @@ int sssm_ldap_access_init(struct be_ctx *bectx, access_ctx->access_rule[c] = LDAP_ACCESS_EMPTY; if (c == 0) { DEBUG(SSSDBG_FATAL_FAILURE, "Warning: access_provider=ldap set, " - "but ldap_access_order is empty. " - "All domain users will be denied access.\n"); + "but ldap_access_order is empty. " + "All domain users will be denied access.\n"); + } + +done: + talloc_free(order_list); + if (ret != EOK) { + talloc_zfree(access_ctx->filter); + } + return ret; +} + +static errno_t get_sdap_service(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_options *opts, + struct sdap_service **_sdap_service) +{ + errno_t ret; + const char *urls; + const char *backup_urls; + const char *dns_service_name; + struct sdap_service *sdap_service; + + urls = dp_opt_get_string(opts->basic, SDAP_URI); + backup_urls = dp_opt_get_string(opts->basic, SDAP_BACKUP_URI); + dns_service_name = dp_opt_get_string(opts->basic, SDAP_DNS_SERVICE_NAME); + if (dns_service_name != NULL) { + DEBUG(SSSDBG_CONF_SETTINGS, + "Service name for discovery set to %s\n", dns_service_name); + } + + ret = sdap_service_init(mem_ctx, be_ctx, "LDAP", + dns_service_name, + urls, + backup_urls, + &sdap_service); + if (ret != EOK) { + return ret; + } + + *_sdap_service = sdap_service; + return EOK; +} + +static bool should_call_gssapi_init(struct sdap_options *opts) +{ + const char *sasl_mech; + + sasl_mech = dp_opt_get_string(opts->basic, SDAP_SASL_MECH); + if (sasl_mech == NULL) { + return false; + } + + if (strcasecmp(sasl_mech, "GSSAPI") != 0) { + return false; + } + + if (dp_opt_get_bool(opts->basic, SDAP_KRB5_KINIT) == false) { + return false; + } + + return true; +} + +static errno_t ldap_init_misc(struct be_ctx *be_ctx, + struct sdap_options *options, + struct sdap_id_ctx *id_ctx) +{ + errno_t ret; + + if (should_call_gssapi_init(options)) { + ret = sdap_gssapi_init(id_ctx, options->basic, be_ctx, + id_ctx->conn->service, &id_ctx->krb5_service); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "sdap_gssapi_init failed [%d][%s].\n", + ret, sss_strerror(ret)); + return ret; + } + } + + ret = setup_tls_config(options->basic); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get TLS options [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + + /* Setup the ID mapping object */ + ret = sdap_idmap_init(id_ctx, id_ctx, &options->idmap_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Could not initialize ID mapping. In case ID mapping properties " + "changed on the server, please remove the SSSD database\n"); + return ret; + } + + ret = ldap_id_setup_tasks(id_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup background tasks " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + + ret = sdap_setup_child(); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup sdap child [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + + /* Setup SRV lookup plugin */ + ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + + /* Setup periodical refresh of expired records */ + ret = sdap_refresh_init(be_ctx->refresh_ctx, id_ctx); + if (ret != EOK && ret != EEXIST) { + DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh will not work " + "[%d]: %s\n", ret, sss_strerror(ret)); + } + + return EOK; +} + +errno_t sssm_ldap_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct data_provider *provider, + const char *module_name, + void **_module_data) +{ + struct sdap_service *sdap_service; + struct ldap_init_ctx *init_ctx; + errno_t ret; + + init_ctx = talloc_zero(mem_ctx, struct ldap_init_ctx); + if (init_ctx == NULL) { + return ENOMEM; + } + + /* Always initialize options since it is needed everywhere. */ + ret = ldap_get_options(init_ctx, be_ctx->domain, be_ctx->cdb, + be_ctx->conf_path, &init_ctx->options); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize LDAP options " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + /* Always initialize id_ctx since it is needed everywhere. */ + ret = get_sdap_service(init_ctx, be_ctx, init_ctx->options, &sdap_service); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to initialize failover service " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + init_ctx->id_ctx = sdap_id_ctx_new(init_ctx, be_ctx, sdap_service); + if (init_ctx->id_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize LDAP ID context\n"); + ret = ENOMEM; + goto done; } - *ops = &sdap_access_ops; - *pvt_data = access_ctx; + init_ctx->id_ctx->opts = init_ctx->options; + + /* Setup miscellaneous things. */ + ret = ldap_init_misc(be_ctx, init_ctx->options, init_ctx->id_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init LDAP module " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + /* Initialize auth_ctx only if one of the target is enabled. */ + if (dp_target_enabled(provider, module_name, DPT_AUTH, DPT_CHPASS)) { + ret = ldap_init_auth_ctx(init_ctx, be_ctx, init_ctx->id_ctx, + init_ctx->options, &init_ctx->auth_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + } + + *_module_data = init_ctx; ret = EOK; done: if (ret != EOK) { - talloc_free(access_ctx); + talloc_free(init_ctx); } + return ret; } -int sssm_ldap_sudo_init(struct be_ctx *be_ctx, - struct bet_ops **ops, - void **pvt_data) +errno_t sssm_ldap_id_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) { -#ifdef BUILD_SUDO + struct ldap_init_ctx *init_ctx; struct sdap_id_ctx *id_ctx; - void *data; - int ret; - ret = ldap_id_init_internal(be_ctx, ops, &data); + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + id_ctx = init_ctx->id_ctx; + + dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER, + sdap_account_info_handler_send, sdap_account_info_handler_recv, id_ctx, + struct sdap_id_ctx, struct be_acct_req, struct dp_reply_std); + + dp_set_method(dp_methods, DPM_CHECK_ONLINE, + sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx, + struct sdap_id_ctx, void, struct dp_reply_std); + + return EOK; +} + +errno_t sssm_ldap_auth_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct ldap_init_ctx *init_ctx; + struct sdap_auth_ctx *auth_ctx; + + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + auth_ctx = init_ctx->auth_ctx; + + dp_set_method(dp_methods, DPM_AUTH_HANDLER, + sdap_pam_auth_handler_send, sdap_pam_auth_handler_recv, auth_ctx, + struct sdap_auth_ctx, struct pam_data, struct pam_data *); + + return EOK; +} + +errno_t sssm_ldap_chpass_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ + struct ldap_init_ctx *init_ctx; + struct sdap_auth_ctx *auth_ctx; + errno_t ret; + + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + auth_ctx = init_ctx->auth_ctx; + + ret = init_chpass_service(auth_ctx, be_ctx, init_ctx->options, + &auth_ctx->chpass_service); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init LDAP ID provider [%d]: %s\n", - ret, strerror(ret)); + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize chpass service " + "[%d]: %s\n", ret, sss_strerror(ret)); return ret; } - id_ctx = talloc_get_type(data, struct sdap_id_ctx); - if (!id_ctx) { - DEBUG(SSSDBG_CRIT_FAILURE, "No ID provider?\n"); - return EIO; - } + dp_set_method(dp_methods, DPM_AUTH_HANDLER, + sdap_pam_chpass_handler_send, sdap_pam_chpass_handler_recv, auth_ctx, + struct sdap_auth_ctx, struct pam_data, struct pam_data *); - return sdap_sudo_init(be_ctx, id_ctx, ops, pvt_data); -#else - DEBUG(SSSDBG_MINOR_FAILURE, "Sudo init handler called but SSSD is " - "built without sudo support, ignoring\n"); return EOK; -#endif } -int sssm_ldap_autofs_init(struct be_ctx *be_ctx, - struct bet_ops **ops, - void **pvt_data) +errno_t sssm_ldap_access_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) { -#ifdef BUILD_AUTOFS - struct sdap_id_ctx *id_ctx; - void *data; - int ret; + struct ldap_init_ctx *init_ctx; + struct sdap_access_ctx *access_ctx; + errno_t ret; + + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + + access_ctx = talloc_zero(mem_ctx, struct sdap_access_ctx); + if(access_ctx == NULL) { + ret = ENOMEM; + goto done; + } - ret = ldap_id_init_internal(be_ctx, ops, &data); + access_ctx->id_ctx = init_ctx->id_ctx; + + ret = set_access_rules(access_ctx, access_ctx, access_ctx->id_ctx->opts); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init LDAP ID provider [%d]: %s\n", - ret, strerror(ret)); - return ret; + DEBUG(SSSDBG_CRIT_FAILURE, + "set_access_rules failed: [%d][%s].\n", + ret, sss_strerror(ret)); + goto done; } - id_ctx = talloc_get_type(data, struct sdap_id_ctx); - if (!id_ctx) { - DEBUG(SSSDBG_CRIT_FAILURE, "No ID provider?\n"); - return EIO; + dp_set_method(dp_methods, DPM_ACCESS_HANDLER, + sdap_pam_access_handler_send, sdap_pam_access_handler_recv, access_ctx, + struct sdap_access_ctx, struct pam_data, struct pam_data *); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(access_ctx); } - return sdap_autofs_init(be_ctx, id_ctx, ops, pvt_data); + return ret; +} + +errno_t sssm_ldap_autofs_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) +{ +#ifdef BUILD_AUTOFS + struct ldap_init_ctx *init_ctx; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing LDAP autofs handler\n"); + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + + return sdap_autofs_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods); #else DEBUG(SSSDBG_MINOR_FAILURE, "Autofs init handler called but SSSD is " "built without autofs support, ignoring\n"); @@ -517,9 +637,21 @@ int sssm_ldap_autofs_init(struct be_ctx *be_ctx, #endif } -static void sdap_shutdown(struct be_req *req) +errno_t sssm_ldap_sudo_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + void *module_data, + struct dp_method *dp_methods) { - /* TODO: Clean up any internal data */ - sdap_handler_done(req, DP_ERR_OK, EOK, NULL); -} +#ifdef BUILD_SUDO + struct ldap_init_ctx *init_ctx; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing LDAP sudo handler\n"); + init_ctx = talloc_get_type(module_data, struct ldap_init_ctx); + return sdap_sudo_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods); +#else + DEBUG(SSSDBG_MINOR_FAILURE, "Sudo init handler called but SSSD is " + "built without sudo support, ignoring\n"); + return EOK; +#endif +} diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h index 93ddfd5e5..049daced6 100644 --- a/src/providers/ldap/sdap_access.h +++ b/src/providers/ldap/sdap_access.h @@ -76,6 +76,17 @@ struct sdap_access_ctx { }; struct tevent_req * +sdap_pam_access_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_access_ctx *access_ctx, + struct pam_data *pd, + struct dp_req_params *params); + +errno_t +sdap_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); + +struct tevent_req * sdap_access_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct be_ctx *be_ctx, diff --git a/src/providers/ldap/sdap_autofs.c b/src/providers/ldap/sdap_autofs.c index f65b6ea61..c02c04d5c 100644 --- a/src/providers/ldap/sdap_autofs.c +++ b/src/providers/ldap/sdap_autofs.c @@ -34,103 +34,6 @@ #include "db/sysdb_autofs.h" #include "util/util.h" -static void -sdap_autofs_shutdown(struct be_req *req) -{ - sdap_handler_done(req, DP_ERR_OK, EOK, NULL); -} - -void sdap_autofs_handler(struct be_req *be_req); - -/* Autofs Handler */ -struct bet_ops sdap_autofs_ops = { - .handler = sdap_autofs_handler, - .finalize = sdap_autofs_shutdown -}; - -int sdap_autofs_init(struct be_ctx *be_ctx, - struct sdap_id_ctx *id_ctx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - - DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing autofs LDAP back end\n"); - - *ops = &sdap_autofs_ops; - *pvt_data = id_ctx; - - ret = ldap_get_autofs_options(id_ctx, be_ctx->cdb, - be_ctx->conf_path, id_ctx->opts); - if (ret != EOK) { - return ret; - } - - return ret; -} - -static struct tevent_req * -sdap_autofs_get_map_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *map_name); - -static void sdap_autofs_handler_done(struct tevent_req *req); - -void sdap_autofs_handler(struct be_req *be_req) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); - struct sdap_id_ctx *id_ctx; - struct be_autofs_req *autofs_req; - struct tevent_req *req; - const char *master_map; - int ret = EOK; - - DEBUG(SSSDBG_TRACE_INTERNAL, "sdap autofs handler called\n"); - - id_ctx = talloc_get_type(be_ctx->bet_info[BET_AUTOFS].pvt_bet_data, - struct sdap_id_ctx); - - if (be_is_offline(id_ctx->be)) { - return sdap_handler_done(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline"); - } - - autofs_req = talloc_get_type(be_req_get_data(be_req), struct be_autofs_req); - - DEBUG(SSSDBG_FUNC_DATA, "Requested refresh for: %s\n", - autofs_req->mapname ? autofs_req->mapname : "<ALL>\n"); - - if (autofs_req->mapname != NULL) { - master_map = dp_opt_get_string(id_ctx->opts->basic, - SDAP_AUTOFS_MAP_MASTER_NAME); - if (strcmp(master_map, autofs_req->mapname) == 0) { - autofs_req->invalidate = true; - DEBUG(SSSDBG_FUNC_DATA, "Refresh of automount master map triggered: %s\n", - autofs_req->mapname); - } - } - - if (autofs_req->invalidate) { - ret = sysdb_invalidate_autofs_maps(id_ctx->be->domain); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "Could not invalidate autofs maps, " - "backend might return stale entries\n"); - } - } - - req = sdap_autofs_get_map_send(be_req, be_ctx->ev, - id_ctx, autofs_req->mapname); - if (!req) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(req, sdap_autofs_handler_done, be_req); - - return; -fail: - be_req_terminate(be_req, DP_ERR_FATAL, ret, NULL); -} - struct autofs_get_map_state { struct tevent_context *ev; struct sdap_id_ctx *ctx; @@ -298,15 +201,121 @@ sdap_autofs_get_map_recv(struct tevent_req *req, int *dp_error_out) return EOK; } -static void -sdap_autofs_handler_done(struct tevent_req *req) +struct sdap_autofs_handler_state { + struct dp_reply_std reply; +}; + +static void sdap_autofs_handler_done(struct tevent_req *subreq); + +struct tevent_req * +sdap_autofs_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_autofs_data *data, + struct dp_req_params *params) { - struct be_req *be_req = - tevent_req_callback_data(req, struct be_req); - int dperr; + struct sdap_autofs_handler_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + const char *master_map; + errno_t ret; - ret = sdap_autofs_get_map_recv(req, &dperr); - sdap_handler_done(be_req, dperr, ret, strerror(ret)); + req = tevent_req_create(mem_ctx, &state, struct sdap_autofs_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + DEBUG(SSSDBG_FUNC_DATA, "Requested refresh for: %s\n", data->mapname); + + master_map = dp_opt_get_string(id_ctx->opts->basic, + SDAP_AUTOFS_MAP_MASTER_NAME); + if (strcmp(master_map, data->mapname) == 0) { + DEBUG(SSSDBG_FUNC_DATA, "Refresh of automount master map triggered: " + "%s\n", data->mapname); + + ret = sysdb_invalidate_autofs_maps(id_ctx->be->domain); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Could not invalidate autofs maps, " + "backend might return stale entries\n"); + } + } + + subreq = sdap_autofs_get_map_send(mem_ctx, params->ev, + id_ctx, data->mapname); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request for %s.\n", + data->mapname); + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_autofs_handler_done, req); + + return req; + +immediately: + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; } +static void sdap_autofs_handler_done(struct tevent_req *subreq) +{ + struct sdap_autofs_handler_state *state; + struct tevent_req *req; + int dp_error; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_autofs_handler_state); + + ret = sdap_autofs_get_map_recv(subreq, &dp_error); + talloc_zfree(subreq); + + /* TODO For backward compatibility we always return EOK to DP now. */ + dp_reply_std_set(&state->reply, dp_error, ret, NULL); + tevent_req_done(req); +} + +errno_t +sdap_autofs_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data) +{ + struct sdap_autofs_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_autofs_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *data = state->reply; + + return EOK; +} + +errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_method *dp_methods) +{ + errno_t ret; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing autofs LDAP back end\n"); + + ret = ldap_get_autofs_options(id_ctx, be_ctx->cdb, be_ctx->conf_path, + id_ctx->opts); + if (ret != EOK) { + return ret; + } + + dp_set_method(dp_methods, DPM_AUTOFS_HANDLER, + sdap_autofs_handler_send, sdap_autofs_handler_recv, id_ctx, + struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std); + + return EOK; +} diff --git a/src/providers/ldap/sdap_autofs.h b/src/providers/ldap/sdap_autofs.h index 0369e2645..593d8c94f 100644 --- a/src/providers/ldap/sdap_autofs.h +++ b/src/providers/ldap/sdap_autofs.h @@ -25,10 +25,10 @@ #ifndef _SDAP_AUTOFS_H_ #define _SDAP_AUTOFS_H_ -int sdap_autofs_init(struct be_ctx *be_ctx, - struct sdap_id_ctx *id_ctx, - struct bet_ops **ops, - void **pvt_data); +errno_t sdap_autofs_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_method *dp_methods); struct tevent_req * sdap_autofs_setautomntent_send(TALLOC_CTX *memctx, diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c index 4e322124c..b5dfc6cef 100644 --- a/src/providers/ldap/sdap_idmap.c +++ b/src/providers/ldap/sdap_idmap.c @@ -542,7 +542,7 @@ bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx, TALLOC_CTX *tmp_ctx = NULL; if (dp_opt_get_bool(ctx->id_ctx->opts->basic, SDAP_ID_MAPPING) - && 0 == strcmp("ldap", ctx->id_ctx->be->bet_info[BET_ID].mod_name)) { + && dp_target_enabled(ctx->id_ctx->be->provider, "ldap", DPT_ID)) { return true; } diff --git a/src/providers/ldap/sdap_online_check.c b/src/providers/ldap/sdap_online_check.c new file mode 100644 index 000000000..f721a5f45 --- /dev/null +++ b/src/providers/ldap/sdap_online_check.c @@ -0,0 +1,249 @@ +/* + Authors: + Pavel Březina <pbrezina@redhat.com> + + Copyright (C) 2016 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 <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <talloc.h> +#include <tevent.h> +#include "util/util.h" +#include "providers/backend.h" +#include "providers/ldap/sdap_async.h" +#include "providers/ldap/ldap_common.h" + +struct sdap_online_check_state { + struct sdap_id_ctx *id_ctx; + struct be_ctx *be_ctx; +}; + +static void sdap_online_check_connect_done(struct tevent_req *subreq); +static void sdap_online_check_reinit_done(struct tevent_req *subreq); + +static struct tevent_req *sdap_online_check_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx) +{ + struct sdap_online_check_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + struct be_ctx *be_ctx; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_online_check_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + state->id_ctx = id_ctx; + state->be_ctx = be_ctx = id_ctx->be; + + subreq = sdap_cli_connect_send(state, be_ctx->ev, id_ctx->opts, be_ctx, + id_ctx->conn->service, false, + CON_TLS_DFL, false); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_online_check_connect_done, req); + + return req; + +immediately: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, be_ctx->ev); + + return req; +} + +static void sdap_online_check_connect_done(struct tevent_req *subreq) +{ + struct sdap_online_check_state *state; + struct sdap_server_opts *srv_opts; + struct sdap_id_ctx *id_ctx; + struct tevent_req *req; + bool can_retry; + bool reinit = false; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_online_check_state); + + id_ctx = state->id_ctx; + + ret = sdap_cli_connect_recv(subreq, state, &can_retry, NULL, &srv_opts); + talloc_zfree(subreq); + if (ret != EOK) { + if (can_retry == false) { + ret = ERR_OFFLINE; + } + + goto done; + } else { + if (id_ctx->srv_opts == NULL) { + srv_opts->max_user_value = 0; + srv_opts->max_group_value = 0; + srv_opts->max_service_value = 0; + srv_opts->max_sudo_value = 0; + } else if (strcmp(srv_opts->server_id, id_ctx->srv_opts->server_id) == 0 + && srv_opts->supports_usn + && id_ctx->srv_opts->last_usn > srv_opts->last_usn) { + id_ctx->srv_opts->max_user_value = 0; + id_ctx->srv_opts->max_group_value = 0; + id_ctx->srv_opts->max_service_value = 0; + id_ctx->srv_opts->max_sudo_value = 0; + id_ctx->srv_opts->last_usn = srv_opts->last_usn; + + reinit = true; + } + + sdap_steal_server_opts(id_ctx, &srv_opts); + } + + if (reinit) { + DEBUG(SSSDBG_TRACE_FUNC, "Server reinitialization detected. " + "Cleaning cache.\n"); + subreq = sdap_reinit_cleanup_send(state, state->be_ctx, id_ctx); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " + "clean up.\n"); + /* not fatal */ + goto done; + } + + tevent_req_set_callback(subreq, sdap_online_check_reinit_done, req); + return; + } + + ret = EOK; + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +static void sdap_online_check_reinit_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + + ret = sdap_reinit_cleanup_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " + "clean up [%d]: %s\n", ret, strerror(ret)); + /* not fatal */ + } else { + DEBUG(SSSDBG_TRACE_FUNC, "Reinitialization clean up completed\n"); + } + + tevent_req_done(req); +} + +static errno_t sdap_online_check_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +struct sdap_online_check_handler_state { + struct dp_reply_std reply; +}; + +static void sdap_online_check_handler_done(struct tevent_req *subreq); + +struct tevent_req * +sdap_online_check_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + void *data, + struct dp_req_params *params) +{ + struct sdap_online_check_handler_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, + struct sdap_online_check_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + subreq = sdap_online_check_send(state, id_ctx); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_online_check_handler_done, req); + + return req; + +immediately: + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; +} + +static void sdap_online_check_handler_done(struct tevent_req *subreq) +{ + struct sdap_online_check_handler_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_online_check_handler_state); + + ret = sdap_online_check_recv(subreq); + talloc_zfree(subreq); + + /* TODO For backward compatibility we always return EOK to DP now. */ + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + tevent_req_done(req); +} + +errno_t sdap_online_check_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data) +{ + struct sdap_online_check_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_online_check_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *data = state->reply; + + return EOK; +} diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index 2ed97b9aa..bf73f7b45 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -29,13 +29,118 @@ #include "providers/ldap/sdap_sudo.h" #include "db/sysdb_sudo.h" -static void sdap_sudo_handler(struct be_req *breq); - -struct bet_ops sdap_sudo_ops = { - .handler = sdap_sudo_handler, - .finalize = NULL +struct sdap_sudo_handler_state { + uint32_t type; + struct dp_reply_std reply; }; +static void sdap_sudo_handler_done(struct tevent_req *subreq); + +static struct tevent_req * +sdap_sudo_handler_send(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx, + struct dp_sudo_data *data, + struct dp_req_params *params) +{ + struct sdap_sudo_handler_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_handler_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + state->type = data->type; + + switch (data->type) { + case BE_REQ_SUDO_FULL: + DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n"); + subreq = sdap_sudo_full_refresh_send(state, sudo_ctx); + break; + case BE_REQ_SUDO_RULES: + DEBUG(SSSDBG_TRACE_FUNC, "Issuing a refresh of specific sudo rules\n"); + subreq = sdap_sudo_rules_refresh_send(state, sudo_ctx, data->rules); + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", data->type); + ret = EINVAL; + goto immediately; + } + + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request: %d\n", data->type); + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_sudo_handler_done, req); + + return req; + +immediately: + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; +} + +static void sdap_sudo_handler_done(struct tevent_req *subreq) +{ + struct sdap_sudo_handler_state *state; + struct tevent_req *req; + int dp_error; + bool deleted; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_handler_state); + + switch (state->type) { + case BE_REQ_SUDO_FULL: + ret = sdap_sudo_full_refresh_recv(subreq, &dp_error); + talloc_zfree(subreq); + break; + case BE_REQ_SUDO_RULES: + ret = sdap_sudo_rules_refresh_recv(subreq, &dp_error, &deleted); + talloc_zfree(subreq); + if (ret == EOK && deleted == true) { + ret = ENOENT; + } + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", state->type); + dp_error = DP_ERR_FATAL; + ret = ERR_INTERNAL; + break; + } + + /* TODO For backward compatibility we always return EOK to DP now. */ + dp_reply_std_set(&state->reply, dp_error, ret, NULL); + tevent_req_done(req); +} + +static errno_t +sdap_sudo_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct dp_reply_std *data) +{ + struct sdap_sudo_handler_state *state = NULL; + + state = tevent_req_data(req, struct sdap_sudo_handler_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *data = state->reply; + + return EOK; +} + static void sdap_sudo_online_cb(void *pvt) { struct sdap_sudo_ctx *sudo_ctx; @@ -51,43 +156,40 @@ static void sdap_sudo_online_cb(void *pvt) sudo_ctx->run_hostinfo = true; } -int sdap_sudo_init(struct be_ctx *be_ctx, - struct sdap_id_ctx *id_ctx, - struct bet_ops **ops, - void **pvt_data) +errno_t sdap_sudo_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_method *dp_methods) { - struct sdap_sudo_ctx *sudo_ctx = NULL; + struct sdap_sudo_ctx *sudo_ctx; int ret; DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing sudo LDAP back end\n"); - sudo_ctx = talloc_zero(be_ctx, struct sdap_sudo_ctx); + sudo_ctx = talloc_zero(mem_ctx, struct sdap_sudo_ctx); if (sudo_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc() failed\n"); return ENOMEM; } sudo_ctx->id_ctx = id_ctx; - *ops = &sdap_sudo_ops; - *pvt_data = sudo_ctx; - ret = ldap_get_sudo_options(be_ctx->cdb, - be_ctx->conf_path, id_ctx->opts, + ret = ldap_get_sudo_options(be_ctx->cdb, be_ctx->conf_path, id_ctx->opts, &sudo_ctx->use_host_filter, &sudo_ctx->include_regexp, &sudo_ctx->include_netgroups); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Cannot get SUDO options [%d]: %s\n", - ret, strerror(ret)); + ret, sss_strerror(ret)); goto done; } if (sudo_ctx->use_host_filter) { - ret = be_add_online_cb(sudo_ctx, sudo_ctx->id_ctx->be, - sdap_sudo_online_cb, sudo_ctx, NULL); + ret = be_add_online_cb(sudo_ctx, be_ctx, sdap_sudo_online_cb, + sudo_ctx, NULL); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to install online callback " - "[%d]: %s\n", ret, sss_strerror(ret)); + "[%d]: %s\n", ret, sss_strerror(ret)); goto done; } @@ -95,15 +197,18 @@ int sdap_sudo_init(struct be_ctx *be_ctx, sudo_ctx->run_hostinfo = true; } - ret = sdap_sudo_ptask_setup(sudo_ctx->id_ctx->be, sudo_ctx); + ret = sdap_sudo_ptask_setup(be_ctx, sudo_ctx); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to setup periodical refresh of sudo rules [%d]: %s\n", - ret, strerror(ret)); + DEBUG(SSSDBG_OP_FAILURE, "Unable to setup periodical refresh of " + "sudo rules [%d]: %s\n", ret, sss_strerror(ret)); /* periodical updates will not work, but specific-rule update * is no affected by this, therefore we don't have to fail here */ } + dp_set_method(dp_methods, DPM_SUDO_HANDLER, + sdap_sudo_handler_send, sdap_sudo_handler_recv, sudo_ctx, + struct sdap_sudo_ctx, struct dp_sudo_data, struct dp_reply_std); + ret = EOK; done: @@ -113,85 +218,3 @@ done: return ret; } - -static void sdap_sudo_reply(struct tevent_req *req) -{ - struct be_req *be_req = NULL; - struct be_sudo_req *sudo_req = NULL; - int dp_error; - bool deleted; - int ret; - - be_req = tevent_req_callback_data(req, struct be_req); - sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req); - - switch (sudo_req->type) { - case BE_REQ_SUDO_FULL: - ret = sdap_sudo_full_refresh_recv(req, &dp_error); - break; - case BE_REQ_SUDO_RULES: - ret = sdap_sudo_rules_refresh_recv(req, &dp_error, &deleted); - if (ret == EOK && deleted == true) { - ret = ENOENT; - } - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", - sudo_req->type); - dp_error = DP_ERR_FATAL; - ret = ERR_INTERNAL; - break; - } - - talloc_zfree(req); - sdap_handler_done(be_req, dp_error, ret, strerror(ret)); -} - -static void sdap_sudo_handler(struct be_req *be_req) -{ - struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); - struct tevent_req *req = NULL; - struct be_sudo_req *sudo_req = NULL; - struct sdap_sudo_ctx *sudo_ctx = NULL; - int ret = EOK; - - if (be_is_offline(be_ctx)) { - sdap_handler_done(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline"); - return; - } - - sudo_ctx = talloc_get_type(be_ctx->bet_info[BET_SUDO].pvt_bet_data, - struct sdap_sudo_ctx); - - sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req); - - switch (sudo_req->type) { - case BE_REQ_SUDO_FULL: - DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n"); - req = sdap_sudo_full_refresh_send(be_req, sudo_ctx); - break; - case BE_REQ_SUDO_RULES: - DEBUG(SSSDBG_TRACE_FUNC, "Issuing a refresh of specific sudo rules\n"); - req = sdap_sudo_rules_refresh_send(be_req, sudo_ctx, sudo_req->rules); - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", - sudo_req->type); - ret = EINVAL; - goto fail; - } - - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request: %d\n", - sudo_req->type); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(req, sdap_sudo_reply, be_req); - - return; - -fail: - sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL); -} diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index fccd64c2f..0e732abf4 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -40,10 +40,10 @@ struct sdap_sudo_ctx { /* Common functions from ldap_sudo.c */ -int sdap_sudo_init(struct be_ctx *be_ctx, - struct sdap_id_ctx *id_ctx, - struct bet_ops **ops, - void **pvt_data); +errno_t sdap_sudo_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct dp_method *dp_methods); /* sdap async interface */ struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx, |