summaryrefslogtreecommitdiffstats
path: root/src/providers
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2016-03-29 12:38:25 +0200
committerJakub Hrozek <jhrozek@redhat.com>2016-06-20 14:48:47 +0200
commitdea636af4d1902a081ee891f1b19ee2f8729d759 (patch)
treea4d66ceb2b32ddf3b69bee1f1e2412568eae655e /src/providers
parent62370340092503baeaf6587d7ffe4fe25bd9582d (diff)
downloadsssd-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')
-rw-r--r--src/providers/ad/ad_access.c121
-rw-r--r--src/providers/ad/ad_access.h12
-rw-r--r--src/providers/ad/ad_autofs.c10
-rw-r--r--src/providers/ad/ad_common.h18
-rw-r--r--src/providers/ad/ad_id.c186
-rw-r--r--src/providers/ad/ad_id.h14
-rw-r--r--src/providers/ad/ad_init.c698
-rw-r--r--src/providers/ad/ad_subdomains.c1404
-rw-r--r--src/providers/ad/ad_subdomains.h9
-rw-r--r--src/providers/ad/ad_sudo.c14
-rw-r--r--src/providers/backend.h126
-rw-r--r--src/providers/data_provider/dp_custom_data.h30
-rw-r--r--src/providers/data_provider/dp_iface.c12
-rw-r--r--src/providers/data_provider/dp_iface.h28
-rw-r--r--src/providers/data_provider/dp_target_auth.c302
-rw-r--r--src/providers/data_provider/dp_target_autofs.c55
-rw-r--r--src/providers/data_provider/dp_target_hostid.c63
-rw-r--r--src/providers/data_provider/dp_target_id.c311
-rw-r--r--src/providers/data_provider/dp_target_subdomains.c50
-rw-r--r--src/providers/data_provider/dp_target_sudo.c199
-rw-r--r--src/providers/data_provider_be.c2464
-rw-r--r--src/providers/data_provider_req.c29
-rw-r--r--src/providers/data_provider_req.h3
-rw-r--r--src/providers/ipa/ipa_access.c951
-rw-r--r--src/providers/ipa/ipa_access.h34
-rw-r--r--src/providers/ipa/ipa_auth.c339
-rw-r--r--src/providers/ipa/ipa_auth.h14
-rw-r--r--src/providers/ipa/ipa_autofs.c23
-rw-r--r--src/providers/ipa/ipa_common.h14
-rw-r--r--src/providers/ipa/ipa_hbac_common.c12
-rw-r--r--src/providers/ipa/ipa_hostid.c177
-rw-r--r--src/providers/ipa/ipa_hostid.h11
-rw-r--r--src/providers/ipa/ipa_id.c273
-rw-r--r--src/providers/ipa/ipa_id.h14
-rw-r--r--src/providers/ipa/ipa_init.c1032
-rw-r--r--src/providers/ipa/ipa_selinux.c742
-rw-r--r--src/providers/ipa/ipa_selinux.h11
-rw-r--r--src/providers/ipa/ipa_subdomains.c1593
-rw-r--r--src/providers/ipa/ipa_subdomains.h10
-rw-r--r--src/providers/ipa/ipa_subdomains_ext_groups.c22
-rw-r--r--src/providers/ipa/ipa_subdomains_id.c19
-rw-r--r--src/providers/ipa/ipa_subdomains_server.c2
-rw-r--r--src/providers/ipa/ipa_sudo.c220
-rw-r--r--src/providers/krb5/krb5_auth.c172
-rw-r--r--src/providers/krb5/krb5_auth.h12
-rw-r--r--src/providers/krb5/krb5_common.h4
-rw-r--r--src/providers/krb5/krb5_init.c265
-rw-r--r--src/providers/ldap/ldap_access.c122
-rw-r--r--src/providers/ldap/ldap_auth.c619
-rw-r--r--src/providers/ldap/ldap_common.c6
-rw-r--r--src/providers/ldap/ldap_common.h62
-rw-r--r--src/providers/ldap/ldap_id.c300
-rw-r--r--src/providers/ldap/ldap_init.c780
-rw-r--r--src/providers/ldap/sdap_access.h11
-rw-r--r--src/providers/ldap/sdap_autofs.c217
-rw-r--r--src/providers/ldap/sdap_autofs.h8
-rw-r--r--src/providers/ldap/sdap_idmap.c2
-rw-r--r--src/providers/ldap/sdap_online_check.c249
-rw-r--r--src/providers/ldap/sdap_sudo.c233
-rw-r--r--src/providers/ldap/sdap_sudo.h8
-rw-r--r--src/providers/proxy/proxy.h25
-rw-r--r--src/providers/proxy/proxy_auth.c278
-rw-r--r--src/providers/proxy/proxy_client.c192
-rw-r--r--src/providers/proxy/proxy_id.c201
-rw-r--r--src/providers/proxy/proxy_init.c675
-rw-r--r--src/providers/simple/simple_access.c269
-rw-r--r--src/providers/simple/simple_access_check.c17
67 files changed, 8084 insertions, 8314 deletions
diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c
index bf03f8637..a64a5b053 100644
--- a/src/providers/ad/ad_access.c
+++ b/src/providers/ad/ad_access.c
@@ -457,73 +457,92 @@ ad_access_recv(struct tevent_req *req)
return EOK;
}
-static void
-ad_access_done(struct tevent_req *req);
+struct ad_pam_access_handler_state {
+ struct pam_data *pd;
+};
-void
-ad_access_handler(struct be_req *breq)
+static void ad_pam_access_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ad_pam_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_access_ctx *access_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
{
+ struct ad_pam_access_handler_state *state;
+ struct tevent_req *subreq;
struct tevent_req *req;
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- struct ad_access_ctx *access_ctx =
- talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct ad_access_ctx);
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(breq), struct pam_data);
- struct sss_domain_info *domain;
- /* Handle subdomains */
- if (strcasecmp(pd->domain, be_ctx->domain->name) != 0) {
- domain = find_domain_by_name(be_ctx->domain, pd->domain, true);
- if (domain == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
- be_req_terminate(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
- return;
- }
- } else {
- domain = be_ctx->domain;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_pam_access_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- /* Verify access control: locked accounts, ldap policies, GPOs, etc */
- req = ad_access_send(breq, be_ctx->ev, be_ctx, domain,
- access_ctx, pd);
- if (!req) {
- be_req_terminate(breq, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
- return;
+ state->pd = pd;
+
+ subreq = ad_access_send(state, params->ev, params->be_ctx,
+ params->domain, access_ctx, pd);
+ if (subreq == NULL) {
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
}
- tevent_req_set_callback(req, ad_access_done, breq);
+
+ tevent_req_set_callback(subreq, ad_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);
+
+ return req;
}
-static void
-ad_access_done(struct tevent_req *req)
+static void ad_pam_access_handler_done(struct tevent_req *subreq)
{
+ struct ad_pam_access_handler_state *state;
+ struct tevent_req *req;
errno_t ret;
- struct be_req *breq =
- tevent_req_callback_data(req, struct be_req);
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(breq), struct pam_data);
- ret = ad_access_recv(req);
- talloc_zfree(req);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_pam_access_handler_state);
+
+ ret = ad_access_recv(subreq);
+ talloc_free(subreq);
switch (ret) {
case EOK:
- pd->pam_status = PAM_SUCCESS;
- be_req_terminate(breq, DP_ERR_OK, PAM_SUCCESS, NULL);
- return;
+ state->pd->pam_status = PAM_SUCCESS;
+ break;
case ERR_ACCESS_DENIED:
- /* We got the proper denial */
- pd->pam_status = PAM_PERM_DENIED;
- be_req_terminate(breq, DP_ERR_OK, PAM_PERM_DENIED, NULL);
- return;
+ state->pd->pam_status = PAM_PERM_DENIED;
+ break;
case ERR_ACCOUNT_EXPIRED:
- pd->pam_status = PAM_ACCT_EXPIRED;
- be_req_terminate(breq, DP_ERR_OK, PAM_ACCT_EXPIRED, NULL);
- return;
+ state->pd->pam_status = PAM_ACCT_EXPIRED;
+ break;
default:
- /* Something went wrong */
- pd->pam_status = PAM_SYSTEM_ERR;
- be_req_terminate(breq, DP_ERR_FATAL,
- PAM_SYSTEM_ERR, sss_strerror(ret));
- return;
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ break;
}
+
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+ad_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct ad_pam_access_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ad_pam_access_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
}
diff --git a/src/providers/ad/ad_access.h b/src/providers/ad/ad_access.h
index 34f5d2d1b..cc565a8e6 100644
--- a/src/providers/ad/ad_access.h
+++ b/src/providers/ad/ad_access.h
@@ -49,7 +49,15 @@ struct ad_access_ctx {
enum gpo_map_type gpo_default_right;
};
-void
-ad_access_handler(struct be_req *breq);
+struct tevent_req *
+ad_pam_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_access_ctx *access_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+ad_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data);
#endif /* AD_ACCESS_H_ */
diff --git a/src/providers/ad/ad_autofs.c b/src/providers/ad/ad_autofs.c
index 7d4ed34b5..c1d7219aa 100644
--- a/src/providers/ad/ad_autofs.c
+++ b/src/providers/ad/ad_autofs.c
@@ -22,16 +22,16 @@
#include "providers/ad/ad_common.h"
#include "providers/ldap/sdap_autofs.h"
-int ad_autofs_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t ad_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct dp_method *dp_methods)
{
int ret;
DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing autofs AD back end\n");
- ret = sdap_autofs_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data);
+ ret = sdap_autofs_init(mem_ctx, be_ctx, id_ctx->sdap_id_ctx, dp_methods);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD autofs [%d]: %s\n",
ret, sss_strerror(ret));
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index 37178d611..ce363c5a4 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -172,15 +172,15 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx,
struct ad_options *ctx);
void ad_dyndns_timer(void *pvt);
-int ad_sudo_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data);
-
-int ad_autofs_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data);
+errno_t ad_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct dp_method *dp_methods);
+
+errno_t ad_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct dp_method *dp_methods);
errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
struct ad_options *ad_opts);
diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
index c464fa948..92ac4ab6a 100644
--- a/src/providers/ad/ad_id.c
+++ b/src/providers/ad/ad_id.c
@@ -51,7 +51,6 @@ disable_gc(struct ad_options *ad_options)
}
struct ad_handle_acct_info_state {
- struct be_req *breq;
struct be_acct_req *ar;
struct sdap_id_ctx *ctx;
struct sdap_id_conn_ctx **conn;
@@ -69,7 +68,6 @@ static void ad_handle_acct_info_done(struct tevent_req *subreq);
struct tevent_req *
ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
- struct be_req *breq,
struct be_acct_req *ar,
struct sdap_id_ctx *ctx,
struct ad_options *ad_options,
@@ -78,14 +76,13 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req;
struct ad_handle_acct_info_state *state;
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
+ struct be_ctx *be_ctx = ctx->be;
errno_t ret;
req = tevent_req_create(mem_ctx, &state, struct ad_handle_acct_info_state);
if (req == NULL) {
return NULL;
}
- state->breq = breq;
state->ar = ar;
state->ctx = ctx;
state->sdom = sdom;
@@ -276,7 +273,7 @@ ad_handle_acct_info_recv(struct tevent_req *req,
}
struct sdap_id_conn_ctx **
-get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
+get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
struct sss_domain_info *dom, struct be_acct_req *ar)
{
struct sdap_id_conn_ctx **clist;
@@ -289,11 +286,11 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
case BE_REQ_USER_AND_GROUP: /* get SID */
case BE_REQ_GROUP: /* group */
case BE_REQ_INITGROUPS: /* init groups for user */
- clist = ad_gc_conn_list(breq, ad_ctx, dom);
+ clist = ad_gc_conn_list(mem_ctx, ad_ctx, dom);
break;
default:
/* Requests for other object should only contact LDAP by default */
- clist = ad_ldap_conn_list(breq, ad_ctx, dom);
+ clist = ad_ldap_conn_list(mem_ctx, ad_ctx, dom);
break;
}
@@ -365,146 +362,136 @@ done:
return shortcut;
}
-static void ad_account_info_complete(struct tevent_req *req);
-
-struct ad_account_info_state {
- struct be_req *be_req;
- struct sss_domain_info *dom;
+struct ad_account_info_handler_state {
+ struct sss_domain_info *domain;
+ struct dp_reply_std reply;
};
-void
-ad_account_info_handler(struct be_req *be_req)
+static void ad_account_info_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params)
{
- struct ad_id_ctx *ad_ctx;
- struct be_acct_req *ar;
+ struct ad_account_info_handler_state *state;
+ struct sdap_id_conn_ctx **clist;
struct sdap_id_ctx *sdap_id_ctx;
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct tevent_req *req;
- struct sss_domain_info *dom;
+ struct sss_domain_info *domain;
struct sdap_domain *sdom;
- struct sdap_id_conn_ctx **clist;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ struct be_ctx *be_ctx;
bool shortcut;
errno_t ret;
- struct ad_account_info_state *state;
- ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct ad_id_ctx);
- ar = talloc_get_type(be_req_get_data(be_req), struct be_acct_req);
- sdap_id_ctx = ad_ctx->sdap_id_ctx;
+ sdap_id_ctx = id_ctx->sdap_id_ctx;
+ be_ctx = params->be_ctx;
- if (be_is_offline(be_ctx)) {
- return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_account_info_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- if (sdap_is_enum_request(ar)) {
+ if (sdap_is_enum_request(data)) {
DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
- return sdap_handler_done(be_req, DP_ERR_OK, EOK, "Success");
+ ret = EOK;
+ goto immediately;
}
/* Try to shortcut if this is ID or SID search and it belongs to
* other domain range than is in ar->domain. */
shortcut = ad_account_can_shortcut(be_ctx, sdap_id_ctx->opts->idmap_ctx,
- ar->filter_type, ar->filter_value,
- ar->domain);
+ data->filter_type, data->filter_value,
+ data->domain);
if (shortcut) {
DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n");
- be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
- return;
+ ret = EOK;
+ goto immediately;
}
- dom = be_ctx->domain;
- if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
- /* Subdomain request, verify subdomain */
- dom = find_domain_by_name(be_ctx->domain, ar->domain, true);
+ domain = be_ctx->domain;
+ if (strcasecmp(data->domain, be_ctx->domain->name) != 0) {
+ /* Subdomain request, verify subdomain. */
+ domain = find_domain_by_name(be_ctx->domain, data->domain, true);
}
- if (dom == NULL) {
+ if (domain == NULL) {
ret = EINVAL;
- goto fail;
+ goto immediately;
}
- /* Determine whether to connect to GC, LDAP or try both */
- clist = get_conn_list(be_req, ad_ctx, dom, ar);
+ /* Determine whether to connect to GC, LDAP or try both. */
+ clist = get_conn_list(state, id_ctx, domain, data);
if (clist == NULL) {
ret = EIO;
- goto fail;
+ goto immediately;
}
- sdom = sdap_domain_get(sdap_id_ctx->opts, dom);
+ sdom = sdap_domain_get(sdap_id_ctx->opts, domain);
if (sdom == NULL) {
ret = EIO;
- goto fail;
+ goto immediately;
}
- state = talloc(be_req, struct ad_account_info_state);
- if (state == NULL) {
- ret = ENOMEM;
- goto fail;
- }
- state->dom = sdom->dom;
- state->be_req = be_req;
+ state->domain = sdom->dom;
- req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx,
- ad_ctx->ad_options, sdom, clist);
- if (req == NULL) {
+ subreq = ad_handle_acct_info_send(state, data, sdap_id_ctx,
+ id_ctx->ad_options, sdom, clist);
+ if (subreq == NULL) {
ret = ENOMEM;
- goto fail;
+ goto immediately;
}
- tevent_req_set_callback(req, ad_account_info_complete, state);
- return;
-fail:
- be_req_terminate(be_req, DP_ERR_FATAL, ret, NULL);
+ tevent_req_set_callback(subreq, ad_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
-ad_account_info_complete(struct tevent_req *req)
+static void ad_account_info_handler_done(struct tevent_req *subreq)
{
- struct be_req *be_req;
- errno_t ret;
+ struct ad_account_info_handler_state *state;
+ struct tevent_req *req;
+ const char *err_msg;
int dp_error;
- const char *error_text = "Internal error";
- const char *req_error_text;
- struct ad_account_info_state *state;
-
- state = tevent_req_callback_data(req, struct ad_account_info_state);
- be_req = state->be_req;
-
- ret = ad_handle_acct_info_recv(req, &dp_error, &req_error_text);
- talloc_zfree(req);
- if (ret == ERR_SUBDOM_INACTIVE) {
- be_mark_dom_offline(state->dom, be_req_get_be_ctx(be_req));
- return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
- } else if (dp_error == DP_ERR_OK) {
- if (ret == EOK) {
- error_text = NULL;
- } else {
- DEBUG(SSSDBG_FATAL_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;
- }
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_account_info_handler_state);
+
+ ret = ad_handle_acct_info_recv(subreq, &dp_error, &err_msg);
+ talloc_zfree(subreq);
- return be_req_terminate(be_req, dp_error, ret, error_text);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ dp_reply_std_set(&state->reply, dp_error, ret, err_msg);
+ tevent_req_done(req);
}
-void
-ad_check_online(struct be_req *be_req)
+errno_t ad_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
{
- struct ad_id_ctx *ad_ctx;
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
+ struct ad_account_info_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ad_account_info_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct ad_id_ctx);
+ *data = state->reply;
- return sdap_do_online_check(be_req, ad_ctx->sdap_id_ctx);
+ return EOK;
}
struct ad_enumeration_state {
@@ -1079,3 +1066,4 @@ ad_enumeration_recv(struct tevent_req *req)
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
+
diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
index 9eb0ac375..2e7f9005a 100644
--- a/src/providers/ad/ad_id.h
+++ b/src/providers/ad/ad_id.h
@@ -23,12 +23,18 @@
#ifndef AD_ID_H_
#define AD_ID_H_
-void
-ad_account_info_handler(struct be_req *breq);
+struct tevent_req *
+ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params);
+
+errno_t ad_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data);
struct tevent_req *
ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
- struct be_req *breq,
struct be_acct_req *ar,
struct sdap_id_ctx *ctx,
struct ad_options *ad_options,
@@ -48,6 +54,4 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
errno_t
ad_enumeration_recv(struct tevent_req *req);
-void
-ad_check_online(struct be_req *be_req);
#endif /* AD_ID_H_ */
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index 905338135..3a2ec1c7d 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -42,30 +42,10 @@
#include "providers/ad/ad_subdomains.h"
#include "providers/ad/ad_domain_info.h"
-struct ad_options *ad_options = NULL;
-
-static void
-ad_shutdown(struct be_req *req);
-
-struct bet_ops ad_id_ops = {
- .handler = ad_account_info_handler,
- .finalize = ad_shutdown,
- .check_online = ad_check_online
-};
-
-struct bet_ops ad_auth_ops = {
- .handler = krb5_pam_handler,
- .finalize = NULL
-};
-
-struct bet_ops ad_chpass_ops = {
- .handler = krb5_pam_handler,
- .finalize = NULL
-};
-
-struct bet_ops ad_access_ops = {
- .handler = ad_access_handler,
- .finalize = NULL
+struct ad_init_ctx {
+ struct ad_options *options;
+ struct ad_id_ctx *id_ctx;
+ struct krb5_ctx *auth_ctx;
};
#define AD_COMPAT_ON "1"
@@ -119,7 +99,7 @@ static int map_sasl2sssd_log_level(int sasl_level)
return sssd_level;
}
-int ad_sasl_log(void *context, int level, const char *message)
+static int ad_sasl_log(void *context, int level, const char *message)
{
int sssd_level;
@@ -137,6 +117,7 @@ static const sasl_callback_t ad_sasl_callbacks[] = {
{ SASL_CB_LOG, (sss_sasl_gen_cb_fn)ad_sasl_log, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
+
/* This is quite a hack, we *try* to fool openldap libraries by initializing
* sasl first so we can pass in the SASL_CB_GETOPT callback we need to set some
* options. Should be removed as soon as openldap exposes a way to do that */
@@ -149,26 +130,25 @@ static void ad_sasl_initialize(void)
(void)sasl_client_init(ad_sasl_callbacks);
}
-static errno_t
-common_ad_init(struct be_ctx *bectx)
+static errno_t ad_init_options(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_options **_ad_options)
{
- errno_t ret;
+ struct ad_options *ad_options;
char *ad_servers = NULL;
char *ad_backup_servers = NULL;
char *ad_realm;
+ errno_t ret;
ad_sasl_initialize();
/* Get AD-specific options */
- ret = ad_get_common_options(bectx, bectx->cdb,
- bectx->conf_path,
- bectx->domain,
- &ad_options);
+ ret = ad_get_common_options(mem_ctx, be_ctx->cdb, be_ctx->conf_path,
+ be_ctx->domain, &ad_options);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not parse common options: [%s]\n",
- strerror(ret));
- goto done;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not parse common options "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
}
ad_servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
@@ -176,180 +156,165 @@ common_ad_init(struct be_ctx *bectx)
ad_realm = dp_opt_get_string(ad_options->basic, AD_KRB5_REALM);
/* Set up the failover service */
- ret = ad_failover_init(ad_options, bectx, ad_servers, ad_backup_servers, ad_realm,
- AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
+ ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
+ ad_realm, AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
dp_opt_get_string(ad_options->basic, AD_DOMAIN),
&ad_options->service);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to init AD failover service: [%s]\n",
- strerror(ret));
- goto done;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init AD failover service: "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ talloc_free(ad_options);
+ return ret;
}
- ret = EOK;
-done:
- return ret;
+ *_ad_options = ad_options;
+
+ return EOK;
}
-int
-sssm_ad_id_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
+ struct ad_options *ad_options)
{
- errno_t ret;
- struct ad_id_ctx *ad_ctx;
+ struct ad_srv_plugin_ctx *srv_ctx;
const char *hostname;
const char *ad_domain;
const char *ad_site_override;
- struct ad_srv_plugin_ctx *srv_ctx;
+ bool sites_enabled;
+ errno_t ret;
- if (!ad_options) {
- ret = common_ad_init(bectx);
+ hostname = dp_opt_get_string(ad_options->basic, AD_HOSTNAME);
+ ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
+ ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
+ sites_enabled = dp_opt_get_bool(ad_options->basic, AD_ENABLE_DNS_SITES);
+
+
+ if (!sites_enabled) {
+ ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, hostname);
if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
+ "[%d]: %s\n", ret, sss_strerror(ret));
return ret;
}
- }
- if (ad_options->id_ctx) {
- /* already initialized */
- *ops = &ad_id_ops;
- *pvt_data = ad_options->id_ctx;
return EOK;
}
-
- ad_ctx = ad_id_ctx_init(ad_options, bectx);
- if (ad_ctx == NULL) {
+ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
+ default_host_dbs, ad_options->id,
+ hostname, ad_domain,
+ ad_site_override);
+ if (srv_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
return ENOMEM;
}
- ad_options->id_ctx = ad_ctx;
- ret = ad_dyndns_init(ad_ctx->sdap_id_ctx->be, ad_options);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failure setting up automatic DNS update\n");
- /* Continue without DNS updates */
- }
+ be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send,
+ ad_srv_plugin_recv, srv_ctx, "AD");
- ret = sdap_setup_child();
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "setup_child failed [%d][%s].\n",
- ret, strerror(ret));
- goto done;
- }
+ return EOK;
+}
- /* Set up various SDAP options */
- ret = ad_get_id_options(ad_options, bectx->cdb,
- bectx->conf_path,
- &ad_ctx->sdap_id_ctx->opts);
- if (ret != EOK) {
- goto done;
- }
+static errno_t ad_init_sdap_access_ctx(struct ad_access_ctx *access_ctx)
+{
+ struct dp_option *options = access_ctx->ad_options;
+ struct sdap_id_ctx *sdap_id_ctx = access_ctx->ad_id_ctx->sdap_id_ctx;
+ struct sdap_access_ctx *sdap_access_ctx;
+ const char *filter;
- ret = sdap_id_setup_tasks(bectx,
- ad_ctx->sdap_id_ctx,
- ad_ctx->sdap_id_ctx->opts->sdom,
- ad_enumeration_send,
- ad_enumeration_recv,
- ad_ctx);
- if (ret != EOK) {
- goto done;
+ sdap_access_ctx = talloc_zero(access_ctx, struct sdap_access_ctx);
+ if (sdap_access_ctx == NULL) {
+ return ENOMEM;
}
- ad_ctx->sdap_id_ctx->opts->sdom->pvt = ad_ctx;
+ sdap_access_ctx->id_ctx = sdap_id_ctx;
- /* Set up the ID mapping object */
- ret = sdap_idmap_init(ad_ctx->sdap_id_ctx, ad_ctx->sdap_id_ctx,
- &ad_ctx->sdap_id_ctx->opts->idmap_ctx);
- if (ret != EOK) goto done;
- ret = setup_tls_config(ad_ctx->sdap_id_ctx->opts->basic);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "setup_tls_config failed [%s]\n", strerror(ret));
- goto done;
- }
-
- /* setup SRV lookup plugin */
- hostname = dp_opt_get_string(ad_options->basic, AD_HOSTNAME);
- if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_DNS_SITES)) {
- /* use AD plugin */
- ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
- ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
-
- srv_ctx = ad_srv_plugin_ctx_init(bectx, bectx->be_res,
- default_host_dbs, ad_options->id,
- hostname, ad_domain,
- ad_site_override);
- if (srv_ctx == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
- ret = ENOMEM;
- goto done;
+ /* If ad_access_filter is set, the value of ldap_acess_order is
+ * expire, filter, otherwise only expire.
+ */
+ sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
+ filter = dp_opt_get_cstring(options, AD_ACCESS_FILTER);
+ if (filter != NULL) {
+ /* The processing of the extended filter is performed during the access
+ * check itself.
+ */
+ sdap_access_ctx->filter = talloc_strdup(sdap_access_ctx, filter);
+ if (sdap_access_ctx->filter == NULL) {
+ talloc_free(sdap_access_ctx);
+ return ENOMEM;
}
- be_fo_set_srv_lookup_plugin(bectx, ad_srv_plugin_send,
- ad_srv_plugin_recv, srv_ctx, "AD");
+ sdap_access_ctx->access_rule[1] = LDAP_ACCESS_FILTER;
+ sdap_access_ctx->access_rule[2] = LDAP_ACCESS_EMPTY;
} else {
- /* fall back to standard plugin */
- ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
- "[%d]: %s\n", ret, strerror(ret));
- goto done;
- }
+ sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
}
- /* setup periodical refresh of expired records */
- ret = sdap_refresh_init(bectx->refresh_ctx, ad_ctx->sdap_id_ctx);
- if (ret != EOK && ret != EEXIST) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
- "will not work [%d]: %s\n", ret, strerror(ret));
+ access_ctx->sdap_access_ctx = sdap_access_ctx;
+
+ return EOK;
+}
+
+errno_t ad_gpo_parse_map_options(struct ad_access_ctx *access_ctx);
+
+static errno_t ad_init_gpo(struct ad_access_ctx *access_ctx)
+{
+ struct dp_option *options;
+ const char *gpo_access_control_mode;
+ int gpo_cache_timeout;
+ errno_t ret;
+
+ options = access_ctx->ad_options;
+
+ /* GPO access control mode */
+ gpo_access_control_mode = dp_opt_get_string(options, AD_GPO_ACCESS_CONTROL);
+ if (gpo_access_control_mode == NULL) {
+ return EINVAL;
+ } else if (strcasecmp(gpo_access_control_mode, "disabled") == 0) {
+ access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_DISABLED;
+ } else if (strcasecmp(gpo_access_control_mode, "permissive") == 0) {
+ access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_PERMISSIVE;
+ } else if (strcasecmp(gpo_access_control_mode, "enforcing") == 0) {
+ access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_ENFORCING;
+ } else {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized GPO access control mode: "
+ "%s\n", gpo_access_control_mode);
+ return EINVAL;
}
- ret = ad_machine_account_password_renewal_init(bectx, ad_options);
+ /* GPO cache timeout */
+ gpo_cache_timeout = dp_opt_get_int(options, AD_GPO_CACHE_TIMEOUT);
+ access_ctx->gpo_cache_timeout = gpo_cache_timeout;
+
+ /* GPO logon maps */
+ ret = sss_hash_create(access_ctx, 10, &access_ctx->gpo_map_options_table);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot setup task for machine account "
- "password renewal.\n");
- goto done;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create gpo_map_options "
+ "hash table [%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
}
- *ops = &ad_id_ops;
- *pvt_data = ad_ctx;
-
- ret = EOK;
-done:
+ ret = ad_gpo_parse_map_options(access_ctx);
if (ret != EOK) {
- talloc_zfree(ad_options->id_ctx);
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not parse gpo_map_options "
+ "(invalid config) [%d]: %s\n", ret, sss_strerror(ret));
+ talloc_zfree(access_ctx->gpo_map_options_table);
+ return ret;
}
- return ret;
+
+ return EOK;
}
-int
-sssm_ad_auth_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+static errno_t ad_init_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_options *ad_options,
+ struct krb5_ctx **_auth_ctx)
{
+ struct krb5_ctx *krb5_auth_ctx;
errno_t ret;
- struct krb5_ctx *krb5_auth_ctx = NULL;
-
- if (!ad_options) {
- ret = common_ad_init(bectx);
- if (ret != EOK) {
- return ret;
- }
- }
-
- if (ad_options->auth_ctx) {
- /* Already initialized */
- *ops = &ad_auth_ops;
- *pvt_data = ad_options->auth_ctx;
- return EOK;
- }
- krb5_auth_ctx = talloc_zero(NULL, struct krb5_ctx);
- if (!krb5_auth_ctx) {
+ krb5_auth_ctx = talloc_zero(mem_ctx, struct krb5_ctx);
+ if (krb5_auth_ctx == NULL) {
ret = ENOMEM;
goto done;
}
@@ -357,257 +322,324 @@ sssm_ad_auth_init(struct be_ctx *bectx,
krb5_auth_ctx->config_type = K5C_GENERIC;
krb5_auth_ctx->service = ad_options->service->krb5_service;
- ret = ad_get_auth_options(krb5_auth_ctx, ad_options, bectx,
+ ret = ad_get_auth_options(krb5_auth_ctx, ad_options, be_ctx,
&krb5_auth_ctx->opts);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not determine Kerberos options\n");
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not determine Kerberos options\n");
goto done;
}
- ret = krb5_child_init(krb5_auth_ctx, bectx);
+ ret = krb5_child_init(krb5_auth_ctx, be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not initialize krb5_child settings: [%s]\n",
- strerror(ret));
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize krb5_child settings: "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- ad_options->auth_ctx = talloc_steal(ad_options, krb5_auth_ctx);
- *ops = &ad_auth_ops;
- *pvt_data = ad_options->auth_ctx;
+ ad_options->auth_ctx = krb5_auth_ctx;
+ *_auth_ctx = krb5_auth_ctx;
+
+ ret = EOK;
done:
if (ret != EOK) {
talloc_free(krb5_auth_ctx);
}
+
return ret;
}
-int
-sssm_ad_chpass_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+static errno_t ad_init_misc(struct be_ctx *be_ctx,
+ struct ad_options *ad_options,
+ struct ad_id_ctx *ad_id_ctx,
+ struct sdap_id_ctx *sdap_id_ctx)
{
errno_t ret;
- if (!ad_options) {
- ret = common_ad_init(bectx);
- if (ret != EOK) {
- return ret;
- }
+ ret = ad_dyndns_init(be_ctx, ad_options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failure setting up automatic DNS update\n");
+ /* Continue without DNS updates */
}
- if (ad_options->auth_ctx) {
- /* Already initialized */
- *ops = &ad_chpass_ops;
- *pvt_data = ad_options->auth_ctx;
- return EOK;
+ ret = setup_tls_config(sdap_id_ctx->opts->basic);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get TLS options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- ret = sssm_ad_auth_init(bectx, ops, pvt_data);
- *ops = &ad_chpass_ops;
- ad_options->auth_ctx = *pvt_data;
- return ret;
-}
-
-/* GPO parsing of PAM service names to Windows Logon Rights*/
-errno_t ad_gpo_parse_map_options(struct ad_access_ctx *access_ctx);
+ ret = sdap_idmap_init(sdap_id_ctx, sdap_id_ctx,
+ &sdap_id_ctx->opts->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;
+ }
-int
-sssm_ad_access_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
-{
- errno_t ret;
- struct ad_access_ctx *access_ctx;
- struct ad_id_ctx *ad_id_ctx;
- const char *filter;
- const char *gpo_access_control_mode;
- int gpo_cache_timeout;
+ ret = sdap_id_setup_tasks(be_ctx, sdap_id_ctx, sdap_id_ctx->opts->sdom,
+ ad_enumeration_send, ad_enumeration_recv,
+ ad_id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup background tasks "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
- access_ctx = talloc_zero(bectx, struct ad_access_ctx);
- if (!access_ctx) return ENOMEM;
+ sdap_id_ctx->opts->sdom->pvt = ad_id_ctx;
- ret = sssm_ad_id_init(bectx, ops, (void **)&ad_id_ctx);
+ ret = sdap_setup_child();
if (ret != EOK) {
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_setup_child() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- access_ctx->ad_id_ctx = ad_id_ctx;
- ret = dp_copy_options(access_ctx, ad_options->basic, AD_OPTS_BASIC,
- &access_ctx->ad_options);
+ ret = ad_init_srv_plugin(be_ctx, ad_options);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not initialize access provider options: [%s]\n",
- strerror(ret));
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup SRV plugin [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- /* Set up an sdap_access_ctx for checking expired/locked accounts */
- access_ctx->sdap_access_ctx =
- talloc_zero(access_ctx, struct sdap_access_ctx);
- if (!access_ctx->sdap_access_ctx) {
- ret = ENOMEM;
- goto fail;
+ ret = sdap_refresh_init(be_ctx->refresh_ctx, sdap_id_ctx);
+ if (ret != EOK && ret != EEXIST) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+ "will not work [%d]: %s\n", ret, sss_strerror(ret));
}
- access_ctx->sdap_access_ctx->id_ctx = ad_id_ctx->sdap_id_ctx;
- /* If ad_access_filter is set, the value of ldap_acess_order is
- * expire, filter, otherwise only expire
- */
- access_ctx->sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
- filter = dp_opt_get_cstring(access_ctx->ad_options, AD_ACCESS_FILTER);
- if (filter != NULL) {
- /* The processing of the extended filter is performed during the access
- * check itself
- */
- access_ctx->sdap_access_ctx->filter = talloc_strdup(
- access_ctx->sdap_access_ctx,
- filter);
- if (access_ctx->sdap_access_ctx->filter == NULL) {
- ret = ENOMEM;
- goto fail;
- }
+ ret = ad_machine_account_password_renewal_init(be_ctx, ad_options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot setup task for machine account "
+ "password renewal.\n");
+ return ret;
+ }
- access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_FILTER;
- access_ctx->sdap_access_ctx->access_rule[2] = LDAP_ACCESS_EMPTY;
- } else {
- access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
+ return EOK;
+}
+
+errno_t sssm_ad_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct data_provider *provider,
+ const char *module_name,
+ void **_module_data)
+{
+ struct ad_init_ctx *init_ctx;
+ errno_t ret;
+
+ init_ctx = talloc_zero(mem_ctx, struct ad_init_ctx);
+ if (init_ctx == NULL) {
+ return ENOMEM;
}
- /* GPO access control mode */
- gpo_access_control_mode =
- dp_opt_get_string(access_ctx->ad_options, AD_GPO_ACCESS_CONTROL);
- if (strcasecmp(gpo_access_control_mode, "disabled") == 0) {
- access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_DISABLED;
- } else if (strcasecmp(gpo_access_control_mode, "permissive") == 0) {
- access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_PERMISSIVE;
- } else if (strcasecmp(gpo_access_control_mode, "enforcing") == 0) {
- access_ctx->gpo_access_control_mode = GPO_ACCESS_CONTROL_ENFORCING;
- } else {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Unrecognized GPO access control mode: %s\n",
- gpo_access_control_mode);
- ret = EINVAL;
- goto fail;
+ /* Always initialize options since it is needed everywhere. */
+ ret = ad_init_options(mem_ctx, be_ctx, &init_ctx->options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init AD options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- /* GPO cache timeout */
- gpo_cache_timeout =
- dp_opt_get_int(access_ctx->ad_options, AD_GPO_CACHE_TIMEOUT);
- access_ctx->gpo_cache_timeout = gpo_cache_timeout;
+ /* Always initialize id_ctx since it is needed everywhere. */
+ init_ctx->id_ctx = ad_id_ctx_init(init_ctx->options, be_ctx);
+ if (init_ctx->id_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize AD ID context\n");
+ ret = ENOMEM;
+ goto done;
+ }
- /* GPO logon maps */
+ init_ctx->options->id_ctx = init_ctx->id_ctx;
- ret = sss_hash_create(access_ctx, 10, &access_ctx->gpo_map_options_table);
+ ret = ad_get_id_options(init_ctx->options, be_ctx->cdb, be_ctx->conf_path,
+ &init_ctx->id_ctx->sdap_id_ctx->opts);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not create gpo_map_options hash table: [%s]\n",
- strerror(ret));
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init AD id options\n");
+ return ret;
}
- ret = ad_gpo_parse_map_options(access_ctx);
+ /* Setup miscellaneous things. */
+ ret = ad_init_misc(be_ctx, init_ctx->options, init_ctx->id_ctx,
+ init_ctx->id_ctx->sdap_id_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not parse gpo_map_options (invalid config): [%s]\n",
- strerror(ret));
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init AD module "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- *ops = &ad_access_ops;
- *pvt_data = access_ctx;
+ /* Initialize auth_ctx only if one of the target is enabled. */
+ if (dp_target_enabled(provider, module_name, DPT_AUTH, DPT_CHPASS)) {
+ ret = ad_init_auth_ctx(init_ctx, be_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;
+ }
+ }
- return EOK;
+ *_module_data = init_ctx;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(init_ctx);
+ }
-fail:
- talloc_free(access_ctx);
return ret;
}
-static void
-ad_shutdown(struct be_req *req)
+errno_t sssm_ad_id_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);
+ struct ad_init_ctx *init_ctx;
+ struct ad_id_ctx *id_ctx;
+
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
+ id_ctx = init_ctx->id_ctx;
+
+ dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER,
+ ad_account_info_handler_send, ad_account_info_handler_recv, id_ctx,
+ struct ad_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->sdap_id_ctx,
+ struct sdap_id_ctx, void, struct dp_reply_std);
+
+ return EOK;
}
-int sssm_ad_subdomains_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ad_auth_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- struct ad_id_ctx *id_ctx;
- const char *ad_domain;
+ struct ad_init_ctx *init_ctx;
+ struct krb5_ctx *auth_ctx;
- ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ad_id_init failed.\n");
- return ret;
- }
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
+ auth_ctx = init_ctx->auth_ctx;
- if (ad_options == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Global AD options not available.\n");
- return EINVAL;
+ dp_set_method(dp_methods, DPM_AUTH_HANDLER,
+ krb5_pam_handler_send, krb5_pam_handler_recv, auth_ctx,
+ struct krb5_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
+}
+
+errno_t sssm_ad_chpass_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ return sssm_ad_auth_init(mem_ctx, be_ctx, module_data, dp_methods);
+}
+
+errno_t sssm_ad_access_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ struct ad_init_ctx *init_ctx;
+ struct ad_access_ctx *access_ctx;
+ errno_t ret;
+
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
+
+ access_ctx = talloc_zero(mem_ctx, struct ad_access_ctx);
+ if (access_ctx == NULL) {
+ return ENOMEM;
}
- ad_domain = dp_opt_get_cstring(ad_options->basic, AD_DOMAIN);
+ access_ctx->ad_id_ctx = init_ctx->id_ctx;
- ret = ad_subdom_init(bectx, id_ctx, ad_domain, ops, pvt_data);
+ ret = dp_copy_options(access_ctx, init_ctx->options->basic, AD_OPTS_BASIC,
+ &access_ctx->ad_options);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "ad_subdom_init failed.\n");
- return ret;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize access provider "
+ "options [%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- return EOK;
-}
+ ret = ad_init_sdap_access_ctx(access_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize sdap access context "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+ ret = ad_init_gpo(access_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize GPO "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
-int sssm_ad_sudo_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
-{
-#ifdef BUILD_SUDO
- struct ad_id_ctx *id_ctx;
- int ret;
+ dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+ ad_pam_access_handler_send, ad_pam_access_handler_recv, access_ctx,
+ struct ad_access_ctx, struct pam_data, struct pam_data *);
- DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing AD sudo handler\n");
+ ret = EOK;
- ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
+done:
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ad_id_init failed.\n");
- return ret;
+ talloc_free(access_ctx);
}
- return ad_sudo_init(bectx, 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
+ return ret;
}
-int sssm_ad_autofs_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ad_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
#ifdef BUILD_AUTOFS
- struct ad_id_ctx *id_ctx;
- int ret;
+ struct ad_init_ctx *init_ctx;
DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing AD autofs handler\n");
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
- ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ad_id_init failed.\n");
- return ret;
- }
-
- return ad_autofs_init(bectx, id_ctx, ops, pvt_data);
+ return ad_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");
return EOK;
#endif
}
+
+errno_t sssm_ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ struct ad_init_ctx *init_ctx;
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing AD subdomains handler\n");
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
+
+ return ad_subdomains_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods);
+}
+
+errno_t sssm_ad_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+#ifdef BUILD_SUDO
+ struct ad_init_ctx *init_ctx;
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing AD sudo handler\n");
+ init_ctx = talloc_get_type(module_data, struct ad_init_ctx);
+
+ return ad_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/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 1aee92cab..5b0bee866 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -29,6 +29,7 @@
#include "providers/ad/ad_common.h"
#include "providers/ldap/sdap_idmap.h"
+#include "providers/ldap/sdap_ops.h"
#include "util/util_sss_idmap.h"
#include <ctype.h>
#include <ndr.h>
@@ -56,42 +57,6 @@
/* do not refresh more often than every 5 seconds for now */
#define AD_SUBDOMAIN_REFRESH_LIMIT 5
-struct ad_subdomains_ctx {
- struct be_ctx *be_ctx;
- struct sdap_id_ctx *sdap_id_ctx;
- struct sdap_domain *sdom;
- struct sdap_id_conn_ctx *ldap_ctx;
- struct sss_idmap_ctx *idmap_ctx;
- char *domain_name;
-
- time_t last_refreshed;
- struct tevent_timer *timer_event;
- struct ad_id_ctx *ad_id_ctx;
-};
-
-struct ad_subdomains_req_ctx {
- struct be_req *be_req;
- struct ad_subdomains_ctx *sd_ctx;
- struct sdap_id_op *sdap_op;
-
- char *current_filter;
- size_t base_iter;
-
- struct ad_id_ctx *root_id_ctx;
- struct sdap_id_op *root_op;
- size_t root_base_iter;
- struct sysdb_attrs *root_domain_attrs;
- struct sss_domain_info *root_domain;
-
- size_t reply_count;
- struct sysdb_attrs **reply;
-
- char *master_sid;
- char *flat_name;
- char *site;
- char *forest;
-};
-
static errno_t
ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
struct ad_id_ctx *id_ctx,
@@ -119,8 +84,8 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
return EINVAL;
}
- ad_options = ad_create_2way_trust_options(id_ctx, realm,
- ad_domain, hostname, keytab);
+ ad_options = ad_create_2way_trust_options(id_ctx, realm, ad_domain,
+ hostname, keytab);
if (ad_options == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
talloc_free(ad_options);
@@ -192,34 +157,16 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
return EOK;
}
-static errno_t
-ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
- struct sss_domain_info *parent)
-{
- int ret;
- struct sdap_domain *sditer;
- struct ad_id_ctx *subdom_id_ctx;
-
- ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
- return ret;
- }
+struct ad_subdomains_ctx {
+ struct be_ctx *be_ctx;
+ struct ad_id_ctx *ad_id_ctx;
+ struct sdap_id_ctx *sdap_id_ctx;
- DLIST_FOR_EACH(sditer, ctx->sdom) {
- if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
- ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
- sditer->dom, &subdom_id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
- } else {
- sditer->pvt = subdom_id_ctx;
- }
- }
- }
+ struct sdap_domain *sdom;
+ char *domain_name;
- return EOK;
-}
+ time_t last_refreshed;
+};
static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
struct sysdb_attrs *attrs,
@@ -239,7 +186,7 @@ static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
}
static errno_t
-ad_subdom_store(struct ad_subdomains_ctx *ctx,
+ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
struct sss_domain_info *domain,
struct sysdb_attrs *subdom_attrs,
bool enumerate)
@@ -293,10 +240,8 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
goto done;
}
- err = sss_idmap_bin_sid_to_sid(ctx->idmap_ctx,
- el->values[0].data,
- el->values[0].length,
- &sid_str);
+ err = sss_idmap_bin_sid_to_sid(idmap_ctx->map, el->values[0].data,
+ el->values[0].length, &sid_str);
if (err != IDMAP_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not convert SID: [%s].\n", idmap_error_string(err));
@@ -304,10 +249,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
goto done;
}
- mpg = sdap_idmap_domain_has_algorithmic_mapping(
- ctx->sdap_id_ctx->opts->idmap_ctx,
- name,
- sid_str);
+ mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str);
ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
mpg, enumerate, domain->forest, 0);
@@ -318,32 +260,37 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
ret = EOK;
done:
- sss_idmap_free_sid(ctx->sdap_id_ctx->opts->idmap_ctx->map, sid_str);
+ sss_idmap_free_sid(idmap_ctx->map, sid_str);
talloc_free(tmp_ctx);
return ret;
}
-static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
- int count, bool root_domain,
- struct sysdb_attrs **reply,
- bool *changes)
+static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
+ struct sdap_idmap_ctx *idmap_ctx,
+ struct sdap_options *opts,
+ struct sysdb_attrs **subdomains,
+ size_t num_subdomains,
+ bool root_domain,
+ time_t *_last_refreshed,
+ bool *_changes)
{
struct sdap_domain *sdom;
- struct sss_domain_info *domain, *dom;
- bool handled[count];
+ struct sss_domain_info *domain;
+ struct sss_domain_info *dom;
+ bool handled[num_subdomains];
const char *value;
const char *root_name = NULL;
- int c, h;
+ size_t c, h;
int ret;
bool enumerate;
- domain = ctx->be_ctx->domain;
- memset(handled, 0, sizeof(bool) * count);
+ domain = be_ctx->domain;
+ memset(handled, 0, sizeof(bool) * num_subdomains);
h = 0;
if (root_domain) {
- ret = sysdb_attrs_get_string(reply[0], AD_AT_TRUST_PARTNER,
+ ret = sysdb_attrs_get_string(subdomains[0], AD_AT_TRUST_PARTNER,
&root_name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
@@ -363,11 +310,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
continue;
}
- for (c = 0; c < count; c++) {
+ for (c = 0; c < num_subdomains; c++) {
if (handled[c]) {
continue;
}
- ret = sysdb_attrs_get_string(reply[c], AD_AT_TRUST_PARTNER, &value);
+ ret = sysdb_attrs_get_string(subdomains[c], AD_AT_TRUST_PARTNER,
+ &value);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
goto done;
@@ -377,7 +325,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
}
}
- if (c >= count) {
+ if (c >= num_subdomains) {
/* ok this subdomain does not exist anymore, let's clean up */
sss_domain_set_state(dom, DOM_DISABLED);
ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
@@ -385,29 +333,29 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
goto done;
}
- sdom = sdap_domain_get(ctx->sdap_id_ctx->opts, dom);
+ sdom = sdap_domain_get(opts, dom);
if (sdom == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Domain does not exist?\n");
continue;
}
/* Remove the subdomain from the list of LDAP domains */
- sdap_domain_remove(ctx->sdap_id_ctx->opts, dom);
+ sdap_domain_remove(opts, dom);
be_ptask_destroy(&sdom->enum_task);
be_ptask_destroy(&sdom->cleanup_task);
/* terminate all requests for this subdomain so we can free it */
- be_terminate_domain_requests(ctx->be_ctx, dom->name);
+ dp_terminate_domain_requests(be_ctx->provider, dom->name);
talloc_zfree(sdom);
} else {
/* ok let's try to update it */
- ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+ ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
if (ret != EOK) {
goto done;
}
- ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
+ ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
if (ret) {
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains
@@ -420,29 +368,29 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
}
}
- if (count == h) {
+ if (num_subdomains == h) {
/* all domains were already accounted for and have been updated */
ret = EOK;
- *changes = false;
+ *_changes = false;
goto done;
}
/* if we get here it means we have changes to the subdomains list */
- *changes = true;
+ *_changes = true;
- for (c = 0; c < count; c++) {
+ for (c = 0; c < num_subdomains; c++) {
if (handled[c]) {
continue;
}
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains.
*/
- ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+ ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
if (ret != EOK) {
goto done;
}
- ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
+ ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
if (ret) {
DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
"will try to use cached subdomain\n");
@@ -453,39 +401,132 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
done:
if (ret != EOK) {
- ctx->last_refreshed = 0;
+ *_last_refreshed = 0;
} else {
- ctx->last_refreshed = time(NULL);
+ *_last_refreshed = time(NULL);
}
return ret;
}
-static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
+static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ size_t nsd, struct sysdb_attrs **sd,
+ struct sysdb_attrs *root,
+ size_t *_nsd_out,
+ struct sysdb_attrs ***_sd_out)
{
+ size_t i, sdi;
+ struct sysdb_attrs **sd_out;
+ const char *sd_name;
errno_t ret;
- ret = sss_write_krb5_conf_snippet(
- dp_opt_get_string(ctx->ad_id_ctx->ad_options->basic,
- AD_KRB5_CONFD_PATH));
+ if (root == NULL) {
+ /* We are connected directly to the root domain. The 'sd'
+ * list is complete and we can just use it
+ */
+ *_nsd_out = nsd;
+ *_sd_out = sd;
+ return EOK;
+ }
+
+ /* If we searched for root separately, we must:
+ * a) treat the root domain as a subdomain
+ * b) filter the subdomain we are connected to from the subdomain
+ * list, from our point of view, it's the master domain
+ */
+ sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
+ if (sd_out == NULL) {
+ return ENOMEM;
+ }
+
+ sdi = 0;
+ for (i = 0; i < nsd; i++) {
+ ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto fail;
+ }
+
+ if (strcasecmp(sd_name, domain->name) == 0) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Not including primary domain %s in the subdomain list\n",
+ domain->name);
+ continue;
+ }
+
+ sd_out[sdi] = talloc_steal(sd_out, sd[i]);
+ sdi++;
+ }
+
+ /* Now include the root */
+ sd_out[sdi] = talloc_steal(sd_out, root);
+
+ *_nsd_out = sdi+1;
+ *_sd_out = sd_out;
+ return EOK;
+
+fail:
+ talloc_free(sd_out);
+ return ret;
+}
+
+static errno_t
+ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
+ struct sss_domain_info *parent)
+{
+ int ret;
+ struct sdap_domain *sditer;
+ struct ad_id_ctx *subdom_id_ctx;
+
+ ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
+ return ret;
+ }
+
+ DLIST_FOR_EACH(sditer, ctx->sdom) {
+ if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
+ ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
+ sditer->dom, &subdom_id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
+ } else {
+ sditer->pvt = subdom_id_ctx;
+ }
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx)
+{
+ const char *path;
+ errno_t ret;
+
+ path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic,
+ AD_KRB5_CONFD_PATH);
+
+ ret = sss_write_krb5_conf_snippet(path);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
/* Just continue */
}
- ret = sysdb_update_subdomains(ctx->be_ctx->domain);
+ ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
return ret;
}
- ret = sss_write_domain_mappings(ctx->be_ctx->domain);
+ ret = sss_write_domain_mappings(subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "sss_krb5_write_mappings failed.\n");
/* Just continue */
}
- ret = ads_store_sdap_subdom(ctx, ctx->be_ctx->domain);
+ ret = ads_store_sdap_subdom(subdoms_ctx, subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ads_store_sdap_subdom failed.\n");
return ret;
@@ -494,364 +535,260 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
return EOK;
}
-static void ad_subdomains_get_conn_done(struct tevent_req *req);
-static void ad_subdomains_master_dom_done(struct tevent_req *req);
-static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx);
-static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx);
+struct ad_get_slave_domain_state {
+ struct tevent_context *ev;
+ struct ad_subdomains_ctx *sd_ctx;
+ struct be_ctx *be_ctx;
+ struct sdap_options *opts;
+ struct sdap_idmap_ctx *idmap_ctx;
+ struct sysdb_attrs *root_attrs;
+ struct sdap_id_op *sdap_op;
+};
-static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
- struct be_req *be_req)
+static errno_t ad_get_slave_domain_retry(struct tevent_req *req);
+static void ad_get_slave_domain_connect_done(struct tevent_req *subreq);
+static void ad_get_slave_domain_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_get_slave_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_subdomains_ctx *sd_ctx,
+ struct sysdb_attrs *root_attrs,
+ struct ad_id_ctx *root_id_ctx)
{
- struct ad_subdomains_req_ctx *req_ctx = NULL;
+ struct ad_get_slave_domain_state *state;
struct tevent_req *req;
- int dp_error = DP_ERR_FATAL;
- int ret;
+ errno_t ret;
- req_ctx = talloc_zero(be_req, struct ad_subdomains_req_ctx);
- if (req_ctx == NULL) {
- ret = ENOMEM;
- goto done;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_get_slave_domain_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- req_ctx->be_req = be_req;
- req_ctx->sd_ctx = ctx;
- req_ctx->current_filter = NULL;
- req_ctx->base_iter = 0;
- req_ctx->root_base_iter = 0;
- req_ctx->root_id_ctx = NULL;
- req_ctx->root_op = NULL;
- req_ctx->root_domain = NULL;
- req_ctx->root_domain_attrs = NULL;
- req_ctx->reply_count = 0;
- req_ctx->reply = NULL;
-
- req_ctx->sdap_op = sdap_id_op_create(req_ctx,
- ctx->ldap_ctx->conn_cache);
- if (req_ctx->sdap_op == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
+ state->ev = ev;
+ state->sd_ctx = sd_ctx;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->opts = root_id_ctx->sdap_id_ctx->opts;
+ state->idmap_ctx = root_id_ctx->sdap_id_ctx->opts->idmap_ctx;
+ state->root_attrs = root_attrs;
+
+ state->sdap_op = sdap_id_op_create(state, root_id_ctx->ldap_ctx->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
ret = ENOMEM;
- goto done;
+ goto immediately;
}
- req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
- ret, strerror(ret));
- goto done;
+ ret = ad_get_slave_domain_retry(req);
+ if (ret == EAGAIN) {
+ /* asynchronous processing */
+ return req;
}
- tevent_req_set_callback(req, ad_subdomains_get_conn_done, req_ctx);
-
- return;
-
-done:
- talloc_free(req_ctx);
+immediately:
if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
- be_req_terminate(be_req, dp_error, ret, NULL);
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ad_subdomains_get_conn_done(struct tevent_req *req)
+static errno_t ad_get_slave_domain_retry(struct tevent_req *req)
{
+ struct ad_get_slave_domain_state *state;
+ struct tevent_req *subreq;
int ret;
- int dp_error = DP_ERR_FATAL;
- struct ad_subdomains_req_ctx *ctx;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- ret = sdap_id_op_connect_recv(req, &dp_error);
- talloc_zfree(req);
- if (ret) {
- if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to connect to AD server: [%d](%s)\n",
- ret, strerror(ret));
- }
-
- goto fail;
+ 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, sss_strerror(ret));
+ return ret;
}
- req = ad_master_domain_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->sd_ctx->ldap_ctx,
- ctx->sdap_op,
- ctx->sd_ctx->domain_name);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
- ret = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(req, ad_subdomains_master_dom_done, ctx);
- return;
+ tevent_req_set_callback(subreq, ad_get_slave_domain_connect_done, req);
-fail:
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+ return EAGAIN;
}
-static void ad_subdomains_master_dom_done(struct tevent_req *req)
+static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
{
- struct ad_subdomains_req_ctx *ctx;
+ struct ad_get_slave_domain_state *state;
+ struct tevent_req *req = NULL;
+ int dp_error;
errno_t ret;
- const char *realm;
+ const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
+ AD_AT_SID, AD_AT_TRUST_TYPE,
+ AD_AT_TRUST_ATTRS, NULL };
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
-
- ret = ad_master_domain_recv(req, ctx,
- &ctx->flat_name, &ctx->master_sid,
- &ctx->site, &ctx->forest);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
- goto done;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- realm = dp_opt_get_cstring(ctx->sd_ctx->ad_id_ctx->ad_options->basic,
- AD_KRB5_REALM);
- if (realm == NULL) {
- DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
- ret = EINVAL;
- goto done;
- }
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
- ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
- realm,
- ctx->flat_name, ctx->master_sid,
- ctx->forest);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n");
- goto done;
- }
-
- if (ctx->forest == NULL ||
- strcasecmp(ctx->sd_ctx->be_ctx->domain->name, ctx->forest) != 0) {
- DEBUG(SSSDBG_TRACE_FUNC,
- "SSSD needs to look up the forest root domain\n");
- ret = ad_subdomains_get_root(ctx);
- } else {
- DEBUG(SSSDBG_TRACE_FUNC,
- "Connected to forest root, looking up child domains..\n");
-
- ctx->root_op = ctx->sdap_op;
- ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-
- ret = ad_subdomains_get_slave(ctx);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ if (dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
+ "cannot get the subdomain list while offline\n");
+ ret = ERR_OFFLINE;
+ }
+ tevent_req_error(req, ret);
+ return;
}
- if (ret == EAGAIN) {
+ subreq = sdap_search_bases_send(state, state->ev, state->opts,
+ sdap_id_op_handle(state->sdap_op),
+ state->opts->sdom->search_bases,
+ NULL, false, 0,
+ SLAVE_DOMAIN_FILTER, attrs);
+ if (subreq == NULL) {
+ tevent_req_error(req, ret);
return;
- } else if (ret != EOK) {
- goto done;
}
-done:
- be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
+ tevent_req_set_callback(subreq, ad_get_slave_domain_done, req);
+ return;
}
-static void ad_subdomains_get_root_domain_done(struct tevent_req *req);
-
-static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx)
+static void ad_get_slave_domain_done(struct tevent_req *subreq)
{
+ struct ad_get_slave_domain_state *state;
struct tevent_req *req;
- struct sdap_search_base *base;
- struct sdap_id_ctx *sdap_id_ctx;
- char *filter;
- const char *forest_root_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
- AD_AT_SID, AD_AT_TRUST_TYPE,
- AD_AT_TRUST_ATTRS, NULL };
-
- sdap_id_ctx = ctx->sd_ctx->sdap_id_ctx;
- base = sdap_id_ctx->opts->sdom->search_bases[ctx->root_base_iter];
- if (base == NULL) {
- return EOK;
- }
-
- filter = talloc_asprintf(ctx, FOREST_ROOT_FILTER_FMT, ctx->forest);
- if (filter == NULL) {
- return ENOMEM;
- }
-
- req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
- sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->sdap_op),
- base->basedn, LDAP_SCOPE_SUBTREE,
- filter, forest_root_attrs,
- NULL, 0,
- dp_opt_get_int(sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT),
- false);
-
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
- }
-
- tevent_req_set_callback(req, ad_subdomains_get_root_domain_done, ctx);
- return EAGAIN;
-}
-
-static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx);
-static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx);
-static void ad_subdomains_root_conn_done(struct tevent_req *req);
-
-static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-{
- int ret;
+ struct sysdb_attrs **reply;
size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ad_subdomains_req_ctx *ctx;
- int dp_error = DP_ERR_FATAL;
- bool has_changes = false;
+ struct sysdb_attrs **subdoms;
+ size_t nsubdoms;
+ bool has_changes;
+ int dp_error;
+ errno_t ret;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
+ ret = sdap_search_bases_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup slave domain data "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ /* We continue to finish sdap_id_op. */
}
- if (reply_count == 0) {
- /* If no root domain was found in the default search base, try the
- * next one, if available
- */
- ctx->root_base_iter++;
- ret = ad_subdomains_get_root(ctx);
- if (ret == EAGAIN) {
- return;
- }
-
- goto fail;
- } else if (reply_count > 1) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Multiple results for root domain search, "
- "domain list might be incomplete!\n");
-
- ctx->root_op = ctx->sdap_op;
- ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-
- ret = ad_subdomains_get_slave(ctx);
- if (ret == EAGAIN) {
- return;
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ad_get_slave_domain_retry(req);
+ if (ret != EOK) {
+ goto done;
}
-
- goto fail;
+ return;
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ ret = ERR_OFFLINE;
+ goto done;
+ } else if (ret != EOK) {
+ goto done;
}
- /* Exactly one result, good. */
- /* We won't use the operation to the local LDAP anymore, but
- * read from the forest root
+ /* Based on whether we are connected to the forest root or not, we might
+ * need to exclude the subdomain we are connected to from the list of
+ * subdomains.
*/
- ret = sdap_id_op_done(ctx->sdap_op, ret, &dp_error);
+ ret = ad_subdomains_process(state, state->be_ctx->domain,
+ reply_count, reply, state->root_attrs,
+ &nsubdoms, &subdoms);
if (ret != EOK) {
- if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to search the AD server: [%d](%s)\n",
- ret, strerror(ret));
- }
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot process subdomain list\n");
+ tevent_req_error(req, ret);
+ return;
}
- ret = ad_subdomains_refresh(ctx->sd_ctx, 1, true, reply, &has_changes);
+ /* Got all the subdomains, let's process them. */
+ ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
+ subdoms, nsubdoms, false,
+ &state->sd_ctx->last_refreshed,
+ &has_changes);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed.\n");
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ goto done;
}
+ DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
+ has_changes ? "" : "no ");
+
if (has_changes) {
- ret = ad_subdom_reinit(ctx->sd_ctx);
+ ret = ad_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
- goto fail;
+ goto done;
}
}
- ctx->root_domain_attrs = reply[0];
- ctx->root_domain = ads_get_root_domain(ctx);
- if (ctx->root_domain == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
- ret = EFAULT;
- goto fail;
- }
-
- ctx->root_id_ctx = ads_get_root_id_ctx(ctx);
- if (ctx->root_id_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
- ret = EFAULT;
- goto fail;
- }
+ state->sd_ctx->last_refreshed = time(NULL);
+ ret = EOK;
- ctx->root_op = sdap_id_op_create(ctx,
- ctx->root_id_ctx->ldap_ctx->conn_cache);
- if (ctx->root_op == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
- ret = ENOMEM;
- goto fail;
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- req = sdap_id_op_connect_send(ctx->root_op, ctx, &ret);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
- ret, strerror(ret));
- goto fail;
- }
+ tevent_req_done(req);
+}
- tevent_req_set_callback(req, ad_subdomains_root_conn_done, ctx);
- return;
+static errno_t ad_get_slave_domain_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
-fail:
- if (ret == EOK) {
- ctx->sd_ctx->last_refreshed = time(NULL);
- dp_error = DP_ERR_OK;
- }
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+ return EOK;
}
-static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx)
+static struct sss_domain_info *
+ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
{
- errno_t ret;
- const char *name;
struct sss_domain_info *root;
+ const char *name;
+ errno_t ret;
- ret = sysdb_attrs_get_string(ctx->root_domain_attrs, AD_AT_TRUST_PARTNER, &name);
+ ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
return NULL;
}
/* With a subsequent run, the root should already be known */
- root = find_domain_by_name(ctx->sd_ctx->be_ctx->domain,
- name, false);
+ root = find_domain_by_name(be_ctx->domain, name, false);
return root;
}
-static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
+static struct ad_id_ctx *
+ads_get_root_id_ctx(struct be_ctx *be_ctx,
+ struct ad_id_ctx *ad_id_ctx,
+ struct sss_domain_info *root_domain,
+ struct sdap_options *opts)
{
errno_t ret;
struct sdap_domain *sdom;
struct ad_id_ctx *root_id_ctx;
- sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts,
- ctx->root_domain);
+ sdom = sdap_domain_get(opts, root_domain);
if (sdom == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
- "Cannot get the sdom for %s!\n", ctx->root_domain->name);
+ "Cannot get the sdom for %s!\n", root_domain->name);
return NULL;
}
if (sdom->pvt == NULL) {
- ret = ad_subdom_ad_ctx_new(ctx->sd_ctx->be_ctx,
- ctx->sd_ctx->ad_id_ctx,
- ctx->root_domain,
+ ret = ad_subdom_ad_ctx_new(be_ctx, ad_id_ctx, root_domain,
&root_id_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
@@ -867,362 +804,585 @@ static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
return root_id_ctx;
}
-static void ad_subdomains_root_conn_done(struct tevent_req *req)
-{
- int ret;
- int dp_error = DP_ERR_FATAL;
- struct ad_subdomains_req_ctx *ctx;
+struct ad_get_root_domain_state {
+ struct ad_subdomains_ctx *sd_ctx;
+ struct be_ctx *be_ctx;
+ struct sdap_idmap_ctx *idmap_ctx;
+ struct sdap_options *opts;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ struct ad_id_ctx *root_id_ctx;
+ struct sysdb_attrs *root_domain_attrs;
+};
- ret = sdap_id_op_connect_recv(req, &dp_error);
- talloc_zfree(req);
- if (ret) {
- be_mark_dom_offline(ctx->root_domain, be_req_get_be_ctx(ctx->be_req));
+static void ad_get_root_domain_done(struct tevent_req *subreq);
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to connect to AD server: [%d](%s)\n",
- ret, strerror(ret));
- goto fail;
+static struct tevent_req *
+ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *forest,
+ struct sdap_handle *sh,
+ struct ad_subdomains_ctx *sd_ctx)
+{
+ struct ad_get_root_domain_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ struct sdap_options *opts;
+ errno_t ret;
+ const char *filter;
+ const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
+ AD_AT_SID, AD_AT_TRUST_TYPE,
+ AD_AT_TRUST_ATTRS, NULL };
+
+ req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ret = ad_subdomains_get_slave(ctx);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto fail;
+ if (forest != NULL && strcasecmp(sd_ctx->be_ctx->domain->name, forest) == 0) {
+ state->root_id_ctx = sd_ctx->ad_id_ctx;
+ state->root_domain_attrs = NULL;
+ ret = EOK;
+ goto immediately;
}
-fail:
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
-}
+ DEBUG(SSSDBG_TRACE_FUNC, "Looking up the forest root domain.\n");
-static void ad_subdomains_get_slave_domain_done(struct tevent_req *req);
+ state->sd_ctx = sd_ctx;
+ state->opts = opts = sd_ctx->sdap_id_ctx->opts;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->idmap_ctx = opts->idmap_ctx;
-static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
-{
- struct tevent_req *req;
- struct sdap_search_base *base;
- const char *slave_dom_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
- AD_AT_SID, AD_AT_TRUST_TYPE,
- AD_AT_TRUST_ATTRS, NULL };
+ filter = talloc_asprintf(state, FOREST_ROOT_FILTER_FMT, forest);
+ if (filter == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
- base = ctx->root_id_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter];
- if (base == NULL) {
- return EOK;
+ subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
+ opts->sdom->search_bases,
+ NULL, false, 0, filter, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->root_id_ctx->sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->root_op),
- base->basedn, LDAP_SCOPE_SUBTREE,
- SLAVE_DOMAIN_FILTER, slave_dom_attrs,
- NULL, 0,
- dp_opt_get_int(ctx->root_id_ctx->sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT),
- false);
+ tevent_req_set_callback(subreq, ad_get_root_domain_done, req);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
+ tevent_req_post(req, ev);
- tevent_req_set_callback(req, ad_subdomains_get_slave_domain_done, ctx);
- return EAGAIN;
+ return req;
}
-static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- size_t nsd, struct sysdb_attrs **sd,
- struct sysdb_attrs *root,
- size_t *_nsd_out,
- struct sysdb_attrs ***_sd_out)
+static void ad_get_root_domain_done(struct tevent_req *subreq)
{
- size_t i, sdi;
- struct sysdb_attrs **sd_out;
- const char *sd_name;
+ struct tevent_req *req;
+ struct ad_get_root_domain_state *state;
+ struct sysdb_attrs **reply;
+ struct sss_domain_info *root_domain;
+ size_t reply_count;
+ bool has_changes;
errno_t ret;
- if (root == NULL) {
- /* We are connected directly to the root domain. The 'sd'
- * list is complete and we can just use it
- */
- *_nsd_out = nsd;
- *_sd_out = sd;
- return EOK;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_root_domain_state);
+
+ ret = sdap_search_bases_return_first_recv(subreq, state, &reply_count,
+ &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to lookup forest root information "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- /* If we searched for root separately, we must:
- * a) treat the root domain as a subdomain
- * b) filter the subdomain we are connected to from the subdomain
- * list, from our point of view, it's the master domain
- */
- sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
- if (sd_out == NULL) {
- return ENOMEM;
+ if (reply_count == 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "No information provided for root domain\n");
+ ret = ENOENT;
+ goto done;
+ } else if (reply_count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Multiple results for root domain search, "
+ "domain list might be incomplete!\n");
+ ret = ERR_MALFORMED_ENTRY;
+ goto done;
}
- sdi = 0;
- for (i = 0; i < nsd; i++) {
- ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
+ ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
+ reply, reply_count, true,
+ &state->sd_ctx->last_refreshed,
+ &has_changes);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (has_changes) {
+ ret = ad_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
+ goto done;
}
+ }
- if (strcasecmp(sd_name, domain->name) == 0) {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "Not including primary domain %s in the subdomain list\n",
- domain->name);
- continue;
- }
+ state->root_domain_attrs = reply[0];
+ root_domain = ads_get_root_domain(state->be_ctx, reply[0]);
+ if (root_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
+ ret = EFAULT;
+ goto done;
+ }
- sd_out[sdi] = talloc_steal(sd_out, sd[i]);
- sdi++;
+ state->root_id_ctx = ads_get_root_id_ctx(state->be_ctx,
+ state->sd_ctx->ad_id_ctx,
+ root_domain, state->opts);
+ if (state->root_id_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
+ ret = EFAULT;
+ goto done;
}
- /* Now include the root */
- sd_out[sdi] = talloc_steal(sd_out, root);
+ ret = EOK;
- *_nsd_out = sdi+1;
- *_sd_out = sd_out;
- return EOK;
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
-fail:
- talloc_free(sd_out);
- return ret;
+ tevent_req_done(req);
}
-static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
+static errno_t ad_get_root_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct sysdb_attrs **_attrs,
+ struct ad_id_ctx **_id_ctx)
{
- int ret;
- size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ad_subdomains_req_ctx *ctx;
- int dp_error = DP_ERR_FATAL;
- bool refresh_has_changes = false;
- size_t nsubdoms;
- struct sysdb_attrs **subdoms;
+ struct ad_get_root_domain_state *state = NULL;
+ state = tevent_req_data(req, struct ad_get_root_domain_state);
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto done;
+ *_attrs = talloc_steal(mem_ctx, state->root_domain_attrs);
+ *_id_ctx = state->root_id_ctx;
+
+ return EOK;
+}
+
+struct ad_subdomains_refresh_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct ad_subdomains_ctx *sd_ctx;
+ struct sdap_id_op *sdap_op;
+ struct sdap_id_ctx *id_ctx;
+ struct ad_options *ad_options;
+};
+
+static errno_t ad_subdomains_refresh_retry(struct tevent_req *req);
+static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_master_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_root_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_subdomains_ctx *sd_ctx)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_subdomains_refresh_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- if (reply_count) {
- ctx->reply = talloc_realloc(ctx, ctx->reply, struct sysdb_attrs *,
- ctx->reply_count + reply_count);
- if (ctx->reply == NULL) {
- ret = ENOMEM;
- goto done;
- }
- memcpy(ctx->reply+ctx->reply_count, reply,
- reply_count * sizeof(struct sysdb_attrs *));
- ctx->reply_count += reply_count;
+ state->ev = ev;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->sd_ctx = sd_ctx;
+ state->id_ctx = sd_ctx->sdap_id_ctx;
+ state->ad_options = sd_ctx->ad_id_ctx->ad_options;
+
+ state->sdap_op = sdap_id_op_create(state,
+ sd_ctx->sdap_id_ctx->conn->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
+ ret = ENOMEM;
+ goto immediately;
}
- ctx->base_iter++;
- ret = ad_subdomains_get_slave(ctx);
+ ret = ad_subdomains_refresh_retry(req);
if (ret == EAGAIN) {
- /* Search in progress */
- return;
+ /* asynchronous processing */
+ 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 ad_subdomains_refresh_retry(struct tevent_req *req)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct ad_subdomains_refresh_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, sss_strerror(ret));
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_connect_done, req);
+
+ return EAGAIN;
+}
+
+static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_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 ad_subdomains_refresh_state);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
- ret = sdap_id_op_done(ctx->root_op, ret, &dp_error);
if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
+ "[%d]: %s\n", ret, sss_strerror(ret));
if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to search the AD server: [%d](%s)\n",
- ret, strerror(ret));
+ DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
+ "cannot get the subdomain list while offline\n");
+ ret = ERR_OFFLINE;
}
tevent_req_error(req, ret);
return;
}
- /* Based on whether we are connected to the forest root or not, we might
- * need to exclude the subdomain we are connected to from the list of
- * subdomains
- */
- ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain,
- ctx->reply_count, ctx->reply,
- ctx->root_domain_attrs, &nsubdoms, &subdoms);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot process subdomain list\n");
- tevent_req_error(req, ret);
+ subreq = ad_master_domain_send(state, state->ev, state->id_ctx->conn,
+ state->sdap_op, state->sd_ctx->domain_name);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
return;
}
- /* Got all the subdomains, let's process them */
- ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, false, subdoms,
- &refresh_has_changes);
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_master_done, req);
+ return;
+}
+
+static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ const char *realm;
+ char *master_sid;
+ char *flat_name;
+ char *forest;
+ char *site;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+
+ ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid,
+ &site, &forest);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
- refresh_has_changes ? "" : "no ");
+ realm = dp_opt_get_cstring(state->ad_options->basic, AD_KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
+ ret = EINVAL;
+ goto done;
+ }
- if (refresh_has_changes) {
- ret = ad_subdom_reinit(ctx->sd_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
- goto done;
- }
+ ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm,
+ flat_name, master_sid, forest);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- ret = EOK;
+ subreq = ad_get_root_domain_send(state, state->ev, forest,
+ sdap_id_op_handle(state->sdap_op),
+ state->sd_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_root_done, req);
+ return;
+
done:
- if (ret == EOK) {
- ctx->sd_ctx->last_refreshed = time(NULL);
- dp_error = DP_ERR_OK;
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+
+ tevent_req_done(req);
}
-static void ad_subdom_online_cb(void *pvt);
+static void ad_subdomains_refresh_root_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ struct ad_id_ctx *root_id_ctx;
+ struct sysdb_attrs *root_attrs;
+ int dp_error;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+
+ ret = ad_get_root_domain_recv(state, subreq, &root_attrs, &root_id_ctx);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get forest root [%d]: %s\n",
+ ret, sss_strerror(ret));
+ root_attrs = NULL;
+ root_id_ctx = NULL;
+ /* We continue to finish sdap_id_op. */
+ }
+
+ /* We finish sdap_id_op here since we connect
+ * to forest root for slave domains. */
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ad_subdomains_refresh_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_error(req, ERR_OFFLINE);
+ return;
+ } else if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = ad_get_slave_domain_send(state, state->ev, state->sd_ctx,
+ root_attrs, root_id_ctx);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
-static void ad_subdom_timer_refresh(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_done, req);
+ return;
+}
+
+static void ad_subdomains_refresh_done(struct tevent_req *subreq)
{
- ad_subdom_online_cb(pvt);
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = ad_get_slave_domain_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n");
+ tevent_req_done(req);
}
-static void ad_subdom_be_req_callback(struct be_req *be_req,
- int dp_err, int dp_ret,
- const char *errstr)
+static errno_t ad_subdomains_refresh_recv(struct tevent_req *req)
{
- talloc_free(be_req);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
}
-static void ad_subdom_online_cb(void *pvt)
+struct ad_subdomains_handler_state {
+ struct dp_reply_std reply;
+};
+
+static void ad_subdomains_handler_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_subdomains_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_subdomains_ctx *sd_ctx,
+ struct dp_subdomains_data *data,
+ struct dp_req_params *params)
{
- struct ad_subdomains_ctx *ctx;
- struct be_req *be_req;
- struct timeval tv;
- uint32_t refresh_interval;
-
- ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
- if (!ctx) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
- return;
+ struct ad_subdomains_handler_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_subdomains_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- refresh_interval = ctx->be_ctx->domain->subdomain_refresh_interval;
- be_req = be_req_create(ctx, NULL, ctx->be_ctx, "AD subdomains",
- ad_subdom_be_req_callback, NULL);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_req_create() failed.\n");
- return;
+ if (sd_ctx->last_refreshed > time(NULL) - AD_SUBDOMAIN_REFRESH_LIMIT) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains were recently refreshed, "
+ "nothing to do\n");
+ ret = EOK;
+ goto immediately;
}
- ad_subdomains_retrieve(ctx, be_req);
-
- tv = tevent_timeval_current_ofs(refresh_interval, 0);
- ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
- ad_subdom_timer_refresh, ctx);
- if (!ctx->timer_event) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom timer event\n");
+ subreq = ad_subdomains_refresh_send(state, params->ev, sd_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
+
+ tevent_req_set_callback(subreq, ad_subdomains_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 ad_subdom_offline_cb(void *pvt)
+static void ad_subdomains_handler_done(struct tevent_req *subreq)
{
- struct ad_subdomains_ctx *ctx;
+ struct ad_subdomains_handler_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_handler_state);
- if (ctx) {
- talloc_zfree(ctx->timer_event);
- }
+ ret = ad_subdomains_refresh_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);
}
-void ad_subdomains_handler(struct be_req *be_req)
+static errno_t ad_subdomains_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ad_subdomains_ctx *ctx;
- time_t now;
-
- ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
- struct ad_subdomains_ctx);
- if (!ctx) {
- be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
- return;
- }
+ struct ad_subdomains_handler_state *state;
- now = time(NULL);
+ state = tevent_req_data(req, struct ad_subdomains_handler_state);
- if (ctx->last_refreshed > now - AD_SUBDOMAIN_REFRESH_LIMIT) {
- be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
- return;
- }
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
- ad_subdomains_retrieve(ctx, be_req);
+ return EOK;
}
-struct bet_ops ad_subdomains_ops = {
- .handler = ad_subdomains_handler,
- .finalize = NULL
-};
+static struct tevent_req *
+ad_subdomains_ptask_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct be_ptask *be_ptask,
+ void *pvt)
+{
+ struct ad_subdomains_ctx *sd_ctx;
+ sd_ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+
+ return ad_subdomains_refresh_send(mem_ctx, ev, sd_ctx);
+}
-int ad_subdom_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- const char *ad_domain,
- struct bet_ops **ops,
- void **pvt_data)
+static errno_t
+ad_subdomains_ptask_recv(struct tevent_req *req)
{
- struct ad_subdomains_ctx *ctx;
- int ret;
- enum idmap_error_code err;
+ return ad_subdomains_refresh_recv(req);
+}
+
+errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *ad_id_ctx,
+ struct dp_method *dp_methods)
+{
+ struct ad_subdomains_ctx *sd_ctx;
+ const char *ad_domain;
+ time_t period;
+ errno_t ret;
+
+ ad_domain = dp_opt_get_string(ad_id_ctx->ad_options->basic, AD_DOMAIN);
- ctx = talloc_zero(id_ctx, struct ad_subdomains_ctx);
- if (ctx == NULL) {
+ sd_ctx = talloc_zero(mem_ctx, struct ad_subdomains_ctx);
+ if (sd_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
return ENOMEM;
}
- ctx->be_ctx = be_ctx;
- ctx->sdom = id_ctx->sdap_id_ctx->opts->sdom;
- ctx->ldap_ctx = id_ctx->ldap_ctx;
- ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
- ctx->domain_name = talloc_strdup(ctx, ad_domain);
- if (ctx->domain_name == NULL) {
+ sd_ctx->be_ctx = be_ctx;
+ sd_ctx->sdom = ad_id_ctx->sdap_id_ctx->opts->sdom;
+ sd_ctx->sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
+ sd_ctx->domain_name = talloc_strdup(sd_ctx, ad_domain);
+ if (sd_ctx->domain_name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
return ENOMEM;
}
- ctx->ad_id_ctx = id_ctx;
- *ops = &ad_subdomains_ops;
- *pvt_data = ctx;
+ sd_ctx->ad_id_ctx = ad_id_ctx;
- ret = be_add_online_cb(ctx, be_ctx, ad_subdom_online_cb, ctx, NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom online callback\n");
- }
+ dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
+ ad_subdomains_handler_send, ad_subdomains_handler_recv, sd_ctx,
+ struct ad_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
- ret = be_add_offline_cb(ctx, be_ctx, ad_subdom_offline_cb, ctx, NULL);
+ period = be_ctx->domain->subdomain_refresh_interval;
+ ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
+ BE_PTASK_OFFLINE_DISABLE, 0,
+ ad_subdomains_ptask_send, ad_subdomains_ptask_recv, sd_ctx,
+ "Subdomains Refresh", NULL);
if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom offline callback\n");
- }
-
- err = sss_idmap_init(sss_idmap_talloc, ctx, sss_idmap_talloc_free,
- &ctx->idmap_ctx);
- if (err != IDMAP_SUCCESS) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
- return EFAULT;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ /* Ignore, responders will trigger refresh from time to time. */
}
- ret = ad_subdom_reinit(ctx);
+ ret = ad_subdom_reinit(sd_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Could not reinitialize subdomains. "
"Users from trusted domains might not be resolved correctly\n");
diff --git a/src/providers/ad/ad_subdomains.h b/src/providers/ad/ad_subdomains.h
index b4b0e765d..adc286b2b 100644
--- a/src/providers/ad/ad_subdomains.h
+++ b/src/providers/ad/ad_subdomains.h
@@ -28,10 +28,9 @@
#include "providers/backend.h"
#include "providers/ad/ad_common.h"
-int ad_subdom_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- const char *ad_domain,
- struct bet_ops **ops,
- void **pvt_data);
+errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *ad_id_ctx,
+ struct dp_method *dp_methods);
#endif /* _AD_SUBDOMAINS_H_ */
diff --git a/src/providers/ad/ad_sudo.c b/src/providers/ad/ad_sudo.c
index 53ce5af59..026eab1fd 100644
--- a/src/providers/ad/ad_sudo.c
+++ b/src/providers/ad/ad_sudo.c
@@ -25,21 +25,21 @@
#include "providers/ad/ad_common.h"
#include "providers/ldap/sdap_sudo.h"
-int ad_sudo_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t ad_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *id_ctx,
+ struct dp_method *dp_methods)
{
- int ret;
+ errno_t ret;
struct ad_options *ad_options;
struct sdap_options *ldap_options;
DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing sudo AD back end\n");
- ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data);
+ ret = sdap_sudo_init(mem_ctx, be_ctx, id_ctx->sdap_id_ctx, dp_methods);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize LDAP SUDO [%d]: %s\n",
- ret, strerror(ret));
+ ret, sss_strerror(ret));
return ret;
}
diff --git a/src/providers/backend.h b/src/providers/backend.h
index e91ed9c3e..739e935fc 100644
--- a/src/providers/backend.h
+++ b/src/providers/backend.h
@@ -35,49 +35,9 @@
#define BE_SRV_IDENTIFIER "_srv_"
struct be_ctx;
-struct bet_ops;
-struct be_req;
-
-typedef int (*bet_init_fn_t)(TALLOC_CTX *, struct bet_ops **, void **);
-typedef void (*be_shutdown_fn)(void *);
-typedef void (*be_req_fn_t)(struct be_req *);
-typedef void (*be_async_callback_t)(struct be_req *, int, int, const char *);
typedef void (*be_callback_t)(void *);
-enum bet_type {
- BET_NULL = 0,
- BET_ID,
- BET_AUTH,
- BET_ACCESS,
- BET_CHPASS,
- BET_SUDO,
- BET_AUTOFS,
- BET_SELINUX,
- BET_HOSTID,
- BET_SUBDOMAINS,
- BET_MAX
-};
-
-struct bet_data {
- enum bet_type bet_type;
- const char *option_name;
- const char *mod_init_fn_name_fmt;
-};
-
-struct loaded_be {
- char *be_name;
- void *handle;
-};
-
-struct bet_info {
- enum bet_type bet_type;
- struct bet_ops *bet_ops;
- void *pvt_bet_data;
- char *mod_name;
- struct bet_queue_item *req_queue;
-};
-
struct be_offline_status {
time_t went_offline;
bool offline;
@@ -90,13 +50,6 @@ struct be_resolv_ctx {
enum restrict_family family_order;
};
-struct be_client {
- struct be_ctx *bectx;
- struct sbus_connection *conn;
- struct tevent_timer *timeout;
- bool initialized;
-};
-
struct be_failover_ctx;
struct be_cb;
@@ -130,35 +83,14 @@ struct be_ctx {
struct be_ptask *check_if_online_ptask;
struct sbus_connection *mon_conn;
- struct sbus_connection *sbus_srv;
-
- struct be_client *nss_cli;
- struct be_client *pam_cli;
- struct be_client *sudo_cli;
- struct be_client *autofs_cli;
- struct be_client *ssh_cli;
- struct be_client *pac_cli;
- struct be_client *ifp_cli;
-
- struct loaded_be loaded_be[BET_MAX];
- struct bet_info bet_info[BET_MAX];
struct be_refresh_ctx *refresh_ctx;
size_t check_online_ref_count;
- /* List of ongoing requests */
- struct be_req *active_requests;
-
struct data_provider *provider;
};
-struct bet_ops {
- be_req_fn_t check_online;
- be_req_fn_t handler;
- be_req_fn_t finalize;
-};
-
struct be_acct_req {
int entry_type;
int attr_type;
@@ -168,28 +100,6 @@ struct be_acct_req {
char *domain;
};
-struct be_sudo_req {
- uint32_t type;
- char **rules;
-};
-
-struct be_autofs_req {
- char *mapname;
- bool invalidate;
-};
-
-struct be_subdom_req {
- bool force;
- char *domain_hint;
-};
-
-struct be_host_req {
- uint32_t type;
- int filter_type;
- char *name;
- char *alias;
-};
-
bool be_is_offline(struct be_ctx *ctx);
void be_mark_offline(struct be_ctx *ctx);
void be_mark_dom_offline(struct sss_domain_info *dom, struct be_ctx *ctx);
@@ -295,40 +205,4 @@ const char *be_fo_get_active_server_name(struct be_ctx *ctx,
errno_t be_res_init(struct be_ctx *ctx);
-/* be_req helpers */
-
-/* Create a back end request and call fn when done. Please note the
- * request name is not duplicated. The caller should either provide
- * a static string or steal a dynamic string onto req context.
- */
-struct be_req *be_req_create(TALLOC_CTX *mem_ctx,
- struct be_client *becli,
- struct be_ctx *be_ctx,
- const char *name,
- be_async_callback_t fn,
- void *pvt_fn_data);
-struct be_ctx *be_req_get_be_ctx(struct be_req *be_req);
-
-void *be_req_get_data(struct be_req *be_req);
-
-void be_req_terminate(struct be_req *be_req,
- int dp_err_type, int errnum, const char *errstr);
-
-void be_terminate_domain_requests(struct be_ctx *be_ctx,
- const char *domain);
-
-/* Request account information */
-struct tevent_req *
-be_get_account_info_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct be_client *becli,
- struct be_ctx *be_ctx,
- struct be_acct_req *ar);
-
-errno_t be_get_account_info_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- int *_err_maj,
- int *_err_min,
- const char **_err_msg);
-
#endif /* __DP_BACKEND_H___ */
diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h
index 298f91de4..decc0f4e8 100644
--- a/src/providers/data_provider/dp_custom_data.h
+++ b/src/providers/data_provider/dp_custom_data.h
@@ -25,6 +25,36 @@
/* Request handler private data. */
+struct dp_sudo_data {
+ uint32_t type;
+ char **rules;
+};
+
+struct dp_hostid_data {
+ const char *name;
+ const char *alias;
+};
+
+struct dp_autofs_data {
+ const char *mapname;
+};
+
+struct dp_subdomains_data {
+ const char *domain_hint;
+};
+
+/* TODO rename be_acct_req to dp_id_data to be consistent
+ This can be done after the original code is removed.
+struct dp_id_data {
+ uint32_t entry_type;
+ uint32_t attr_type;
+ uint32_t filter_type;
+ const char *filter_value;
+ const char *extra_value;
+ const char *domain;
+};
+*/
+
/* Reply private data. */
struct dp_reply_std {
diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
index 5eaf7e2a3..6a6ca6769 100644
--- a/src/providers/data_provider/dp_iface.c
+++ b/src/providers/data_provider/dp_iface.c
@@ -28,12 +28,12 @@
struct iface_dp iface_dp = {
{&iface_dp_meta, 0},
- .pamHandler = NULL,
- .sudoHandler = NULL,
- .autofsHandler = NULL,
- .hostHandler = NULL,
- .getDomains = NULL,
- .getAccountInfo = NULL
+ .pamHandler = dp_pam_handler,
+ .sudoHandler = dp_sudo_handler,
+ .autofsHandler = dp_autofs_handler,
+ .hostHandler = dp_host_handler,
+ .getDomains = dp_subdomains_handler,
+ .getAccountInfo = dp_get_account_info_handler
};
static struct sbus_iface_map dp_map[] = {
diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
index 2991bf7aa..eeef220e3 100644
--- a/src/providers/data_provider/dp_iface.h
+++ b/src/providers/data_provider/dp_iface.h
@@ -31,4 +31,32 @@
errno_t dp_register_sbus_interface(struct sbus_connection *conn,
struct dp_client *pvt);
+errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ uint32_t entry_type,
+ uint32_t attr_type,
+ const char *filter,
+ const char *domain,
+ const char *extra);
+
+errno_t dp_pam_handler(struct sbus_request *sbus_req, void *dp_cli);
+
+errno_t dp_sudo_handler(struct sbus_request *sbus_req, void *dp_cli);
+
+errno_t dp_host_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *name,
+ const char *alias);
+
+errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *mapname);
+
+errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ const char *domain_hint);
+
#endif /* DP_IFACE_H_ */
diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c
new file mode 100644
index 000000000..78c4cce7e
--- /dev/null
+++ b/src/providers/data_provider/dp_target_auth.c
@@ -0,0 +1,302 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+static void dp_pam_reply(struct sbus_request *sbus_req,
+ const char *request_name,
+ struct pam_data *pd)
+{
+ DBusMessage *reply;
+ dbus_bool_t dbret;
+
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Sending result [%d][%s]", pd->pam_status, pd->domain);
+
+ reply = dbus_message_new_method_return(sbus_req->message);
+ if (reply == NULL) {
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Unable to acquire reply message");
+ return;
+ }
+
+ dbret = dp_pack_pam_response(reply, pd);
+ if (!dbret) {
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Unable to generate reply message");
+ dbus_message_unref(reply);
+ return;
+ }
+
+ sbus_request_finish(sbus_req, reply);
+ dbus_message_unref(reply);
+ return;
+}
+
+static errno_t pam_data_create(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct be_ctx *be_ctx,
+ struct pam_data **_pd)
+{
+ DBusError dbus_error;
+ struct pam_data *pd;
+ bool bret;
+
+ dbus_error_init(&dbus_error);
+ bret = dp_unpack_pam_request(sbus_req->message, mem_ctx, &pd, &dbus_error);
+ if (bret == false) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse message!\n");
+ return EINVAL;
+ }
+
+ pd->pam_status = PAM_SYSTEM_ERR;
+ if (pd->domain == NULL) {
+ pd->domain = talloc_strdup(pd, be_ctx->domain->name);
+ if (pd->domain == NULL) {
+ talloc_free(pd);
+ return ENOMEM;
+ }
+ }
+
+ *_pd = pd;
+
+ return EOK;
+}
+
+static void choose_target(struct data_provider *provider,
+ struct pam_data *pd,
+ enum dp_targets *_target,
+ enum dp_methods *_method,
+ const char **_req_name)
+{
+ enum dp_targets target;
+ enum dp_methods method;
+ const char *name;
+
+ switch (pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ target = DPT_AUTH;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Authenticate";
+ break;
+ case SSS_PAM_PREAUTH:
+ target = DPT_AUTH;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Preauth";
+ break;
+ case SSS_PAM_ACCT_MGMT:
+ target = DPT_ACCESS;
+ method = DPM_ACCESS_HANDLER;
+ name = "PAM Account";
+ break;
+ case SSS_PAM_CHAUTHTOK_PRELIM:
+ target = DPT_CHPASS;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Chpass 1st";
+ break;
+ case SSS_PAM_CHAUTHTOK:
+ target = DPT_CHPASS;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Chpass 2nd";
+ break;
+ case SSS_PAM_OPEN_SESSION:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Open Session";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ case SSS_PAM_SETCRED:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Set Credentials";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ case SSS_PAM_CLOSE_SESSION:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Close Session";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ default:
+ DEBUG(SSSDBG_TRACE_LIBS, "Unsupported PAM command [%d].\n",
+ pd->cmd);
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Unsupported";
+ pd->pam_status = PAM_MODULE_UNKNOWN;
+ break;
+ }
+
+ /* Check that target is configured. */
+ if (target != DP_TARGET_SENTINEL
+ && !dp_target_enabled(provider, NULL, target)) {
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ pd->pam_status = PAM_MODULE_UNKNOWN;
+ }
+
+ *_target = target;
+ *_method = method;
+ *_req_name = name;
+}
+
+struct dp_pam_handler_state {
+ struct data_provider *provider;
+ struct dp_client *dp_cli;
+ struct sbus_request *sbus_req;
+ const char *request_name;
+};
+
+void dp_pam_handler_step_done(struct tevent_req *req);
+void dp_pam_handler_selinux_done(struct tevent_req *req);
+
+errno_t dp_pam_handler(struct sbus_request *sbus_req, void *sbus_data)
+{
+ struct dp_pam_handler_state *state;
+ struct data_provider *provider;
+ struct pam_data *pd = NULL;
+ struct dp_client *dp_cli;
+ enum dp_targets target;
+ enum dp_methods method;
+ const char *req_name;
+ struct tevent_req *req;
+ errno_t ret;
+
+ dp_cli = talloc_get_type(sbus_data, struct dp_client);
+ provider = dp_client_provider(dp_cli);
+
+ state = talloc_zero(sbus_req, struct dp_pam_handler_state);
+ if (state == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = pam_data_create(state, sbus_req, provider->be_ctx, &pd);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ state->provider = provider;
+ state->dp_cli = dp_cli;
+ state->sbus_req = sbus_req;
+
+ DEBUG(SSSDBG_CONF_SETTINGS, "Got request with the following data\n");
+ DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
+
+ choose_target(provider, pd, &target, &method, &req_name);
+ if (target == DP_TARGET_SENTINEL) {
+ /* Just send the result. Pam data are freed with this call. */
+ dp_pam_reply(sbus_req, req_name, pd);
+ return EOK;
+ }
+
+ req = dp_req_send(state, provider, dp_cli, pd->domain, req_name,
+ target, method, 0, pd, &state->request_name);
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(req, dp_pam_handler_step_done, state);
+
+done:
+ if (ret != EOK) {
+ talloc_free(pd);
+ }
+
+ return ret;
+}
+
+static bool should_invoke_selinux(struct data_provider *provider,
+ struct pam_data *pd)
+{
+ if (!dp_method_enabled(provider, DPT_SELINUX, DPM_SELINUX_HANDLER)) {
+ return false;
+ }
+
+ if (pd->cmd == SSS_PAM_ACCT_MGMT && pd->pam_status == PAM_SUCCESS) {
+ return true;
+ }
+
+ return false;
+}
+
+void dp_pam_handler_step_done(struct tevent_req *req)
+{
+ struct dp_pam_handler_state *state;
+ struct pam_data *pd;
+ errno_t ret;
+
+ state = tevent_req_callback_data(req, struct dp_pam_handler_state);
+
+ ret = dp_req_recv(state, req, struct pam_data *, &pd);
+ talloc_zfree(req);
+ if (ret != EOK) {
+ dp_req_reply_error(state->sbus_req, state->request_name, ret);
+ return;
+ }
+
+ if (!should_invoke_selinux(state->provider, pd)) {
+ /* State and request related data are freed with sbus_req. */
+ dp_pam_reply(state->sbus_req, state->request_name, pd);
+ return;
+ }
+
+ req = dp_req_send(state, state->provider, state->dp_cli, pd->domain,
+ "PAM SELinux", DPT_SELINUX, DPM_SELINUX_HANDLER,
+ 0, pd, NULL);
+ if (req == NULL) {
+ DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->request_name,
+ "Unable to process SELinux, killing request...");
+ talloc_free(state->sbus_req);
+ return;
+ }
+
+ tevent_req_set_callback(req, dp_pam_handler_selinux_done, state);
+}
+
+void dp_pam_handler_selinux_done(struct tevent_req *req)
+{
+ struct dp_pam_handler_state *state;
+ struct pam_data *pd;
+ errno_t ret;
+
+ state = tevent_req_callback_data(req, struct dp_pam_handler_state);
+
+ ret = dp_req_recv(state, req, struct pam_data *, &pd);
+ talloc_zfree(req);
+ if (ret != EOK) {
+ dp_req_reply_error(state->sbus_req, state->request_name, ret);
+ return;
+ }
+
+ /* State and request related data are freed with sbus_req. */
+ dp_pam_reply(state->sbus_req, state->request_name, pd);
+ return;
+}
diff --git a/src/providers/data_provider/dp_target_autofs.c b/src/providers/data_provider/dp_target_autofs.c
new file mode 100644
index 000000000..13b12f5dd
--- /dev/null
+++ b/src/providers/data_provider/dp_target_autofs.c
@@ -0,0 +1,55 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *mapname)
+{
+ struct dp_autofs_data *data;
+ const char *key;
+
+ if (mapname == NULL) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct dp_autofs_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->mapname = mapname;
+ key = mapname;
+
+ dp_req_with_reply(dp_cli, NULL, "AutoFS", key, sbus_req, DPT_AUTOFS,
+ DPM_AUTOFS_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_hostid.c b/src/providers/data_provider/dp_target_hostid.c
new file mode 100644
index 000000000..a47601f0b
--- /dev/null
+++ b/src/providers/data_provider/dp_target_hostid.c
@@ -0,0 +1,63 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_host_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *name,
+ const char *alias)
+{
+ struct dp_hostid_data *data;
+ const char *key;
+
+ if (name == NULL) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct dp_hostid_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->name = name;
+ data->alias = alias[0] == '\0' ? NULL : alias;
+
+ key = talloc_asprintf(data, "%s:%s", name,
+ (data->alias == NULL ? "(null)" : data->alias));
+ if (key == NULL) {
+ talloc_free(data);
+ return ENOMEM;
+ }
+
+ dp_req_with_reply(dp_cli, NULL, "HostID", key, sbus_req, DPT_HOSTID,
+ DPM_HOSTID_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
new file mode 100644
index 000000000..855bcd895
--- /dev/null
+++ b/src/providers/data_provider/dp_target_id.c
@@ -0,0 +1,311 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+#define FILTER_TYPE(str, type) {str "=", sizeof(str "=") - 1, type}
+
+static bool check_attr_type(uint32_t attr_type)
+{
+ switch (attr_type) {
+ case BE_ATTR_CORE:
+ case BE_ATTR_MEM:
+ case BE_ATTR_ALL:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static bool check_and_parse_filter(struct be_acct_req *data,
+ const char *filter,
+ const char *extra)
+{
+ /* We will use sizeof() to determine the length of a string so we don't
+ * call strlen over and over again with each request. Not a bottleneck,
+ * but unnecessary and simple to avoid. */
+ static struct {
+ const char *name;
+ size_t lenght;
+ uint32_t type;
+ } types[] = {FILTER_TYPE("name", BE_FILTER_NAME),
+ FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
+ FILTER_TYPE(DP_SEC_ID, BE_FILTER_SECID),
+ FILTER_TYPE(DP_CERT, BE_FILTER_CERT),
+ FILTER_TYPE(DP_WILDCARD, BE_FILTER_WILDCARD),
+ {0, 0, 0}};
+ int i;
+
+ if (filter == NULL) {
+ return false;
+ }
+
+ for (i = 0; types[i].name != NULL; i++) {
+ if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
+ data->filter_type = types[i].type;
+ data->filter_value = discard_const(&filter[types[i].lenght]); /* todo remove discard const */
+ data->extra_value = discard_const(extra); /* todo remove discard const */
+ return true;
+ }
+ }
+
+ if (strcmp(filter, ENUM_INDICATOR) == 0) {
+ data->filter_type = BE_FILTER_ENUM;
+ data->filter_value = NULL;
+ data->extra_value = NULL;
+ return true;
+ }
+
+ return false;
+}
+
+struct dp_initgr_ctx {
+ const char *username;
+ const char *domain;
+ 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)
+{
+ struct dp_initgr_ctx *ctx;
+ const char *username;
+ unsigned int i;
+ errno_t ret;
+
+ ctx = talloc_zero(mem_ctx, struct dp_initgr_ctx);
+ if (ctx == NULL) {
+ 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;
+ }
+
+ 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) {
+ 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++;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(ctx);
+ return NULL;
+ }
+
+ 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)
+{
+ struct dp_client *dp_cli;
+ DBusMessage *msg;
+ dbus_bool_t dbret;
+ int num;
+
+ dp_cli = provider->clients[DPC_NSS];
+ if (dp_cli == NULL) {
+ return;
+ }
+
+ msg = dbus_message_new_method_call(NULL,
+ DP_PATH,
+ DATA_PROVIDER_REV_IFACE,
+ DATA_PROVIDER_REV_IFACE_INITGRCHECK);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+ return;
+ }
+
+ num = ctx->gnum;
+ dbret = dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &ctx->username,
+ DBUS_TYPE_STRING, &ctx->domain,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &ctx->groups, num,
+ DBUS_TYPE_INVALID);
+ if (!dbret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+ dbus_message_unref(msg);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Ordering NSS responder to update memory cache\n");
+
+ sbus_conn_send_reply(dp_client_conn(dp_cli), msg);
+ dbus_message_unref(msg);
+
+ return;
+}
+
+static errno_t dp_initgroups(struct sbus_request *sbus_req,
+ struct dp_client *dp_cli,
+ const char *key,
+ uint32_t dp_flags,
+ struct be_acct_req *data)
+{
+ struct be_ctx *be_ctx;
+ struct data_provider *provider;
+ struct sss_domain_info *domain;
+ struct dp_initgr_ctx *ctx;
+ struct ldb_result *res;
+ errno_t ret;
+
+ provider = dp_client_provider(dp_cli);
+ be_ctx = provider->be_ctx;
+
+ if (data->domain == NULL) {
+ domain = be_ctx->domain;
+ } else {
+ domain = find_domain_by_name(be_ctx->domain, data->domain, true);
+ if (domain == NULL) {
+ return ERR_DOMAIN_NOT_FOUND;
+ }
+ }
+
+ ret = sysdb_initgroups(sbus_req, domain, data->filter_value, &res);
+ if (ret == ENOENT || (ret == EOK && res->count == 0)) {
+ /* There is no point in concacting NSS responder. Proceed as usual. */
+ return EAGAIN;
+ } 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);
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dp_req_with_reply_pp(dp_cli, data->domain, "Initgroups", key,
+ sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
+ dp_req_initgr_pp, ctx, struct dp_initgr_ctx,
+ dp_req_reply_std, struct dp_reply_std);
+
+ ret = EOK;
+
+done:
+ talloc_free(res);
+ return ret;
+}
+
+errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ uint32_t entry_type,
+ uint32_t attr_type,
+ const char *filter,
+ const char *domain,
+ const char *extra)
+{
+ struct be_acct_req *data;
+ const char *key;
+ errno_t ret;
+
+ if (!check_attr_type(attr_type)) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct be_acct_req);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->entry_type = entry_type;
+ data->attr_type = attr_type;
+ data->domain = discard_const(domain); /* todo remove discard const */
+
+ if (!check_and_parse_filter(data, filter, extra)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ key = talloc_asprintf(data, "%u:%u:%s:%s:%s", data->entry_type,
+ data->attr_type, extra, domain, filter);
+ if (key == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if ((data->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
+ ret = dp_initgroups(sbus_req, dp_cli, key, dp_flags, data);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ }
+
+ dp_req_with_reply(dp_cli, domain, "Account", key,
+ sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(data);
+ }
+
+ return ret;
+}
diff --git a/src/providers/data_provider/dp_target_subdomains.c b/src/providers/data_provider/dp_target_subdomains.c
new file mode 100644
index 000000000..85e37f063
--- /dev/null
+++ b/src/providers/data_provider/dp_target_subdomains.c
@@ -0,0 +1,50 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ const char *domain_hint)
+{
+ struct dp_subdomains_data *data;
+ const char *key;
+
+ data = talloc_zero(sbus_req, struct dp_subdomains_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->domain_hint = domain_hint;
+ key = domain_hint[0] == '\0' ? "<ALL>" : domain_hint;
+
+ dp_req_with_reply(dp_cli, NULL, "Subdomains", key, sbus_req,
+ DPT_SUBDOMAINS, DPM_DOMAINS_HANDLER, 0, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_sudo.c b/src/providers/data_provider/dp_target_sudo.c
new file mode 100644
index 000000000..37add97fe
--- /dev/null
+++ b/src/providers/data_provider/dp_target_sudo.c
@@ -0,0 +1,199 @@
+/*
+ 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 <talloc.h>
+#include <tevent.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+static errno_t dp_sudo_parse_message(TALLOC_CTX *mem_ctx,
+ DBusMessage *msg,
+ uint32_t *_dp_flags,
+ uint32_t *_sudo_type,
+ char ***_rules)
+{
+ DBusError error;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ uint32_t dp_flags;
+ uint32_t sudo_type;
+ uint32_t num_rules;
+ const char *rule;
+ char **rules = NULL;
+ uint32_t i;
+ errno_t ret;
+
+ dbus_error_init(&error);
+ dbus_message_iter_init(msg, &iter);
+
+ /* get dp flags */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &dp_flags);
+ dbus_message_iter_next(&iter); /* step behind the request type */
+
+ /* get type of the request */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &sudo_type);
+ dbus_message_iter_next(&iter); /* step behind the request type */
+
+ /* get additional arguments according to the request type */
+ switch (sudo_type) {
+ case BE_REQ_SUDO_FULL:
+ /* no arguments required */
+ break;
+ case BE_REQ_SUDO_RULES:
+ /* additional arguments:
+ * rules_num
+ * rules[rules_num]
+ */
+ /* read rules_num */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &num_rules);
+
+ rules = talloc_zero_array(mem_ctx, char *, num_rules + 1);
+ if (rules == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array() failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_recurse(&iter, &array_iter);
+
+ /* read the rules */
+ for (i = 0; i < num_rules; i++) {
+ if (dbus_message_iter_get_arg_type(&array_iter)
+ != DBUS_TYPE_STRING) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&array_iter, &rule);
+ rules[i] = talloc_strdup(rules, rule);
+ if (rules[i] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dbus_message_iter_next(&array_iter);
+ }
+
+ rules[num_rules] = NULL;
+
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type %d\n", sudo_type);
+ return EINVAL;
+ }
+
+ *_dp_flags = dp_flags;
+ *_sudo_type = sudo_type;
+ *_rules = rules;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(rules);
+ }
+
+ return ret;
+}
+
+static const char *dp_sudo_get_key(uint32_t type)
+{
+ switch (type) {
+ case BE_REQ_SUDO_FULL:
+ return "full-refresh";
+ case BE_REQ_SUDO_RULES:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static const char *dp_sudo_get_name(uint32_t type)
+{
+ switch (type) {
+ case BE_REQ_SUDO_FULL:
+ return "SUDO Full Refresh";
+ case BE_REQ_SUDO_RULES:
+ return "SUDO Rules Refresh";
+ }
+
+ return NULL;
+}
+
+errno_t dp_sudo_handler(struct sbus_request *sbus_req, void *dp_cli)
+{
+ struct dp_sudo_data *data;
+ uint32_t dp_flags;
+ const char *key;
+ const char *name;
+ errno_t ret;
+
+ data = talloc_zero(sbus_req, struct dp_sudo_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ ret = dp_sudo_parse_message(data, sbus_req->message, &dp_flags,
+ &data->type, &data->rules);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ key = dp_sudo_get_key(data->type);
+ name = dp_sudo_get_name(data->type);
+
+ dp_req_with_reply(dp_cli, NULL, name, key, sbus_req, DPT_SUDO,
+ DPM_SUDO_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 58c32dca4..78efed851 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -49,12 +49,6 @@
#include "resolv/async_resolv.h"
#include "monitor/monitor_interfaces.h"
-#define MSG_TARGET_NO_CONFIGURED "sssd_be: The requested target is not configured"
-
-#define ACCESS_PERMIT "permit"
-#define ACCESS_DENY "deny"
-#define NO_PROVIDER "none"
-
static int data_provider_res_init(struct sbus_request *dbus_req, void *data);
static int data_provider_go_offline(struct sbus_request *dbus_req, void *data);
static int data_provider_reset_offline(struct sbus_request *dbus_req, void *data);
@@ -73,557 +67,12 @@ struct mon_cli_iface monitor_be_methods = {
.sysbusReconnect = NULL,
};
-static int client_registration(struct sbus_request *dbus_req, void *data);
-static int be_get_account_info(struct sbus_request *dbus_req, void *user_data);
-static int be_pam_handler(struct sbus_request *dbus_req, void *user_data);
-static int be_sudo_handler(struct sbus_request *dbus_req, void *user_data);
-static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data);
-static int be_host_handler(struct sbus_request *dbus_req, void *user_data);
-static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data);
-
-struct data_provider_iface be_methods = {
- { &data_provider_iface_meta, 0 },
- .RegisterService = client_registration,
- .pamHandler = be_pam_handler,
- .sudoHandler = be_sudo_handler,
- .autofsHandler = be_autofs_handler,
- .hostHandler = be_host_handler,
- .getDomains = be_get_subdomains,
- .getAccountInfo = be_get_account_info,
-};
-
-static struct bet_data bet_data[] = {
- {BET_NULL, NULL, NULL},
- {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_id_init"},
- {BET_AUTH, CONFDB_DOMAIN_AUTH_PROVIDER, "sssm_%s_auth_init"},
- {BET_ACCESS, CONFDB_DOMAIN_ACCESS_PROVIDER, "sssm_%s_access_init"},
- {BET_CHPASS, CONFDB_DOMAIN_CHPASS_PROVIDER, "sssm_%s_chpass_init"},
- {BET_SUDO, CONFDB_DOMAIN_SUDO_PROVIDER, "sssm_%s_sudo_init"},
- {BET_AUTOFS, CONFDB_DOMAIN_AUTOFS_PROVIDER, "sssm_%s_autofs_init"},
- {BET_SELINUX, CONFDB_DOMAIN_SELINUX_PROVIDER, "sssm_%s_selinux_init"},
- {BET_HOSTID, CONFDB_DOMAIN_HOSTID_PROVIDER, "sssm_%s_hostid_init"},
- {BET_SUBDOMAINS, CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, "sssm_%s_subdomains_init"},
- {BET_MAX, NULL, NULL}
-};
-
-struct bet_queue_item {
- struct bet_queue_item *prev;
- struct bet_queue_item *next;
-
- TALLOC_CTX *mem_ctx;
- struct be_req *be_req;
- be_req_fn_t fn;
-
-};
-
-static const char *dp_err_to_string(int dp_err_type)
-{
- switch (dp_err_type) {
- case DP_ERR_OK:
- return "Success";
- case DP_ERR_OFFLINE:
- return "Provider is Offline";
- case DP_ERR_TIMEOUT:
- return "Request timed out";
- case DP_ERR_FATAL:
- return "Internal Error";
- default:
- break;
- }
-
- return "Unknown Error";
-}
-
-static const char *safe_be_req_err_msg(const char *msg_in,
- int dp_err_type)
-{
- bool ok;
-
- if (msg_in == NULL) {
- /* No custom error, just use default */
- return dp_err_to_string(dp_err_type);
- }
-
- ok = sss_utf8_check((const uint8_t *) msg_in,
- strlen(msg_in));
- if (!ok) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Back end message [%s] contains invalid non-UTF8 character, " \
- "using default\n", msg_in);
- return dp_err_to_string(dp_err_type);
- }
-
- return msg_in;
-}
-
-#define REQ_PHASE_ACCESS 0
-#define REQ_PHASE_SELINUX 1
-
-struct be_req {
- struct be_client *becli;
- struct be_ctx *be_ctx;
- struct sss_domain_info *domain;
- void *req_data;
-
- be_async_callback_t fn;
- void *pvt;
-
- /* This is utilized in access provider
- * request handling to indicate if access or
- * selinux provider is calling the callback.
- */
- int phase;
-
- /* Just for nicer debugging */
- const char *req_name;
-
- struct be_req *prev;
- struct be_req *next;
-};
-
-static int be_req_destructor(struct be_req *be_req)
-{
- DLIST_REMOVE(be_req->be_ctx->active_requests, be_req);
-
- return 0;
-}
-
-struct be_req *be_req_create(TALLOC_CTX *mem_ctx,
- struct be_client *becli,
- struct be_ctx *be_ctx,
- const char *name,
- be_async_callback_t fn,
- void *pvt_fn_data)
-{
- struct be_req *be_req;
-
- be_req = talloc_zero(mem_ctx, struct be_req);
- if (be_req == NULL) return NULL;
-
- be_req->becli = becli;
- be_req->be_ctx = be_ctx;
- be_req->domain = be_ctx->domain;
- be_req->fn = fn;
- be_req->pvt = pvt_fn_data;
- be_req->req_name = talloc_strdup(be_req, name);
- if (be_req->req_name == NULL) {
- talloc_free(be_req);
- return NULL;
- }
-
- /* Add this request to active request list and make sure it is
- * removed on termination. */
- DLIST_ADD(be_ctx->active_requests, be_req);
- talloc_set_destructor(be_req, be_req_destructor);
-
- return be_req;
-}
-
-static errno_t be_req_set_domain(struct be_req *be_req, const char *domain)
-{
- struct sss_domain_info *dom = NULL;
-
- dom = find_domain_by_name(be_req->be_ctx->domain, domain, true);
- if (dom == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown domain [%s]!\n", domain);
- return ERR_DOMAIN_NOT_FOUND;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC, "Changing request domain from [%s] to [%s]\n",
- be_req->domain->name, dom->name);
- be_req->domain = dom;
-
- return EOK;
-}
-
-struct be_ctx *be_req_get_be_ctx(struct be_req *be_req)
-{
- return be_req->be_ctx;
-}
-
-void *be_req_get_data(struct be_req *be_req)
-{
- return be_req->req_data;
-}
-
-void be_req_terminate(struct be_req *be_req,
- int dp_err_type, int errnum, const char *errstr)
-{
- if (be_req->fn == NULL) return;
- be_req->fn(be_req, dp_err_type, errnum, errstr);
-}
-
-static errno_t be_sbus_reply(struct sbus_request *sbus_req,
- dbus_uint16_t err_maj,
- dbus_uint32_t err_min,
- const char *err_msg)
-{
- errno_t ret;
- const char *safe_err_msg;
-
- /* Only return a reply if one was requested
- * There may not be one if this request began
- * while we were offline
- */
- if (sbus_req == NULL) {
- return EOK;
- }
-
- safe_err_msg = safe_be_req_err_msg(err_msg, err_maj);
-
- if (err_maj == DP_ERR_FATAL && err_min == ENODEV) {
- DEBUG(SSSDBG_TRACE_LIBS,
- "Cannot handle request: %s",
- err_msg ? err_msg : "Handler not configured\n");
- } else {
- DEBUG(SSSDBG_TRACE_LIBS,
- "Request processed. Returned [%s]:%d,%d,%s\n",
- dp_err_to_string(err_maj), err_maj, err_min, err_msg);
- }
-
- ret = sbus_request_return_and_finish(sbus_req,
- DBUS_TYPE_UINT16, &err_maj,
- DBUS_TYPE_UINT32, &err_min,
- DBUS_TYPE_STRING, &safe_err_msg,
- DBUS_TYPE_INVALID);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sbus_request_return_and_finish failed: [%d]: %s\n",
- ret, sss_strerror(ret));
- }
-
- return ret;
-}
-
-static errno_t be_sbus_req_reply(struct sbus_request *sbus_req,
- int dp_err_type,
- int errnum,
- const char *errstr)
-{
- dbus_uint16_t err_maj;
- dbus_uint32_t err_min;
-
- err_maj = dp_err_type;
- err_min = errnum;
-
- return be_sbus_reply(sbus_req, err_maj, err_min, errstr);
-}
-
-static void be_req_default_callback(struct be_req *be_req,
- int dp_err_type,
- int errnum,
- const char *errstr)
-{
- struct sbus_request *dbus_req;
-
- DEBUG(SSSDBG_TRACE_FUNC, "Replying to %s request\n", be_req->req_name);
-
- dbus_req = (struct sbus_request *) be_req->pvt;
-
- be_sbus_req_reply(dbus_req, dp_err_type, errnum, errstr);
- talloc_free(be_req);
-}
-
-/* Send back an immediate reply and set the sbus_request to NULL
- * so that we are sure the request is not reused in the future
- */
-static errno_t be_offline_reply(struct sbus_request **sbus_req_ptr)
-{
- struct sbus_request *dbus_req;
- errno_t ret;
-
- if (sbus_req_ptr == NULL) {
- return EINVAL;
- }
- dbus_req = *sbus_req_ptr;
-
- ret = be_sbus_req_reply(dbus_req, DP_ERR_OFFLINE, EAGAIN,
- "Fast reply - offline");
- *sbus_req_ptr = NULL;
- return ret;
-}
-
-struct be_sbus_reply_data {
- dbus_uint16_t err_maj;
- dbus_uint32_t err_min;
- const char *err_msg;
-};
-
-#define BE_SBUS_REPLY_DATA_INIT { .err_maj = DP_ERR_FATAL, \
- .err_min = ERR_INTERNAL, \
- .err_msg = "Fatal error" \
- };
-
-static inline void be_sbus_reply_data_set(struct be_sbus_reply_data *rdata,
- dbus_uint16_t err_maj,
- dbus_uint32_t err_min,
- const char *err_msg)
-{
- if (rdata == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Bug: Attempt to set NULL be_sbus_reply_data\n");
- return;
- }
-
- rdata->err_maj = err_maj;
- rdata->err_min = err_min;
- rdata->err_msg = err_msg;
-}
-
-static inline errno_t be_sbus_req_reply_data(struct sbus_request *sbus_req,
- struct be_sbus_reply_data *data)
-{
- return be_sbus_reply(sbus_req, data->err_maj,
- data->err_min, data->err_msg);
-}
-
-void be_terminate_domain_requests(struct be_ctx *be_ctx,
- const char *domain)
-{
- struct be_req *be_req;
- struct be_req *next_be_req;
-
- DEBUG(SSSDBG_TRACE_FUNC, "Terminating requests for domain [%s]\n",
- domain);
-
- if (domain == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "BUG: domain is NULL\n");
- return;
- }
-
- be_req = be_ctx->active_requests;
- while (be_req) {
- /* save pointer to next request in case be_req will be freed */
- next_be_req = be_req->next;
- if (strcmp(domain, be_req->domain->name) == 0) {
- be_req_terminate(be_req, DP_ERR_FATAL, ERR_DOMAIN_NOT_FOUND,
- sss_strerror(ERR_DOMAIN_NOT_FOUND));
- }
- be_req = next_be_req;
- }
-}
-
-struct be_async_req {
- be_req_fn_t fn;
- struct be_req *req;
-};
-
-static void be_async_req_handler(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *pvt)
-{
- struct be_async_req *async_req;
-
- async_req = talloc_get_type(pvt, struct be_async_req);
-
- async_req->fn(async_req->req);
-}
-
-struct be_spy {
- TALLOC_CTX *freectx;
- struct be_spy *double_agent;
-};
-
-static int be_spy_destructor(struct be_spy *spy)
-{
- /* If there's a double_agent, set its
- * freectx to NULL so that we don't
- * try to loop. When that spy fires,
- * it will just be a no-op.
- */
- spy->double_agent->freectx = NULL;
- talloc_zfree(spy->freectx);
- return 0;
-}
-
-static errno_t be_spy_create(TALLOC_CTX *mem_ctx, struct be_req *be_req)
-{
- errno_t ret;
- struct be_spy *cli_spy = NULL;
- struct be_spy *req_spy = NULL;
-
- /* Attach a spy for the be_client so that if it dies,
- * we can free the be_req automatically.
- */
- cli_spy = talloc_zero(be_req->becli, struct be_spy);
- if (!cli_spy) {
- ret = ENOMEM;
- goto done;
- }
- cli_spy->freectx = be_req;
-
- /* Also create a spy on the be_req so that we
- * can free the other spy when the be_req
- * completes successfully.
- */
- req_spy = talloc_zero(be_req, struct be_spy);
- if (!req_spy) {
- ret = ENOMEM;
- goto done;
- }
- req_spy->freectx = cli_spy;
-
- /* Create paired spy links to prevent loops */
- cli_spy->double_agent = req_spy;
- req_spy->double_agent = cli_spy;
-
- /* Now create the destructors that will actually free
- * the opposing spies.
- */
- talloc_set_destructor(cli_spy, be_spy_destructor);
- talloc_set_destructor(req_spy, be_spy_destructor);
-
-
- /* Now steal the be_req onto the mem_ctx so that it
- * will be guaranteed that this data will be
- * available for the full duration of execution.
- */
- talloc_steal(mem_ctx, be_req);
-
- ret = EOK;
-done:
- if (ret != EOK) {
- talloc_free(cli_spy);
- talloc_free(req_spy);
- }
- return ret;
-}
-
-/* This function alters the memory hierarchy of the be_req
- * to ensure memory safety during shutdown. It creates a
- * spy on the be_cli object so that it will free the be_req
- * if the client is freed.
- *
- * It is generally allocated atop the private data context
- * for the appropriate back-end against which it is being
- * filed.
- */
-static errno_t be_file_request(TALLOC_CTX *mem_ctx,
- struct be_req *be_req,
- be_req_fn_t fn)
-{
- errno_t ret;
- struct be_async_req *areq;
- struct tevent_timer *te;
- struct timeval tv;
-
- if (!fn || !be_req) return EINVAL;
-
- ret = be_spy_create(mem_ctx, be_req);
- if (ret != EOK) return ret;
-
- areq = talloc(be_req, struct be_async_req);
- if (!areq) {
- return ENOMEM;
- }
- areq->fn = fn;
- areq->req = be_req;
-
- /* fire immediately */
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- te = tevent_add_timer(be_req->be_ctx->ev, be_req,
- tv, be_async_req_handler, areq);
- if (te == NULL) {
- return EIO;
- }
-
- return EOK;
-}
-
-static errno_t be_queue_request(TALLOC_CTX *queue_mem_ctx,
- struct bet_queue_item **req_queue,
- TALLOC_CTX *req_mem_ctx,
- struct be_req *be_req,
- be_req_fn_t fn)
-{
- struct bet_queue_item *item;
- int ret;
-
- if (*req_queue == NULL) {
- DEBUG(SSSDBG_TRACE_ALL, "Queue is empty, " \
- "running request immediately.\n");
- ret = be_file_request(req_mem_ctx, be_req, fn);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "be_file_request failed.\n");
- return ret;
- }
- }
-
- item = talloc_zero(queue_mem_ctx, struct bet_queue_item);
- if (item == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed, cannot add item to " \
- "request queue.\n");
- } else {
- DEBUG(SSSDBG_TRACE_ALL, "Adding request to queue.\n");
- item->mem_ctx = req_mem_ctx;
- item->be_req = be_req;
- item->fn = fn;
-
- DLIST_ADD_END(*req_queue, item, struct bet_queue_item *);
- }
-
- return EOK;
-}
-
-static void be_queue_next_request(struct be_req *be_req, enum bet_type type)
-{
- struct bet_queue_item *item;
- struct bet_queue_item *current = NULL;
- struct bet_queue_item **req_queue;
- struct sbus_request *dbus_req;
- int ret;
- struct be_req *next_be_req = NULL;
-
- req_queue = &be_req->becli->bectx->bet_info[type].req_queue;
-
- if (*req_queue == NULL) {
- DEBUG(SSSDBG_TRACE_ALL, "Queue is empty, nothing to do.\n");
- return;
- }
-
- DLIST_FOR_EACH(item, *req_queue) {
- if (item->be_req == be_req) {
- current = item;
- break;
- }
- }
-
- if (current != NULL) {
- DLIST_REMOVE(*req_queue, current);
- }
-
- if (*req_queue == NULL) {
- DEBUG(SSSDBG_TRACE_ALL, "Request queue is empty.\n");
- return;
- }
-
- next_be_req = (*req_queue)->be_req;
-
- ret = be_file_request((*req_queue)->mem_ctx, next_be_req, (*req_queue)->fn);
- if (ret == EOK) {
- DEBUG(SSSDBG_TRACE_ALL, "Queued request filed successfully.\n");
- return;
- }
-
- DEBUG(SSSDBG_OP_FAILURE, "be_file_request failed.\n");
-
- be_queue_next_request(next_be_req, type);
-
- dbus_req = (struct sbus_request *) next_be_req->pvt;
-
- be_sbus_req_reply(dbus_req, DP_ERR_FATAL, ret,
- "Cannot file back end request");
- talloc_free(next_be_req);
-}
-
bool be_is_offline(struct be_ctx *ctx)
{
return ctx->offstat.offline;
}
-static void check_if_online(struct be_ctx *ctx);
+static void check_if_online(struct be_ctx *be_ctx);
static errno_t
try_to_go_online(TALLOC_CTX *mem_ctx,
@@ -776,1629 +225,125 @@ static void be_reset_offline(struct be_ctx *ctx)
be_run_online_cb(ctx);
}
-static void get_subdomains_callback(struct be_req *req,
- int dp_err_type,
- int errnum,
- const char *errstr)
-{
- struct sbus_request *dbus_req;
-
- be_queue_next_request(req, BET_SUBDOMAINS);
-
- dbus_req = (struct sbus_request *) req->pvt;
-
- be_sbus_req_reply(dbus_req, dp_err_type, errnum, errstr);
- talloc_free(req);
-}
-
-static int be_get_subdomains(struct sbus_request *dbus_req, void *user_data)
-{
- struct be_subdom_req *req;
- struct be_req *be_req = NULL;
- struct be_client *becli;
- char *domain_hint;
- struct be_sbus_reply_data req_reply = BE_SBUS_REPLY_DATA_INIT;
- int ret;
-
- becli = talloc_get_type(user_data, struct be_client);
- if (!becli) return EINVAL;
-
- if (!sbus_request_parse_or_finish(dbus_req,
- DBUS_TYPE_STRING, &domain_hint,
- DBUS_TYPE_INVALID))
- return EOK; /* handled */
-
- /* return an error if corresponding backend target is not configured */
- if (becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops == NULL) {
- DEBUG(SSSDBG_TRACE_INTERNAL, "Undefined backend target.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENODEV,
- "Subdomains back end target is not configured");
- goto immediate;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC, "Got get subdomains [%s]\n",
- domain_hint == NULL ? "no hint": domain_hint );
-
- /* If we are offline return immediately
- */
- if (becli->bectx->offstat.offline) {
- DEBUG(SSSDBG_TRACE_FUNC, "Cannot proceed, provider is offline.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_OFFLINE, EAGAIN,
- "Provider is offline");
- goto immediate;
- }
-
- /* process request */
-
- be_req = be_req_create(becli, becli, becli->bectx, "get subdomains",
- get_subdomains_callback, dbus_req);
- if (!be_req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto immediate;
- }
-
- req = talloc(be_req, struct be_subdom_req);
- if (!req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto immediate;
- }
- req->domain_hint = talloc_strdup(req, domain_hint);
- if (!req->domain_hint) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto immediate;
- }
-
- be_req->req_data = req;
-
- ret = be_queue_request(becli->bectx,
- &becli->bectx->bet_info[BET_SUBDOMAINS].req_queue,
- becli->bectx,
- be_req,
- becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops->handler);
- if (ret != EOK) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ret,
- "Cannot file back end request");
- goto immediate;
- }
-
- return EOK;
-
-immediate:
- talloc_free(be_req);
- be_sbus_req_reply_data(dbus_req, &req_reply);
- return EOK;
-}
-
-struct be_initgr_prereq {
- char *user;
- char *domain;
- uint32_t gnum;
- uint32_t *groups;
-
- void *orig_pvt_data;
- int orig_dp_err_type;
- int orig_errnum;
- const char *orig_errstr;
-};
-
-static void acctinfo_callback_initgr_wrap(struct be_req *be_req)
-{
- struct be_initgr_prereq *pr = talloc_get_type(be_req->pvt,
- struct be_initgr_prereq);
-
- be_req->pvt = pr->orig_pvt_data;
- be_req_default_callback(be_req, pr->orig_dp_err_type,
- pr->orig_errnum, pr->orig_errstr);
-}
-
-static void acctinfo_callback_initgr_sbus(DBusPendingCall *pending, void *ptr)
-{
- struct be_req *be_req = talloc_get_type(ptr, struct be_req);
-
- dbus_pending_call_unref(pending);
-
- acctinfo_callback_initgr_wrap(be_req);
-}
-
-static void acctinfo_initgroups_callback(struct be_req *be_req,
- int dp_err_type,
- int errnum,
- const char *errstr)
-{
- struct be_initgr_prereq *pr = talloc_get_type(be_req->pvt,
- struct be_initgr_prereq);
- DBusMessage *msg = NULL;
- dbus_bool_t dbret;
- int num;
- int ret;
-
- pr->orig_dp_err_type = dp_err_type;
- pr->orig_errnum = errnum;
- pr->orig_errstr = errstr;
-
- if (!be_req->be_ctx->nss_cli || !be_req->be_ctx->nss_cli->conn) {
- DEBUG(SSSDBG_MINOR_FAILURE, "NSS Service not conected\n");
- ret = EACCES;
- goto done;
- }
-
- /* Set up null request */
- msg = dbus_message_new_method_call(NULL,
- DP_PATH,
- DATA_PROVIDER_REV_IFACE,
- DATA_PROVIDER_REV_IFACE_INITGRCHECK);
- if (!msg) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
- ret = ENOMEM;
- goto done;
- }
-
- num = pr->gnum;
- dbret = dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &pr->user,
- DBUS_TYPE_STRING, &pr->domain,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
- &pr->groups, num,
- DBUS_TYPE_INVALID);
- if (!dbret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
- ret = ENOMEM;
- goto done;
- }
-
- /* ping the NSS service, no reply expected */
- ret = sbus_conn_send(be_req->be_ctx->nss_cli->conn, msg, -1,
- acctinfo_callback_initgr_sbus, be_req, NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_TRACE_FUNC,
- "Error contacting NSS responder: %d [%s]\n",
- ret, strerror(ret));
- }
-
-done:
- if (msg) {
- dbus_message_unref(msg);
- }
- if (ret != EOK) {
- /* return immediately if we cannot contact nss provider */
- acctinfo_callback_initgr_wrap(be_req);
- }
-}
-
-static errno_t be_initgroups_prereq(struct be_req *be_req)
-{
- struct be_acct_req *ar = talloc_get_type(be_req_get_data(be_req),
- struct be_acct_req);
- struct be_initgr_prereq *pr;
- struct ldb_result *res;
- errno_t ret;
- const char *tmpstr;
- int i;
-
- ret = sysdb_initgroups(be_req, be_req->be_ctx->domain, ar->filter_value,
- &res);
- if (ret && ret != ENOENT) {
- return ret;
- }
- /* if the user is completely missing there is no need to contact NSS,
- * it would be a noop */
- if (ret == ENOENT || res->count == 0) {
- /* yet unknown, ignore */
- return EOK;
- }
-
- pr = talloc(be_req, struct be_initgr_prereq);
- if (!pr) {
- return ENOMEM;
- }
- pr->groups = talloc_array(pr, gid_t, res->count);
- if (!pr->groups) {
- return ENOMEM;
- }
- tmpstr = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
- if (!tmpstr) {
- return EINVAL;
- }
- pr->user = talloc_strdup(pr, tmpstr);
- if (!pr->user) {
- return ENOMEM;
- }
- pr->domain = talloc_strdup(pr, be_req->be_ctx->domain->name);
- if (!pr->domain) {
- return ENOMEM;
- }
- /* The first GID is the primary so it might be duplicated
- * later in the list */
- for (pr->gnum = 0, i = 0; i < res->count; i++) {
- pr->groups[pr->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 (pr->groups[pr->gnum] != 0) {
- pr->gnum++;
- }
- }
-
- talloc_zfree(res);
-
- pr->orig_pvt_data = be_req->pvt;
- be_req->pvt = pr;
- be_req->fn = acctinfo_initgroups_callback;
+static void be_check_online_done(struct tevent_req *req);
- return EOK;
-}
-
-static errno_t
-be_file_account_request(struct be_req *be_req, struct be_acct_req *ar)
-{
- errno_t ret;
- struct be_ctx *be_ctx = be_req->be_ctx;
-
- be_req->req_data = ar;
-
- /* see if we need a pre request call, only done for initgroups for now */
- if ((ar->entry_type & 0xFF) == BE_REQ_INITGROUPS) {
- ret = be_initgroups_prereq(be_req);
- if (ret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Prerequest failed\n");
- return ret;
- }
- }
-
- /* process request */
- ret = be_file_request(be_ctx, be_req,
- be_ctx->bet_info[BET_ID].bet_ops->handler);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to file request\n");
- return ret;
- }
-
- return EOK;
-}
-
-static errno_t
-split_name_extended(TALLOC_CTX *mem_ctx,
- const char *filter,
- char **name,
- char **extended)
-{
- char *p;
-
- *name = talloc_strdup(mem_ctx, filter);
- if (!*name) {
- return ENOENT;
- }
-
- p = strchr(*name, ':');
- if (p) {
- /* Extended info included */
- *p = '\0';
-
- *extended = p + 1;
- } else {
- *extended = NULL;
- }
-
- return EOK;
-}
-
-static void
-be_get_account_info_done(struct be_req *be_req,
- int dp_err, int dp_ret,
- const char *errstr);
-
-struct be_get_account_info_state {
- int err_maj;
- int err_min;
- const char *err_msg;
-};
-
-struct tevent_req *
-be_get_account_info_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct be_client *becli,
- struct be_ctx *be_ctx,
- struct be_acct_req *ar)
-{
- struct tevent_req *req;
- struct be_get_account_info_state *state;
- struct be_req *be_req;
- errno_t ret;
-
- req = tevent_req_create(mem_ctx, &state,
- struct be_get_account_info_state);
- if (!req) return NULL;
-
- be_req = be_req_create(state, becli, be_ctx, "get account info",
- be_get_account_info_done, req);
- if (!be_req) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = be_req_set_domain(be_req, ar->domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set request domain [%d]: %s\n",
- ret, sss_strerror(ret));
- goto done;
- }
-
- ret = be_file_account_request(be_req, ar);
- if (ret != EOK) {
- goto done;
- }
-
- return req;
-
-done:
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- return req;
-}
-
-static void
-be_get_account_info_done(struct be_req *be_req,
- int dp_err, int dp_ret,
- const char *errstr)
+static errno_t be_check_online_request(struct be_ctx *be_ctx)
{
struct tevent_req *req;
- struct be_get_account_info_state *state;
-
- req = talloc_get_type(be_req->pvt, struct tevent_req);
- state = tevent_req_data(req, struct be_get_account_info_state);
-
- state->err_maj = dp_err;
- state->err_min = dp_ret;
- if (errstr) {
- state->err_msg = talloc_strdup(state, errstr);
- if (state->err_msg == NULL) {
- talloc_free(be_req);
- tevent_req_error(req, ENOMEM);
- return;
- }
- }
- talloc_free(be_req);
- tevent_req_done(req);
-}
-
-errno_t be_get_account_info_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- int *_err_maj,
- int *_err_min,
- const char **_err_msg)
-{
- struct be_get_account_info_state *state;
-
- state = tevent_req_data(req, struct be_get_account_info_state);
-
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- if (_err_maj) {
- *_err_maj = state->err_maj;
- }
-
- if (_err_min) {
- *_err_min = state->err_min;
- }
+ be_ctx->offstat.went_offline = time(NULL);
+ reset_fo(be_ctx);
- if (_err_msg) {
- *_err_msg = talloc_steal(mem_ctx, state->err_msg);
- }
-
- return EOK;
-}
-
-static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
-{
- struct be_acct_req *req;
- struct be_req *be_req;
- struct be_client *becli;
- uint32_t type;
- char *filter;
- char *domain;
- uint32_t attr_type;
- int ret;
- struct be_sbus_reply_data req_reply = BE_SBUS_REPLY_DATA_INIT;
-
- be_req = NULL;
-
- becli = talloc_get_type(user_data, struct be_client);
- if (!becli) return EINVAL;
-
- if (!sbus_request_parse_or_finish(dbus_req,
- DBUS_TYPE_UINT32, &type,
- DBUS_TYPE_UINT32, &attr_type,
- DBUS_TYPE_STRING, &filter,
- DBUS_TYPE_STRING, &domain,
- DBUS_TYPE_INVALID))
- return EOK; /* handled */
-
- DEBUG(SSSDBG_FUNC_DATA,
- "Got request for [%#x][%s][%d][%s]\n", type, be_req2str(type),
- attr_type, filter);
-
- /* If we are offline and fast reply was requested
- * return offline immediately
- */
- if ((type & BE_REQ_FAST) && becli->bectx->offstat.offline) {
- ret = be_offline_reply(&dbus_req);
- if (ret != EOK) {
- return ret;
- }
-
- /* This reply will be queued and sent
- * when we reenter the mainloop.
- *
- * Continue processing in case we are
- * going back online.
- */
- }
-
- be_req = be_req_create(becli, becli, becli->bectx, "get account info",
- be_req_default_callback, dbus_req);
- if (!be_req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- ret = be_req_set_domain(be_req, domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set request domain [%d]: %s\n",
- ret, sss_strerror(ret));
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL,
- ret, sss_strerror(ret));
- goto done;
- }
-
- req = talloc_zero(be_req, struct be_acct_req);
- if (!req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
- req->entry_type = type;
- req->attr_type = (int)attr_type;
- req->domain = talloc_strdup(req, domain);
- if (!req->domain) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- if ((attr_type != BE_ATTR_CORE) &&
- (attr_type != BE_ATTR_MEM) &&
- (attr_type != BE_ATTR_ALL)) {
- /* Unrecognized attr type */
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Invalid Attrs Parameter");
- goto done;
- }
-
- if (filter) {
- ret = EOK;
- if (strncmp(filter, "name=", 5) == 0) {
- req->filter_type = BE_FILTER_NAME;
- ret = split_name_extended(req, &filter[5],
- &req->filter_value,
- &req->extra_value);
- } else if (strncmp(filter, "idnumber=", 9) == 0) {
- req->filter_type = BE_FILTER_IDNUM;
- ret = split_name_extended(req, &filter[9],
- &req->filter_value,
- &req->extra_value);
- } else if (strncmp(filter, DP_SEC_ID"=", DP_SEC_ID_LEN + 1) == 0) {
- req->filter_type = BE_FILTER_SECID;
- ret = split_name_extended(req, &filter[DP_SEC_ID_LEN + 1],
- &req->filter_value,
- &req->extra_value);
- } else if (strncmp(filter, DP_CERT"=", DP_CERT_LEN + 1) == 0) {
- req->filter_type = BE_FILTER_CERT;
- ret = split_name_extended(req, &filter[DP_CERT_LEN + 1],
- &req->filter_value,
- &req->extra_value);
- } else if (strncmp(filter, DP_WILDCARD"=", DP_WILDCARD_LEN + 1) == 0) {
- req->filter_type = BE_FILTER_WILDCARD;
- ret = split_name_extended(req, &filter[DP_WILDCARD_LEN + 1],
- &req->filter_value,
- &req->extra_value);
- } else if (strcmp(filter, ENUM_INDICATOR) == 0) {
- req->filter_type = BE_FILTER_ENUM;
- req->filter_value = NULL;
- req->extra_value = NULL;
- } else {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Invalid filter");
- goto done;
- }
-
- if (ret != EOK) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Invalid filter");
- goto done;
- }
-
- } else {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Missing filter parameter");
- goto done;
- }
-
- ret = be_file_account_request(be_req, req);
- if (ret != EOK) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Cannot file account request");
- goto done;
+ req = dp_req_send(be_ctx, be_ctx->provider, NULL, NULL, "Online Check",
+ DPT_ID, DPM_CHECK_ONLINE, 0, NULL, NULL);
+ if (req == NULL) {
+ return ENOMEM;
}
- return EOK;
+ tevent_req_set_callback(req, be_check_online_done, be_ctx);
-done:
- talloc_free(be_req);
- be_sbus_req_reply_data(dbus_req, &req_reply);
return EOK;
}
-static void be_pam_handler_callback(struct be_req *req,
- int dp_err_type,
- int errnum,
- const char *errstr)
+static void be_check_online_done(struct tevent_req *req)
{
- struct be_client *becli = req->becli;
- struct sbus_request *dbus_req;
- struct pam_data *pd;
- DBusMessage *reply;
- dbus_bool_t dbret;
+ struct be_ctx *be_ctx;
+ struct dp_reply_std reply;
errno_t ret;
- DEBUG(SSSDBG_CONF_SETTINGS, "Backend returned: (%d, %d, %s) [%s]\n",
- dp_err_type, errnum, errstr?errstr:"<NULL>",
- dp_err_to_string(dp_err_type));
-
- pd = talloc_get_type(be_req_get_data(req), struct pam_data);
-
- if (pd->cmd == SSS_PAM_ACCT_MGMT &&
- pd->pam_status == PAM_SUCCESS &&
- req->phase == REQ_PHASE_ACCESS &&
- dp_err_type == DP_ERR_OK) {
- if (!becli->bectx->bet_info[BET_SELINUX].bet_ops) {
- DEBUG(SSSDBG_TRACE_FUNC,
- "SELinux provider doesn't exist, "
- "not sending the request to it.\n");
- } else {
- req->phase = REQ_PHASE_SELINUX;
-
- /* Now is the time to call SELinux provider */
- ret = be_file_request(becli->bectx->bet_info[BET_SELINUX].pvt_bet_data,
- req,
- becli->bectx->bet_info[BET_SELINUX].bet_ops->handler);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "be_file_request failed.\n");
- goto done;
- }
- return;
- }
- }
-
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Sending result [%d][%s]\n", pd->pam_status, pd->domain);
- dbus_req = (struct sbus_request *)req->pvt;
- reply = dbus_message_new_method_return(dbus_req->message);
- if (reply == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "dbus_message_new_method_return failed, cannot send reply.\n");
- goto done;
- }
-
- dbret = dp_pack_pam_response(reply, pd);
- if (!dbret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
- dbus_message_unref(reply);
- goto done;
- }
-
- sbus_request_finish(dbus_req, reply);
- dbus_message_unref(reply);
-
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Sent result [%d][%s]\n", pd->pam_status, pd->domain);
-
-done:
- talloc_free(req);
-}
-
-static int be_pam_handler(struct sbus_request *dbus_req, void *user_data)
-{
- DBusError dbus_error;
- DBusMessage *reply;
- struct be_client *becli;
- dbus_bool_t ret;
- struct pam_data *pd = NULL;
- struct be_req *be_req = NULL;
- enum bet_type target = BET_NULL;
-
- becli = talloc_get_type(user_data, struct be_client);
- if (!becli) return EINVAL;
-
- be_req = be_req_create(becli, becli, becli->bectx, "PAM",
- be_pam_handler_callback, dbus_req);
- if (!be_req) {
- DEBUG(SSSDBG_TRACE_LIBS, "talloc_zero failed.\n");
- return ENOMEM;
- }
-
- dbus_error_init(&dbus_error);
-
- ret = dp_unpack_pam_request(dbus_req->message, be_req, &pd, &dbus_error);
- if (!ret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse message!\n");
- talloc_free(be_req);
- return EIO;
- }
-
- pd->pam_status = PAM_SYSTEM_ERR;
- if (pd->domain == NULL) {
- pd->domain = talloc_strdup(pd, becli->bectx->domain->name);
- if (pd->domain == NULL) {
- talloc_free(be_req);
- return ENOMEM;
- }
- }
-
- ret = be_req_set_domain(be_req, pd->domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set request domain [%d]: %s\n",
- ret, sss_strerror(ret));
- pd->pam_status = PAM_SYSTEM_ERR;
- goto done;
- }
-
- DEBUG(SSSDBG_CONF_SETTINGS, "Got request with the following data\n");
- DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
-
- switch (pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- case SSS_PAM_PREAUTH:
- target = BET_AUTH;
- break;
- case SSS_PAM_ACCT_MGMT:
- target = BET_ACCESS;
- be_req->phase = REQ_PHASE_ACCESS;
- break;
- case SSS_PAM_CHAUTHTOK:
- case SSS_PAM_CHAUTHTOK_PRELIM:
- target = BET_CHPASS;
- break;
- case SSS_PAM_OPEN_SESSION:
- case SSS_PAM_SETCRED:
- case SSS_PAM_CLOSE_SESSION:
- pd->pam_status = PAM_SUCCESS;
- goto done;
- break;
- default:
- DEBUG(SSSDBG_TRACE_LIBS,
- "Unsupported PAM command [%d].\n", pd->cmd);
- pd->pam_status = PAM_MODULE_UNKNOWN;
- goto done;
- }
+ be_ctx = tevent_req_callback_data(req, struct be_ctx);
- /* return PAM_MODULE_UNKNOWN if corresponding backend target is not
- * configured
- */
- if (!becli->bectx->bet_info[target].bet_ops) {
- DEBUG(SSSDBG_TRACE_LIBS, "Undefined backend target.\n");
- pd->pam_status = PAM_MODULE_UNKNOWN;
- goto done;
- }
-
- be_req->req_data = pd;
-
- ret = be_file_request(becli->bectx->bet_info[target].pvt_bet_data,
- be_req,
- becli->bectx->bet_info[target].bet_ops->handler);
+ ret = dp_req_recv_ptr(be_ctx, req, struct dp_reply_std, &reply);
+ talloc_zfree(req);
if (ret != EOK) {
- DEBUG(SSSDBG_TRACE_LIBS, "be_file_request failed.\n");
goto done;
}
- return EOK;
-
-done:
-
- DEBUG(SSSDBG_CONF_SETTINGS, "Sending result [%d][%s]\n",
- pd->pam_status, pd->domain);
-
- reply = dbus_message_new_method_return(dbus_req->message);
- if (reply == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "dbus_message_new_method_return failed, cannot send reply.\n");
- return ENOMEM;
- }
-
- ret = dp_pack_pam_response(reply, pd);
- if (!ret) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to generate dbus reply\n");
- talloc_free(be_req);
- dbus_message_unref(reply);
- return EIO;
- }
-
- /* send reply back immediately */
- sbus_request_finish(dbus_req, reply);
- dbus_message_unref(reply);
-
- talloc_free(be_req);
-
- return EOK;
-}
-
-static int be_sudo_handler(struct sbus_request *dbus_req, void *user_data)
-{
- DBusError dbus_error;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- struct be_client *be_cli = NULL;
- struct be_req *be_req = NULL;
- struct be_sudo_req *sudo_req = NULL;
- int ret = 0;
- uint32_t type;
- uint32_t rules_num = 0;
- const char *rule = NULL;
- const char *err_msg = NULL;
- int i;
-
- DEBUG(SSSDBG_TRACE_FUNC, "Entering be_sudo_handler()\n");
-
- be_cli = talloc_get_type(user_data, struct be_client);
- if (be_cli == NULL) {
- return EINVAL;
- }
-
- /* create be request */
- be_req = be_req_create(be_cli, be_cli, be_cli->bectx, "sudo",
- be_req_default_callback, dbus_req);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- return ENOMEM;
- }
-
- dbus_error_init(&dbus_error);
- dbus_message_iter_init(dbus_req->message, &iter);
-
- /* get type of the request */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
- ret = EIO;
- err_msg = "Invalid D-Bus message format";
- goto fail;
- }
- dbus_message_iter_get_basic(&iter, &type);
- dbus_message_iter_next(&iter); /* step behind the request type */
-
- /* If we are offline and fast reply was requested
- * return offline immediately
- */
- if ((type & BE_REQ_FAST) && be_cli->bectx->offstat.offline) {
- be_offline_reply(&dbus_req);
- be_req->pvt = NULL;
- /* This reply will be queued and sent
- * when we reenter the mainloop.
- *
- * Continue processing in case we are
- * going back online.
- */
- }
-
- /* get and set sudo request data */
- sudo_req = talloc_zero(be_req, struct be_sudo_req);
- if (sudo_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- goto fail;
- }
-
- sudo_req->type = (~BE_REQ_FAST) & type;
-
- /* get additional arguments according to the request type */
- switch (sudo_req->type) {
- case BE_REQ_SUDO_FULL:
- /* no arguments required */
+ switch (reply.dp_error) {
+ case DP_ERR_OK:
+ DEBUG(SSSDBG_TRACE_FUNC, "Backend is online\n");
break;
- case BE_REQ_SUDO_RULES:
- /* additional arguments:
- * rules_num
- * rules[rules_num]
- */
- /* read rules_num */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
- ret = EIO;
- err_msg = "Invalid D-Bus message format";
- goto fail;
- }
-
- dbus_message_iter_get_basic(&iter, &rules_num);
-
- sudo_req->rules = talloc_array(sudo_req, char*, rules_num + 1);
- if (sudo_req->rules == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
- ret = ENOMEM;
- goto fail;
- }
-
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
- ret = EIO;
- err_msg = "Invalid D-Bus message format";
- goto fail;
- }
-
- dbus_message_iter_recurse(&iter, &array_iter);
-
- /* read the rules */
- for (i = 0; i < rules_num; i++) {
- if (dbus_message_iter_get_arg_type(&array_iter)
- != DBUS_TYPE_STRING) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
- ret = EIO;
- err_msg = "Invalid D-Bus message format";
- goto fail;
- }
-
- dbus_message_iter_get_basic(&array_iter, &rule);
- sudo_req->rules[i] = talloc_strdup(sudo_req->rules, rule);
- if (sudo_req->rules[i] == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
- ret = ENOMEM;
- goto fail;
- }
-
- dbus_message_iter_next(&array_iter);
- }
-
- sudo_req->rules[rules_num] = NULL;
-
+ case DP_ERR_OFFLINE:
+ DEBUG(SSSDBG_TRACE_FUNC, "Backend is offline\n");
break;
default:
- DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type %d\n", sudo_req->type);
- ret = EINVAL;
- err_msg = "Invalid DP request type";
- goto fail;
- }
-
- be_req->req_data = sudo_req;
-
- /* return an error if corresponding backend target is not configured */
- if (!be_cli->bectx->bet_info[BET_SUDO].bet_ops) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Undefined backend target.\n");
- ret = ENODEV;
- goto fail;
- }
-
- ret = be_file_request(be_cli->bectx->bet_info[BET_SUDO].pvt_bet_data,
- be_req,
- be_cli->bectx->bet_info[BET_SUDO].bet_ops->handler);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_file_request failed.\n");
- err_msg = "Cannot file back end request";
- goto fail;
- }
-
- return EOK;
-
-fail:
- /* send reply back immediately */
- be_req_default_callback(be_req, DP_ERR_FATAL, ret,
- err_msg ? err_msg : strerror(ret));
- return EOK;
-}
-
-static int be_autofs_handler(struct sbus_request *dbus_req, void *user_data)
-{
- struct be_client *be_cli = NULL;
- struct be_req *be_req = NULL;
- struct be_autofs_req *be_autofs_req = NULL;
- int ret = 0;
- uint32_t type;
- char *filter;
- char *filter_val;
- struct be_sbus_reply_data req_reply = BE_SBUS_REPLY_DATA_INIT;
-
- DEBUG(SSSDBG_TRACE_FUNC, "Entering be_autofs_handler()\n");
-
- be_cli = talloc_get_type(user_data, struct be_client);
- if (be_cli == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get back end client context\n");
- return EINVAL;
- }
-
- if (!sbus_request_parse_or_finish(dbus_req,
- DBUS_TYPE_UINT32, &type,
- DBUS_TYPE_STRING, &filter,
- DBUS_TYPE_INVALID))
- return EOK; /* handled */
-
- /* If we are offline and fast reply was requested
- * return offline immediately
- */
- if ((type & BE_REQ_FAST) && be_cli->bectx->offstat.offline) {
- be_offline_reply(&dbus_req);
- /* This reply will be queued and sent
- * when we reenter the mainloop.
- *
- * Continue processing in case we are
- * going back online.
- */
- }
-
- if (filter) {
- if (strncmp(filter, "mapname=", 8) == 0) {
- filter_val = &filter[8];
- } else {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Invalid filter");
- goto done;
- }
- } else {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Missing filter parameter");
- goto done;
- }
-
- /* create be request */
- be_req = be_req_create(be_cli, be_cli, be_cli->bectx, "autofs",
- be_req_default_callback, dbus_req);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- /* set autofs request data */
- be_autofs_req = talloc_zero(be_req, struct be_autofs_req);
- if (be_autofs_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- be_autofs_req->mapname = talloc_strdup(be_autofs_req, filter_val);
- if (be_autofs_req->mapname == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- be_req->req_data = be_autofs_req;
-
- if (!be_cli->bectx->bet_info[BET_AUTOFS].bet_ops) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Undefined backend target.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENODEV,
- "Autofs back end target is not configured");
- goto done;
- }
-
- ret = be_file_request(be_cli->bectx->bet_info[BET_AUTOFS].pvt_bet_data,
- be_req,
- be_cli->bectx->bet_info[BET_AUTOFS].bet_ops->handler);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_file_request failed.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ret,
- "Cannot file back end request");
- goto done;
- }
-
- return EOK;
-
-done:
- talloc_free(be_req);
- be_sbus_req_reply_data(dbus_req, &req_reply);
- return EOK;
-}
-
-static int be_host_handler(struct sbus_request *dbus_req, void *user_data)
-{
- struct be_host_req *req;
- struct be_req *be_req;
- struct be_client *becli;
- uint32_t flags;
- char *filter;
- int ret;
- struct be_sbus_reply_data req_reply = BE_SBUS_REPLY_DATA_INIT;
-
- be_req = NULL;
-
- becli = talloc_get_type(user_data, struct be_client);
- if (!becli) return EINVAL;
-
- if (!sbus_request_parse_or_finish(dbus_req,
- DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_STRING, &filter,
- DBUS_TYPE_INVALID))
- return EOK; /* request finished */
-
- DEBUG(SSSDBG_TRACE_LIBS,
- "Got request for [%u][%s]\n", flags, filter);
-
- /* If we are offline and fast reply was requested
- * return offline immediately
- */
- if ((flags & BE_REQ_FAST) && becli->bectx->offstat.offline) {
- /* Send back an immediate reply */
- be_offline_reply(&dbus_req);
-
- /* This reply will be queued and sent
- * when we reenter the mainloop.
- *
- * Continue processing in case we are
- * going back online.
- */
- }
-
- be_req = be_req_create(becli, becli, becli->bectx, "hostinfo",
- be_req_default_callback, dbus_req);
- if (!be_req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
-
- req = talloc(be_req, struct be_host_req);
- if (!req) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENOMEM,
- "Out of memory");
- goto done;
- }
- req->type = BE_REQ_HOST | (flags & BE_REQ_FAST);
-
- be_req->req_data = req;
-
- if (filter) {
- ret = strncmp(filter, "name=", 5);
- if (ret == 0) {
- req->filter_type = BE_FILTER_NAME;
- ret = split_name_extended(req, &filter[5],
- &req->name,
- &req->alias);
- }
-
- if (ret) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Invalid filter");
- goto done;
- }
- } else {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, EINVAL,
- "Missing filter parameter");
- goto done;
- }
-
- /* process request */
-
- if (!becli->bectx->bet_info[BET_HOSTID].bet_ops) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Undefined backend target.\n");
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ENODEV,
- "HostID back end target is not configured");
- goto done;
- }
-
- ret = be_file_request(becli->bectx->bet_info[BET_HOSTID].pvt_bet_data,
- be_req,
- becli->bectx->bet_info[BET_HOSTID].bet_ops->handler);
- if (ret != EOK) {
- be_sbus_reply_data_set(&req_reply, DP_ERR_FATAL, ret,
- "Cannot file back end request");
- goto done;
- }
-
- return EOK;
-
-done:
- talloc_free(be_req);
- be_sbus_req_reply_data(dbus_req, &req_reply);
- return EOK;
-}
-
-static int be_client_destructor(void *ctx)
-{
- struct be_client *becli = talloc_get_type(ctx, struct be_client);
- if (becli->bectx) {
- if (becli->bectx->nss_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed NSS client\n");
- becli->bectx->nss_cli = NULL;
- } else if (becli->bectx->pam_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed PAM client\n");
- becli->bectx->pam_cli = NULL;
- } else if (becli->bectx->sudo_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed SUDO client\n");
- becli->bectx->sudo_cli = NULL;
- } else if (becli->bectx->autofs_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed autofs client\n");
- becli->bectx->autofs_cli = NULL;
- } else if (becli->bectx->ssh_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed SSH client\n");
- becli->bectx->ssh_cli = NULL;
- } else if (becli->bectx->pac_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed PAC client\n");
- becli->bectx->pac_cli = NULL;
- } else if (becli->bectx->ifp_cli == becli) {
- DEBUG(SSSDBG_TRACE_FUNC, "Removed IFP client\n");
- becli->bectx->ifp_cli = NULL;
- } else {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown client removed ...\n");
- }
- }
- return 0;
-}
-
-static int client_registration(struct sbus_request *dbus_req, void *data)
-{
- dbus_uint16_t version = DATA_PROVIDER_VERSION;
- struct sbus_connection *conn;
- struct be_client *becli;
- DBusError dbus_error;
- dbus_uint16_t cli_ver;
- char *cli_name;
- dbus_bool_t dbret;
- int ret;
-
- conn = dbus_req->conn;
- becli = talloc_get_type(data, struct be_client);
- if (!becli) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
- return EINVAL;
- }
-
- /* First thing, cancel the timeout */
- DEBUG(SSSDBG_CONF_SETTINGS, "Cancel DP ID timeout [%p]\n", becli->timeout);
- talloc_zfree(becli->timeout);
-
- dbus_error_init(&dbus_error);
-
- dbret = dbus_message_get_args(dbus_req->message, &dbus_error,
- DBUS_TYPE_UINT16, &cli_ver,
- DBUS_TYPE_STRING, &cli_name,
- DBUS_TYPE_INVALID);
- if (!dbret) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failed to parse message, killing connection\n");
- if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
- sbus_disconnect(conn);
- /* FIXME: should we just talloc_zfree(conn) ? */
- return EIO;
- }
-
- if (strcasecmp(cli_name, "NSS") == 0) {
- becli->bectx->nss_cli = becli;
- } else if (strcasecmp(cli_name, "PAM") == 0) {
- becli->bectx->pam_cli = becli;
- } else if (strcasecmp(cli_name, "SUDO") == 0) {
- becli->bectx->sudo_cli = becli;
- } else if (strcasecmp(cli_name, "autofs") == 0) {
- becli->bectx->autofs_cli = becli;
- } else if (strcasecmp(cli_name, "SSH") == 0) {
- becli->bectx->ssh_cli = becli;
- } else if (strcasecmp(cli_name, "PAC") == 0) {
- becli->bectx->pac_cli = becli;
- } else if (strcasecmp(cli_name, "InfoPipe") == 0) {
- becli->bectx->ifp_cli = becli;
- } else {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown client! [%s]\n", cli_name);
- }
- talloc_set_destructor((TALLOC_CTX *)becli, be_client_destructor);
-
- DEBUG(SSSDBG_CONF_SETTINGS, "Added Frontend client [%s]\n", cli_name);
-
- /* reply that all is ok */
- ret = sbus_request_return_and_finish(dbus_req,
- DBUS_TYPE_UINT16, &version,
- DBUS_TYPE_INVALID);
- if (ret != EOK) {
- sbus_disconnect(conn);
- return ret;
- }
-
- becli->initialized = true;
- return EOK;
-}
-
-static errno_t be_file_check_online_request(struct be_req *req)
-{
- int ret;
-
- req->be_ctx->offstat.went_offline = time(NULL);
- reset_fo(req->be_ctx);
-
- ret = be_file_request(req->be_ctx, req,
- req->be_ctx->bet_info[BET_ID].bet_ops->check_online);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_file_request failed.\n");
+ DEBUG(SSSDBG_TRACE_FUNC, "Error during online check [%d]: %s\n",
+ ret, sss_strerror(ret));
+ break;
}
- return ret;
-}
+ be_ctx->check_online_ref_count--;
-static void check_online_callback(struct be_req *req, int dp_err_type,
- int errnum, const char *errstr)
-{
- int ret;
-
- DEBUG(SSSDBG_CONF_SETTINGS, "Backend returned: (%d, %d, %s) [%s]\n",
- dp_err_type, errnum, errstr?errstr:"<NULL>",
- dp_err_to_string(dp_err_type));
-
- req->be_ctx->check_online_ref_count--;
-
- if (dp_err_type != DP_ERR_OK && req->be_ctx->check_online_ref_count > 0) {
- ret = be_file_check_online_request(req);
+ if (reply.dp_error != DP_ERR_OK && be_ctx->check_online_ref_count > 0) {
+ ret = be_check_online_request(be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "be_file_check_online_request failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create check online req.\n");
goto done;
}
return;
}
done:
- req->be_ctx->check_online_ref_count = 0;
- if (dp_err_type != DP_ERR_OFFLINE) {
- if (dp_err_type != DP_ERR_OK) {
- reset_fo(req->be_ctx);
+ be_ctx->check_online_ref_count = 0;
+ if (reply.dp_error != DP_ERR_OFFLINE) {
+ if (reply.dp_error != DP_ERR_OK) {
+ reset_fo(be_ctx);
}
- be_reset_offline(req->be_ctx);
+ be_reset_offline(be_ctx);
}
-
- talloc_free(req);
-
- return;
}
-static void check_if_online(struct be_ctx *ctx)
+static void check_if_online(struct be_ctx *be_ctx)
{
- int ret;
- struct be_req *be_req = NULL;
+ errno_t ret;
- be_run_unconditional_online_cb(ctx);
+ be_run_unconditional_online_cb(be_ctx);
- if (ctx->offstat.offline == false) {
+ if (!be_is_offline(be_ctx)) {
DEBUG(SSSDBG_TRACE_INTERNAL,
"Backend is already online, nothing to do.\n");
return;
}
/* Make sure nobody tries to go online while we are checking */
- ctx->offstat.went_offline = time(NULL);
+ be_ctx->offstat.went_offline = time(NULL);
DEBUG(SSSDBG_TRACE_INTERNAL, "Trying to go back online!\n");
- ctx->check_online_ref_count++;
+ be_ctx->check_online_ref_count++;
- if (ctx->check_online_ref_count != 1) {
+ if (be_ctx->check_online_ref_count != 1) {
DEBUG(SSSDBG_TRACE_INTERNAL,
"There is an online check already running.\n");
return;
}
- if (ctx->bet_info[BET_ID].bet_ops->check_online == NULL) {
+ if (!dp_method_enabled(be_ctx->provider, DPT_ID, DPM_CHECK_ONLINE)) {
DEBUG(SSSDBG_TRACE_INTERNAL,
"ID providers does not provide a check_online method.\n");
goto failed;
}
- be_req = be_req_create(ctx, NULL, ctx, "online check",
- check_online_callback, NULL);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- goto failed;
- }
-
- ret = be_file_check_online_request(be_req);
+ ret = be_check_online_request(be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_file_check_online_request failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create check online req.\n");
goto failed;
}
return;
failed:
- ctx->check_online_ref_count--;
+ be_ctx->check_online_ref_count--;
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to run a check_online test.\n");
- talloc_free(be_req);
-
- if (ctx->check_online_ref_count == 0) {
- reset_fo(ctx);
- be_reset_offline(ctx);
+ if (be_ctx->check_online_ref_count == 0) {
+ reset_fo(be_ctx);
+ be_reset_offline(be_ctx);
}
return;
}
-static void init_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *ptr)
-{
- struct be_client *becli;
-
- DEBUG(SSSDBG_OP_FAILURE,
- "Client timed out before Identification [%p]!\n", te);
-
- becli = talloc_get_type(ptr, struct be_client);
-
- sbus_disconnect(becli->conn);
- talloc_zfree(becli);
-}
-
-static int be_client_init(struct sbus_connection *conn, void *data)
-{
- struct be_ctx *bectx;
- struct be_client *becli;
- struct timeval tv;
-
- bectx = talloc_get_type(data, struct be_ctx);
-
- /* hang off this memory to the connection so that when the connection
- * is freed we can potentially call a destructor */
-
- becli = talloc(conn, struct be_client);
- if (!becli) {
- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
- talloc_zfree(conn);
- return ENOMEM;
- }
- becli->bectx = bectx;
- becli->conn = conn;
- becli->initialized = false;
-
- /* Allow access from the SSSD user */
- sbus_allow_uid(conn, &bectx->uid);
-
- /* 5 seconds should be plenty */
- tv = tevent_timeval_current_ofs(5, 0);
-
- becli->timeout = tevent_add_timer(bectx->ev, becli,
- tv, init_timeout, becli);
- if (!becli->timeout) {
- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
- talloc_zfree(conn);
- return ENOMEM;
- }
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Set-up Backend ID timeout [%p]\n", becli->timeout);
-
- return sbus_conn_register_iface(conn, &be_methods.vtable, DP_PATH, becli);
-}
-
-/* be_srv_init
- * set up per-domain sbus channel */
-static int be_srv_init(struct be_ctx *ctx,
- uid_t uid, gid_t gid)
-{
- char *sbus_address;
- int ret;
-
- /* Set up SBUS connection to the monitor */
- ret = dp_get_sbus_address(ctx, &sbus_address, ctx->domain->name);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not get sbus backend address.\n");
- return ret;
- }
-
- ctx->uid = uid;
- ctx->gid = gid;
-
- ret = sbus_new_server(ctx, ctx->ev, sbus_address, uid, gid,
- true, &ctx->sbus_srv, be_client_init, ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
- return ret;
- }
-
- return EOK;
-}
-
-static void be_target_access_permit(struct be_req *be_req)
-{
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(be_req), struct pam_data);
- DEBUG(SSSDBG_TRACE_ALL,
- "be_target_access_permit called, returning PAM_SUCCESS.\n");
-
- pd->pam_status = PAM_SUCCESS;
- be_req_terminate(be_req, DP_ERR_OK, PAM_SUCCESS, NULL);
-}
-
-static struct bet_ops be_target_access_permit_ops = {
- .check_online = NULL,
- .handler = be_target_access_permit,
- .finalize = NULL
-};
-
-static void be_target_access_deny(struct be_req *be_req)
-{
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(be_req), struct pam_data);
- DEBUG(SSSDBG_TRACE_ALL,
- "be_target_access_deny called, returning PAM_PERM_DENIED.\n");
-
- pd->pam_status = PAM_PERM_DENIED;
- be_req_terminate(be_req, DP_ERR_OK, PAM_PERM_DENIED, NULL);
-}
-
-static struct bet_ops be_target_access_deny_ops = {
- .check_online = NULL,
- .handler = be_target_access_deny,
- .finalize = NULL
-};
-
-static int load_backend_module(struct be_ctx *ctx,
- enum bet_type bet_type,
- struct bet_info *bet_info,
- const char *default_mod_name)
-{
- TALLOC_CTX *tmp_ctx;
- int ret = EINVAL;
- bool already_loaded = false;
- int lb=0;
- char *mod_name = NULL;
- char *path = NULL;
- void *handle;
- char *mod_init_fn_name = NULL;
- bet_init_fn_t mod_init_fn = NULL;
-
- (*bet_info).bet_type = bet_type;
- (*bet_info).mod_name = NULL;
- (*bet_info).bet_ops = NULL;
- (*bet_info).pvt_bet_data = NULL;
-
- if (bet_type <= BET_NULL || bet_type >= BET_MAX ||
- bet_type != bet_data[bet_type].bet_type) {
- DEBUG(SSSDBG_OP_FAILURE, "invalid bet_type or bet_data corrupted.\n");
- return EINVAL;
- }
-
- tmp_ctx = talloc_new(ctx);
- if (!tmp_ctx) {
- DEBUG(SSSDBG_TRACE_LIBS, "talloc_new failed.\n");
- return ENOMEM;
- }
-
- ret = confdb_get_string(ctx->cdb, tmp_ctx, ctx->conf_path,
- bet_data[bet_type].option_name, NULL,
- &mod_name);
- if (ret != EOK) {
- ret = EFAULT;
- goto done;
- }
- if (!mod_name) {
- if (default_mod_name != NULL) {
- DEBUG(SSSDBG_FUNC_DATA,
- "no module name found in confdb, using [%s].\n",
- default_mod_name);
- mod_name = talloc_strdup(ctx, default_mod_name);
- } else {
- ret = ENOENT;
- goto done;
- }
- }
-
- if (strcasecmp(mod_name, NO_PROVIDER) == 0) {
- ret = ENOENT;
- goto done;
- }
-
- if (bet_type == BET_ACCESS) {
- if (strcmp(mod_name, ACCESS_PERMIT) == 0) {
- (*bet_info).bet_ops = &be_target_access_permit_ops;
- (*bet_info).pvt_bet_data = NULL;
- (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_PERMIT);
-
- ret = EOK;
- goto done;
- }
- if (strcmp(mod_name, ACCESS_DENY) == 0) {
- (*bet_info).bet_ops = &be_target_access_deny_ops;
- (*bet_info).pvt_bet_data = NULL;
- (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_DENY);
-
- ret = EOK;
- goto done;
- }
- }
-
- mod_init_fn_name = talloc_asprintf(tmp_ctx,
- bet_data[bet_type].mod_init_fn_name_fmt,
- mod_name);
- if (mod_init_fn_name == NULL) {
- DEBUG(SSSDBG_TRACE_LIBS, "talloc_asprintf failed\n");
- ret = ENOMEM;
- goto done;
- }
-
-
- lb = 0;
- while(ctx->loaded_be[lb].be_name != NULL) {
- if (strncmp(ctx->loaded_be[lb].be_name, mod_name,
- strlen(mod_name)) == 0) {
- DEBUG(SSSDBG_TRACE_LIBS,
- "Backend [%s] already loaded.\n", mod_name);
- already_loaded = true;
- break;
- }
-
- ++lb;
- if (lb >= BET_MAX) {
- DEBUG(SSSDBG_OP_FAILURE, "Backend context corrupted.\n");
- ret = EINVAL;
- goto done;
- }
- }
-
- if (!already_loaded) {
- path = talloc_asprintf(tmp_ctx, "%s/libsss_%s.so",
- DATA_PROVIDER_PLUGINS_PATH, mod_name);
- if (!path) {
- ret = ENOMEM;
- goto done;
- }
-
- DEBUG(SSSDBG_TRACE_LIBS,
- "Loading backend [%s] with path [%s].\n", mod_name, path);
- handle = dlopen(path, RTLD_NOW);
- if (!handle) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Unable to load %s module with path (%s), error: %s\n",
- mod_name, path, dlerror());
- ret = ELIBACC;
- goto done;
- }
-
- ctx->loaded_be[lb].be_name = talloc_strdup(ctx, mod_name);
- ctx->loaded_be[lb].handle = handle;
- }
-
- mod_init_fn = (bet_init_fn_t)dlsym(ctx->loaded_be[lb].handle,
- mod_init_fn_name);
- if (mod_init_fn == NULL) {
- if (default_mod_name != NULL &&
- strcmp(default_mod_name, mod_name) == 0 ) {
- /* If the default is used and fails we indicate this to the caller
- * by returning ENOENT. Ths way the caller can decide how to
- * handle the different types of error conditions. */
- ret = ENOENT;
- } else {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Unable to load init fn %s from module %s, error: %s\n",
- mod_init_fn_name, mod_name, dlerror());
- ret = ELIBBAD;
- }
- goto done;
- }
-
- ret = mod_init_fn(ctx, &(*bet_info).bet_ops, &(*bet_info).pvt_bet_data);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Error (%d) in module (%s) initialization (%s)!\n",
- ret, mod_name, mod_init_fn_name);
- goto done;
- }
-
- (*bet_info).mod_name = talloc_strdup(ctx, mod_name);
-
- ret = EOK;
-
-done:
- talloc_free(tmp_ctx);
- return ret;
-}
-
static void signal_be_offline(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
@@ -2421,308 +366,119 @@ static void signal_be_reset_offline(struct tevent_context *ev,
check_if_online(ctx);
}
-int be_process_init_sudo(struct be_ctx *be_ctx)
-{
- TALLOC_CTX *tmp_ctx = NULL;
- char **services = NULL;
- char *provider = NULL;
- bool responder_enabled = false;
- int i;
- int ret;
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
- return ENOMEM;
- }
-
- ret = confdb_get_string_as_list(be_ctx->cdb, tmp_ctx,
- CONFDB_MONITOR_CONF_ENTRY,
- CONFDB_MONITOR_ACTIVE_SERVICES, &services);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n",
- ret, strerror(ret));
- goto done;
- }
-
- for (i = 0; services[i] != NULL; i++) {
- if (strcmp(services[i], "sudo") == 0) {
- responder_enabled = true;
- break;
- }
- }
-
- ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
- CONFDB_DOMAIN_SUDO_PROVIDER, NULL, &provider);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n",
- ret, strerror(ret));
- goto done;
- }
-
- if (!responder_enabled && provider == NULL) {
- /* provider is not set explicitly */
- DEBUG(SSSDBG_TRACE_FUNC,
- "SUDO is not listed in services, disabling SUDO module.\n");
- ret = ENOENT;
- goto done;
- }
-
- if (!responder_enabled && provider != NULL
- && strcmp(provider, NO_PROVIDER) != 0) {
- /* provider is set but responder is disabled */
- DEBUG(SSSDBG_MINOR_FAILURE, "SUDO provider is set, but it is not "
- "listed in active services. SUDO support will not work!\n");
- }
-
- ret = load_backend_module(be_ctx, BET_SUDO, &be_ctx->bet_info[BET_SUDO],
- be_ctx->bet_info[BET_ID].mod_name);
-
-done:
- talloc_free(tmp_ctx);
- return ret;
-}
-
-int be_process_init(TALLOC_CTX *mem_ctx,
- const char *be_domain,
- uid_t uid, gid_t gid,
- struct tevent_context *ev,
- struct confdb_ctx *cdb)
+errno_t be_process_init(TALLOC_CTX *mem_ctx,
+ const char *be_domain,
+ uid_t uid,
+ gid_t gid,
+ struct tevent_context *ev,
+ struct confdb_ctx *cdb)
{
- struct be_ctx *ctx;
+ uint32_t refresh_interval;
struct tevent_signal *tes;
- int ret;
+ struct be_ctx *be_ctx;
+ errno_t ret;
- ctx = talloc_zero(mem_ctx, struct be_ctx);
- if (!ctx) {
- DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing be_ctx\n");
+ be_ctx = talloc_zero(mem_ctx, struct be_ctx);
+ if (be_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "talloc_zero() failed\n");
return ENOMEM;
}
- ctx->ev = ev;
- ctx->cdb = cdb;
- ctx->identity = talloc_asprintf(ctx, "%%BE_%s", be_domain);
- ctx->conf_path = talloc_asprintf(ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain);
- if (!ctx->identity || !ctx->conf_path) {
+
+ be_ctx->ev = ev;
+ be_ctx->cdb = cdb;
+ be_ctx->identity = talloc_asprintf(be_ctx, "%%BE_%s", be_domain);
+ be_ctx->conf_path = talloc_asprintf(be_ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain);
+ if (be_ctx->identity == NULL || be_ctx->conf_path == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!?\n");
ret = ENOMEM;
- goto fail;
+ goto done;
}
- ret = be_init_failover(ctx);
+ ret = be_init_failover(be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing failover context\n");
- goto fail;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize failover\n");
+ goto done;
}
- ret = sssd_domain_init(ctx, cdb, be_domain, DB_PATH, &ctx->domain);
+ ret = sssd_domain_init(be_ctx, cdb, be_domain, DB_PATH, &be_ctx->domain);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "fatal error opening cache database\n");
- goto fail;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize domain\n");
+ goto done;
}
- ret = sss_monitor_init(ctx, ctx->ev, &monitor_be_methods,
- ctx->identity, DATA_PROVIDER_VERSION,
- ctx, &ctx->mon_conn);
+ ret = sss_monitor_init(be_ctx, be_ctx->ev, &monitor_be_methods,
+ be_ctx->identity, DATA_PROVIDER_VERSION,
+ be_ctx, &be_ctx->mon_conn);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error setting up monitor bus\n");
- goto fail;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize monitor connection\n");
+ goto done;
}
/* We need this for subdomains support, as they have to store fully
- * qualified user and group names for now */
- ret = sss_names_init(ctx->domain, cdb,
- ctx->domain->name, &ctx->domain->names);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error setting fully qualified name format for %s\n",
- ctx->domain->name);
- goto fail;
- }
-
- ret = be_srv_init(ctx, uid, gid);
+ * qualified user and group names for now. */
+ ret = sss_names_init(be_ctx->domain, cdb, be_ctx->domain->name,
+ &be_ctx->domain->names);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up server bus\n");
- goto fail;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup fully qualified name "
+ "format for %s\n", be_ctx->domain->name);
+ goto done;
}
/* Initialize be_refresh periodic task. */
- ctx->refresh_ctx = be_refresh_ctx_init(ctx);
- if (ctx->refresh_ctx == NULL) {
+ be_ctx->refresh_ctx = be_refresh_ctx_init(be_ctx);
+ if (be_ctx->refresh_ctx == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unable to initialize refresh_ctx\n");
ret = ENOMEM;
- goto fail;
+ goto done;
}
- if (ctx->domain->refresh_expired_interval > 0) {
- ret = be_ptask_create(ctx, ctx, ctx->domain->refresh_expired_interval,
- 30, 5, 0, ctx->domain->refresh_expired_interval,
- BE_PTASK_OFFLINE_SKIP, 0,
+ refresh_interval = be_ctx->domain->refresh_expired_interval;
+ if (refresh_interval > 0) {
+ ret = be_ptask_create(be_ctx, be_ctx, refresh_interval, 30, 5, 0,
+ refresh_interval, BE_PTASK_OFFLINE_SKIP, 0,
be_refresh_send, be_refresh_recv,
- ctx->refresh_ctx, "Refresh Records", NULL);
+ be_ctx->refresh_ctx, "Refresh Records", NULL);
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Unable to initialize refresh periodic task\n");
- goto fail;
- }
- }
-
- ret = load_backend_module(ctx, BET_ID,
- &ctx->bet_info[BET_ID], NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "ID backend target successfully loaded from provider [%s].\n",
- ctx->bet_info[BET_ID].mod_name);
-
- ret = load_backend_module(ctx, BET_AUTH,
- &ctx->bet_info[BET_AUTH],
- ctx->bet_info[BET_ID].mod_name);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No authentication module provided for [%s] !!\n",
- be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "AUTH backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_AUTH].mod_name);
- }
-
- ret = load_backend_module(ctx, BET_ACCESS, &ctx->bet_info[BET_ACCESS],
- ACCESS_PERMIT);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to setup ACCESS backend.\n");
- goto fail;
- }
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "ACCESS backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_ACCESS].mod_name);
-
- ret = load_backend_module(ctx, BET_CHPASS,
- &ctx->bet_info[BET_CHPASS],
- ctx->bet_info[BET_AUTH].mod_name);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No change password module provided for [%s] !!\n",
- be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "CHPASS backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_CHPASS].mod_name);
- }
-
- ret = be_process_init_sudo(ctx);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No SUDO module provided for [%s] !!\n", be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "SUDO backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_SUDO].mod_name);
- }
-
- ret = load_backend_module(ctx, BET_AUTOFS,
- &ctx->bet_info[BET_AUTOFS],
- ctx->bet_info[BET_ID].mod_name);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No autofs module provided for [%s] !!\n", be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "autofs backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_AUTOFS].mod_name);
- }
-
- ret = load_backend_module(ctx, BET_SELINUX,
- &ctx->bet_info[BET_SELINUX],
- ctx->bet_info[BET_ID].mod_name);
- if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing data providers\n");
- goto fail;
+ goto done;
}
- DEBUG(SSSDBG_CRIT_FAILURE, "No selinux module provided for [%s] !!\n",
- be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_ALL, "selinux backend target successfully loaded "
- "from provider [%s].\n", ctx->bet_info[BET_SELINUX].mod_name);
}
- ret = load_backend_module(ctx, BET_HOSTID,
- &ctx->bet_info[BET_HOSTID],
- ctx->bet_info[BET_ID].mod_name);
+ ret = dp_init(be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid);
if (ret != EOK) {
- if (ret != ENOENT) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "fatal error initializing data providers\n");
- goto fail;
- }
- DEBUG(SSSDBG_CRIT_FAILURE,
- "No host info module provided for [%s] !!\n", be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_ALL,
- "HOST backend target successfully loaded from provider [%s].\n",
- ctx->bet_info[BET_HOSTID].mod_name);
- }
-
- ret = load_backend_module(ctx, BET_SUBDOMAINS,
- &ctx->bet_info[BET_SUBDOMAINS],
- ctx->bet_info[BET_ID].mod_name);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Subdomains are not supported for [%s] !!\n", be_domain);
- } else {
- DEBUG(SSSDBG_TRACE_ALL, "Get-Subdomains backend target successfully loaded "
- "from provider [%s].\n",
- ctx->bet_info[BET_SUBDOMAINS].mod_name);
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup data provider "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
/* Handle SIGUSR1 to force offline behavior */
BlockSignals(false, SIGUSR1);
- tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
- signal_be_offline, ctx);
+ tes = tevent_add_signal(be_ctx->ev, be_ctx, SIGUSR1, 0,
+ signal_be_offline, be_ctx);
if (tes == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup SIGUSR1 handler\n");
ret = EIO;
- goto fail;
+ goto done;
}
/* Handle SIGUSR2 to force going online */
BlockSignals(false, SIGUSR2);
- tes = tevent_add_signal(ctx->ev, ctx, SIGUSR2, 0,
- signal_be_reset_offline, ctx);
+ tes = tevent_add_signal(be_ctx->ev, be_ctx, SIGUSR2, 0,
+ signal_be_reset_offline, be_ctx);
if (tes == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup SIGUSR2 handler\n");
ret = EIO;
- goto fail;
+ goto done;
}
- return EOK;
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(be_ctx);
+ }
-fail:
- talloc_free(ctx);
return ret;
}
diff --git a/src/providers/data_provider_req.c b/src/providers/data_provider_req.c
index 94aacb676..7750c2cf0 100644
--- a/src/providers/data_provider_req.c
+++ b/src/providers/data_provider_req.c
@@ -21,38 +21,33 @@
#include "providers/data_provider_req.h"
-#define be_req_to_str(req_type, be_req_t) \
- ((req_type) & BE_REQ_FAST) ? "FAST " #be_req_t : #be_req_t
+#define be_req_to_str(be_req_t) #be_req_t
const char *be_req2str(dbus_uint32_t req_type)
{
switch (req_type & BE_REQ_TYPE_MASK) {
case BE_REQ_USER:
- return be_req_to_str(req_type, BE_REQ_USER);
+ return be_req_to_str(BE_REQ_USER);
case BE_REQ_GROUP:
- return be_req_to_str(req_type, BE_REQ_GROUP);
+ return be_req_to_str(BE_REQ_GROUP);
case BE_REQ_INITGROUPS:
- return be_req_to_str(req_type, BE_REQ_INITGROUPS);
+ return be_req_to_str(BE_REQ_INITGROUPS);
case BE_REQ_NETGROUP:
- return be_req_to_str(req_type, BE_REQ_NETGROUP);
+ return be_req_to_str(BE_REQ_NETGROUP);
case BE_REQ_SERVICES:
- return be_req_to_str(req_type, BE_REQ_SERVICES);
+ return be_req_to_str(BE_REQ_SERVICES);
case BE_REQ_SUDO_FULL:
- return be_req_to_str(req_type, BE_REQ_SUDO_FULL);
+ return be_req_to_str(BE_REQ_SUDO_FULL);
case BE_REQ_SUDO_RULES:
- return be_req_to_str(req_type, BE_REQ_SUDO_RULES);
- case BE_REQ_AUTOFS:
- return be_req_to_str(req_type, BE_REQ_AUTOFS);
- case BE_REQ_HOST:
- return be_req_to_str(req_type, BE_REQ_HOST);
+ return be_req_to_str(BE_REQ_SUDO_RULES);
case BE_REQ_BY_SECID:
- return be_req_to_str(req_type, BE_REQ_BY_SECID);
+ return be_req_to_str(BE_REQ_BY_SECID);
case BE_REQ_USER_AND_GROUP:
- return be_req_to_str(req_type, BE_REQ_USER_AND_GROUP);
+ return be_req_to_str(BE_REQ_USER_AND_GROUP);
case BE_REQ_BY_UUID:
- return be_req_to_str(req_type, BE_REQ_BY_UUID);
+ return be_req_to_str(BE_REQ_BY_UUID);
case BE_REQ_BY_CERT:
- return be_req_to_str(req_type, BE_REQ_BY_CERT);
+ return be_req_to_str(BE_REQ_BY_CERT);
}
return "UNKNOWN_REQ";
}
diff --git a/src/providers/data_provider_req.h b/src/providers/data_provider_req.h
index a2889cda5..2dde81e4e 100644
--- a/src/providers/data_provider_req.h
+++ b/src/providers/data_provider_req.h
@@ -33,14 +33,11 @@
#define BE_REQ_SERVICES 0x0005
#define BE_REQ_SUDO_FULL 0x0006
#define BE_REQ_SUDO_RULES 0x0007
-#define BE_REQ_AUTOFS 0x0009
-#define BE_REQ_HOST 0x0010
#define BE_REQ_BY_SECID 0x0011
#define BE_REQ_USER_AND_GROUP 0x0012
#define BE_REQ_BY_UUID 0x0013
#define BE_REQ_BY_CERT 0x0014
#define BE_REQ_TYPE_MASK 0x00FF
-#define BE_REQ_FAST 0x1000
/**
* @brief Convert request type to string for logging purpose.
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index cc780217d..bebb47bf3 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -72,23 +72,6 @@ void hbac_debug_messages(const char *file, int line,
}
}
-static void ipa_access_reply(struct hbac_ctx *hbac_ctx, int pam_status)
-{
- struct be_req *be_req = hbac_ctx->be_req;
- struct pam_data *pd;
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
- pd->pam_status = pam_status;
-
- /* destroy HBAC context now to release all used resources and LDAP connection */
- talloc_zfree(hbac_ctx);
-
- if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {
- be_req_terminate(be_req, DP_ERR_OK, pam_status, NULL);
- } else {
- be_req_terminate(be_req, DP_ERR_FATAL, pam_status, NULL);
- }
-}
-
enum hbac_result {
HBAC_ALLOW = 1,
HBAC_DENY,
@@ -101,285 +84,180 @@ enum check_result {
RULE_ERROR
};
-static void ipa_hbac_check(struct tevent_req *req);
-static int hbac_retry(struct hbac_ctx *hbac_ctx);
-static void hbac_connect_done(struct tevent_req *subreq);
-static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret);
-
-static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx);
+struct ipa_fetch_hbac_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct sdap_id_ctx *sdap_ctx;
+ 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;
+
+ /* Hosts */
+ size_t host_count;
+ struct sysdb_attrs **hosts;
+ size_t hostgroup_count;
+ struct sysdb_attrs **hostgroups;
+ struct sysdb_attrs *ipa_host;
+
+ /* Rules */
+ size_t rule_count;
+ struct sysdb_attrs **rules;
-static void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx);
+ /* Services */
+ size_t service_count;
+ struct sysdb_attrs **services;
+ size_t servicegroup_count;
+ struct sysdb_attrs **servicegroups;
+};
-void ipa_access_handler(struct be_req *be_req)
+static errno_t ipa_fetch_hbac_retry(struct tevent_req *req);
+static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq);
+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);
+
+static struct tevent_req *
+ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct ipa_access_ctx *access_ctx)
{
- struct pam_data *pd;
- struct ipa_access_ctx *ipa_access_ctx;
+ struct ipa_fetch_hbac_state *state;
struct tevent_req *req;
- struct sss_domain_info *dom;
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
-
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
-
- ipa_access_ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct ipa_access_ctx);
-
- 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);
- }
-
- /* First, verify that this account isn't locked.
- * We need to do this in case the auth phase was
- * skipped (such as during GSSAPI single-sign-on
- * or SSH public key exchange.
- */
- req = sdap_access_send(be_req, be_ctx->ev, be_ctx, dom,
- ipa_access_ctx->sdap_access_ctx,
- ipa_access_ctx->sdap_access_ctx->id_ctx->conn,
- pd);
- if (!req) {
- be_req_terminate(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
- return;
- }
- tevent_req_set_callback(req, ipa_hbac_check, be_req);
-}
-
-static void ipa_hbac_check(struct tevent_req *req)
-{
- struct be_req *be_req;
- struct be_ctx *be_ctx;
- struct pam_data *pd;
- struct hbac_ctx *hbac_ctx = NULL;
- struct ipa_access_ctx *ipa_access_ctx;
- int ret;
-
- be_req = tevent_req_callback_data(req, struct be_req);
- be_ctx = be_req_get_be_ctx(be_req);
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
-
- ret = sdap_access_recv(req);
- talloc_zfree(req);
+ time_t now, refresh_interval;
+ bool offline;
+ errno_t ret;
- switch(ret) {
- case EOK:
- /* Account wasn't locked. Continue below
- * to HBAC processing.
- */
- break;
- case ERR_ACCESS_DENIED:
- /* Account was locked. Return permission denied
- * here.
- */
- pd->pam_status = PAM_PERM_DENIED;
- be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
- return;
- case ERR_ACCOUNT_EXPIRED:
- pd->pam_status = PAM_ACCT_EXPIRED;
- be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
- return;
- default:
- /* We got an unexpected error. Return it as-is */
- pd->pam_status = PAM_SYSTEM_ERR;
- be_req_terminate(be_req, DP_ERR_FATAL, pd->pam_status,
- sss_strerror(ret));
- return;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_fetch_hbac_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- hbac_ctx = talloc_zero(be_req, struct hbac_ctx);
- if (hbac_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
- ret = ENOMEM;
- goto fail;
- }
-
- hbac_ctx->be_req = be_req;
- hbac_ctx->pd = pd;
- ipa_access_ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct ipa_access_ctx);
- hbac_ctx->access_ctx = ipa_access_ctx;
- hbac_ctx->sdap_ctx = ipa_access_ctx->sdap_ctx;
- hbac_ctx->ipa_options = ipa_access_ctx->ipa_options;
- hbac_ctx->tr_ctx = ipa_access_ctx->tr_ctx;
- hbac_ctx->search_bases = ipa_access_ctx->hbac_search_bases;
- if (hbac_ctx->search_bases == NULL) {
+ state->ev = ev;
+ state->be_ctx = be_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) {
DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC search base found.\n");
ret = EINVAL;
- goto fail;
+ goto immediately;
}
- ret = hbac_retry(hbac_ctx);
- if (ret != EOK) {
- goto fail;
- }
-
- return;
-
-fail:
- if (hbac_ctx) {
- /* Return an proper error */
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- } else {
- be_req_terminate(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
+ 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;
}
-}
-
-static int hbac_retry(struct hbac_ctx *hbac_ctx)
-{
- struct tevent_req *subreq;
- int ret;
- bool offline;
- time_t now, refresh_interval;
- struct ipa_access_ctx *access_ctx = hbac_ctx->access_ctx;
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
offline = be_is_offline(be_ctx);
- DEBUG(SSSDBG_TRACE_ALL,
- "Connection status is [%s].\n", offline ? "offline" : "online");
-
- refresh_interval = dp_opt_get_int(hbac_ctx->ipa_options,
- IPA_HBAC_REFRESH);
+ DEBUG(SSSDBG_TRACE_ALL, "Connection status is [%s].\n",
+ offline ? "offline" : "online");
+ refresh_interval = dp_opt_get_int(state->ipa_options, IPA_HBAC_REFRESH);
now = time(NULL);
- if (now < access_ctx->last_update + refresh_interval) {
- /* Simulate offline mode and just go to the cache */
+
+ if (offline || now < access_ctx->last_update + refresh_interval) {
DEBUG(SSSDBG_TRACE_FUNC, "Performing cached HBAC evaluation\n");
- offline = true;
+ ret = EOK;
+ goto immediately;
}
- if (!offline) {
- if (hbac_ctx->sdap_op == NULL) {
- hbac_ctx->sdap_op = sdap_id_op_create(hbac_ctx,
- hbac_ctx->sdap_ctx->conn->conn_cache);
- if (hbac_ctx->sdap_op == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_create failed.\n");
- return EIO;
- }
- }
+ ret = ipa_fetch_hbac_retry(req);
+ if (ret != EAGAIN) {
+ goto immediately;
+ }
- subreq = sdap_id_op_connect_send(hbac_ctx->sdap_op, hbac_ctx, &ret);
- if (!subreq) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "sdap_id_op_connect_send failed: %d(%s).\n", ret, strerror(ret));
- talloc_zfree(hbac_ctx->sdap_op);
- return ret;
- }
+ return req;
- tevent_req_set_callback(subreq, hbac_connect_done, hbac_ctx);
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
} else {
- /* Evaluate the rules based on what we have in the
- * sysdb
- */
- ipa_hbac_evaluate_rules(hbac_ctx);
- return EOK;
+ tevent_req_error(req, ret);
}
- return EOK;
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void hbac_connect_done(struct tevent_req *subreq)
+static errno_t ipa_fetch_hbac_retry(struct tevent_req *req)
{
- struct hbac_ctx *hbac_ctx = tevent_req_callback_data(subreq, struct hbac_ctx);
- int ret, dp_error;
-
- ret = sdap_id_op_connect_recv(subreq, &dp_error);
- talloc_zfree(subreq);
-
- if (dp_error == DP_ERR_OFFLINE) {
- /* switching to offline mode */
- talloc_zfree(hbac_ctx->sdap_op);
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *subreq;
+ int ret;
- ipa_hbac_evaluate_rules(hbac_ctx);
- return;
- } else if (ret != EOK) {
- goto fail;
- }
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
- ret = hbac_get_host_info_step(hbac_ctx);
- if (ret != EOK) {
- goto fail;
+ 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;
}
- return;
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_connect_done, req);
-fail:
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+ return EAGAIN;
}
-static void hbac_clear_rule_data(struct hbac_ctx *hbac_ctx)
+static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq)
{
- hbac_ctx->host_count = 0;
- talloc_zfree(hbac_ctx->hosts);
-
- hbac_ctx->hostgroup_count = 0;
- talloc_zfree(hbac_ctx->hostgroups);
-
- hbac_ctx->service_count = 0;
- talloc_zfree(hbac_ctx->services);
-
- hbac_ctx->servicegroup_count = 0;
- talloc_zfree(hbac_ctx->servicegroups);
-
- hbac_ctx->rule_count = 0;
- talloc_zfree(hbac_ctx->rules);
-}
+ struct tevent_req *req = NULL;
+ int dp_error;
+ errno_t ret;
-/* Check whether the current HBAC request is processed in off-line mode */
-static inline bool hbac_ctx_is_offline(struct hbac_ctx *ctx)
-{
- return ctx == NULL || ctx->sdap_op == NULL;
-}
+ req = tevent_req_callback_data(subreq, struct tevent_req);
-/* Check the step result code and continue, retry, get offline result or abort accordingly */
-static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret)
-{
- int dp_error;
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
- if (ret == EOK) {
- return true;
+ if (dp_error == DP_ERR_OFFLINE) {
+ ret = EOK;
+ goto done;
}
- if (hbac_ctx_is_offline(hbac_ctx)) {
- /* already offline => the error is fatal */
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return false;
+ ret = ipa_fetch_hbac_hostinfo(req);
+ if (ret == EAGAIN) {
+ return;
}
- ret = sdap_id_op_done(hbac_ctx->sdap_op, ret, &dp_error);
+done:
if (ret != EOK) {
- if (dp_error == DP_ERR_OFFLINE) {
- /* switching to offline mode */
- talloc_zfree(hbac_ctx->sdap_op);
-
- /* Free any of the results we've gotten */
- hbac_clear_rule_data(hbac_ctx);
-
- dp_error = DP_ERR_OK;
- }
-
- if (dp_error == DP_ERR_OK) {
- /* retry */
- ret = hbac_retry(hbac_ctx);
- if (ret == EOK) {
- return false;
- }
- }
+ tevent_req_error(req, ret);
+ return;
}
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return false;
+ tevent_req_done(req);
}
-static void hbac_get_service_info_step(struct tevent_req *req);
-static void hbac_get_rule_info_step(struct tevent_req *req);
-static void hbac_sysdb_save (struct tevent_req *req);
-
-static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
+static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *subreq;
const char *hostname;
- struct tevent_req *req;
+ bool srchost;
+
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
- if (dp_opt_get_bool(hbac_ctx->ipa_options, IPA_HBAC_SUPPORT_SRCHOST)) {
+ srchost = dp_opt_get_bool(state->ipa_options, IPA_HBAC_SUPPORT_SRCHOST);
+ if (srchost) {
/* Support srchost
* -> we don't want any particular host,
* we want all hosts
@@ -392,284 +270,345 @@ static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
sss_log(SSS_LOG_NOTICE, "WARNING: Using deprecated option "
"ipa_hbac_support_srchost.\n");
} else {
- hostname = dp_opt_get_string(hbac_ctx->ipa_options, IPA_HOSTNAME);
+ hostname = dp_opt_get_string(state->ipa_options, IPA_HOSTNAME);
}
- req = ipa_host_info_send(hbac_ctx, be_ctx->ev,
- sdap_id_op_handle(hbac_ctx->sdap_op),
- hbac_ctx->sdap_ctx->opts,
- hostname,
- hbac_ctx->access_ctx->host_map,
- hbac_ctx->access_ctx->hostgroup_map,
- hbac_ctx->access_ctx->host_search_bases);
- if (req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not get host info\n");
+ subreq = ipa_host_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts, hostname,
+ state->access_ctx->host_map,
+ state->access_ctx->hostgroup_map,
+ state->access_ctx->host_search_bases);
+ if (subreq == NULL) {
return ENOMEM;
}
- tevent_req_set_callback(req, hbac_get_service_info_step, hbac_ctx);
- return EOK;
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_hostinfo_done, req);
+
+ return EAGAIN;
}
-static void hbac_get_service_info_step(struct tevent_req *req)
+static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq)
{
+ struct ipa_fetch_hbac_state *state = NULL;
+ struct tevent_req *req = NULL;
errno_t ret;
- struct hbac_ctx *hbac_ctx =
- tevent_req_callback_data(req, struct hbac_ctx);
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
-
- ret = ipa_host_info_recv(req, hbac_ctx,
- &hbac_ctx->host_count,
- &hbac_ctx->hosts,
- &hbac_ctx->hostgroup_count,
- &hbac_ctx->hostgroups);
- talloc_zfree(req);
- if (!hbac_check_step_result(hbac_ctx, ret)) {
- return;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ 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);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
}
- /* Get services and service groups */
- req = ipa_hbac_service_info_send(hbac_ctx, be_ctx->ev,
- sdap_id_op_handle(hbac_ctx->sdap_op),
- hbac_ctx->sdap_ctx->opts,
- hbac_ctx->search_bases);
- if (req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,"Could not get service info\n");
- goto fail;
+ subreq = ipa_hbac_service_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts,
+ state->search_bases);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
}
- tevent_req_set_callback(req, hbac_get_rule_info_step, hbac_ctx);
+
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_services_done, req);
+
return;
-fail:
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
}
-static void hbac_get_rule_info_step(struct tevent_req *req)
+static void ipa_fetch_hbac_services_done(struct tevent_req *subreq)
{
- errno_t ret;
- size_t i;
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *req;
const char *ipa_hostname;
const char *hostname;
- struct hbac_ctx *hbac_ctx =
- tevent_req_callback_data(req, struct hbac_ctx);
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
-
- ret = ipa_hbac_service_info_recv(req, hbac_ctx,
- &hbac_ctx->service_count,
- &hbac_ctx->services,
- &hbac_ctx->servicegroup_count,
- &hbac_ctx->servicegroups);
- talloc_zfree(req);
- if (!hbac_check_step_result(hbac_ctx, ret)) {
- return;
+ 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);
+
+ ret = ipa_hbac_service_info_recv(subreq, state,
+ &state->service_count, &state->services,
+ &state->servicegroup_count, &state->servicegroups);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
}
/* Get the ipa_host attrs */
- hbac_ctx->ipa_host = NULL;
- ipa_hostname = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME);
+ 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");
- goto fail;
+ ret = EINVAL;
+ goto done;
}
- for (i = 0; i < hbac_ctx->host_count; i++) {
- ret = sysdb_attrs_get_string(hbac_ctx->hosts[i],
- SYSDB_FQDN,
- &hostname);
+ for (i = 0; i < state->host_count; i++) {
+ ret = sysdb_attrs_get_string(state->hosts[i], SYSDB_FQDN, &hostname);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
- goto fail;
+ goto done;
}
if (strcasecmp(hostname, ipa_hostname) == 0) {
- hbac_ctx->ipa_host = hbac_ctx->hosts[i];
+ state->ipa_host = state->hosts[i];
break;
}
}
- if (hbac_ctx->ipa_host == NULL) {
+
+ if (state->ipa_host == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host\n");
- goto fail;
+ ret = EINVAL;
+ goto done;
}
-
- /* Get the list of applicable rules */
- req = ipa_hbac_rule_info_send(hbac_ctx,
- be_ctx->ev,
- sdap_id_op_handle(hbac_ctx->sdap_op),
- hbac_ctx->sdap_ctx->opts,
- hbac_ctx->search_bases,
- hbac_ctx->ipa_host);
- if (req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Could not get rules\n");
- goto fail;
+ subreq = ipa_hbac_rule_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts,
+ state->search_bases,
+ state->ipa_host);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
}
- tevent_req_set_callback(req, hbac_sysdb_save, hbac_ctx);
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_rules_done, req);
+
return;
-fail:
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
}
-static void hbac_sysdb_save(struct tevent_req *req)
+static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq)
{
+ struct ipa_fetch_hbac_state *state = NULL;
+ struct tevent_req *req = NULL;
+ int dp_error;
errno_t ret;
- bool in_transaction = false;
- struct hbac_ctx *hbac_ctx =
- tevent_req_callback_data(req, struct hbac_ctx);
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
- struct sss_domain_info *domain = be_ctx->domain;
- struct ldb_dn *base_dn;
- struct ipa_access_ctx *access_ctx =
- talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct ipa_access_ctx);
- TALLOC_CTX *tmp_ctx;
+ bool found;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
- ret = ipa_hbac_rule_info_recv(req, hbac_ctx,
- &hbac_ctx->rule_count,
- &hbac_ctx->rules);
- talloc_zfree(req);
+ ret = ipa_hbac_rule_info_recv(subreq, state,
+ &state->rule_count, &state->rules);
+ talloc_zfree(subreq);
if (ret == ENOENT) {
- /* No rules were found that apply to this
- * host.
- */
+ /* Set ret to EOK so we can safely call sdap_id_op_done. */
+ found = false;
+ ret = EOK;
+ } else if (ret == EOK) {
+ found = true;
+ } else {
+ goto done;
+ }
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
- }
- /* 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) {
- talloc_free(tmp_ctx);
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ipa_fetch_hbac_retry(req);
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
}
+ return;
+ } else if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
- ret = sysdb_delete_recursive(domain->sysdb, base_dn, true);
- talloc_free(tmp_ctx);
+ if (found == false) {
+ /* No rules were found that apply to this host. */
+ ret = ipa_purge_hbac(state->be_ctx->domain);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n");
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove HBAC rules\n");
+ goto done;
}
- /* If no rules are found, we default to DENY */
- ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
- return;
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = ipa_save_hbac(state->be_ctx->domain, state);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save HBAC rules\n");
+ goto done;
}
- if (!hbac_check_step_result(hbac_ctx, ret)) {
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
return;
}
+ tevent_req_done(req);
+}
+
+static errno_t ipa_fetch_hbac_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(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)
+{
+ 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 fail;
+ goto done;
}
in_transaction = true;
/* Save the hosts */
- ret = ipa_hbac_sysdb_save(domain,
- HBAC_HOSTS_SUBDIR, SYSDB_FQDN,
- hbac_ctx->host_count, hbac_ctx->hosts,
+ ret = ipa_hbac_sysdb_save(domain, HBAC_HOSTS_SUBDIR, SYSDB_FQDN,
+ state->host_count, state->hosts,
HBAC_HOSTGROUPS_SUBDIR, SYSDB_NAME,
- hbac_ctx->hostgroup_count,
- hbac_ctx->hostgroups);
+ state->hostgroup_count, state->hostgroups);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts: [%d][%s]\n",
- ret, strerror(ret));
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error saving hosts [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
/* Save the services */
- ret = ipa_hbac_sysdb_save(domain,
- HBAC_SERVICES_SUBDIR, IPA_CN,
- hbac_ctx->service_count, hbac_ctx->services,
+ ret = ipa_hbac_sysdb_save(domain, HBAC_SERVICES_SUBDIR, IPA_CN,
+ state->service_count, state->services,
HBAC_SERVICEGROUPS_SUBDIR, IPA_CN,
- hbac_ctx->servicegroup_count,
- hbac_ctx->servicegroups);
+ state->servicegroup_count,
+ state->servicegroups);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Error saving services: [%d][%s]\n",
- ret, strerror(ret));
- goto fail;
+ 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,
- hbac_ctx->rule_count,
- hbac_ctx->rules,
+ ret = ipa_hbac_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, strerror(ret));
- goto fail;
+ 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 fail;
+ goto done;
}
in_transaction = false;
- /* We don't need the rule data any longer,
- * the rest of the processing relies on
- * sysdb lookups.
- */
- hbac_clear_rule_data(hbac_ctx);
-
-
- access_ctx->last_update = time(NULL);
+ state->access_ctx->last_update = time(NULL);
- /* Now evaluate the request against the rules */
- ipa_hbac_evaluate_rules(hbac_ctx);
-
- return;
+ ret = EOK;
-fail:
+done:
if (in_transaction) {
- ret = sysdb_transaction_cancel(domain->sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel transaction\n");
+ sret = sysdb_transaction_cancel(domain->sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
}
}
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+
+ return ret;
}
-void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx)
+errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx,
+ struct dp_option *ipa_options,
+ struct pam_data *pd)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
- errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ struct hbac_ctx hbac_ctx;
struct hbac_rule **hbac_rules;
struct hbac_eval_req *eval_req;
enum hbac_eval_result result;
- struct hbac_info *info;
+ struct hbac_info *info = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ hbac_ctx.be_ctx = be_ctx;
+ hbac_ctx.ipa_options = ipa_options;
+ hbac_ctx.pd = pd;
/* Get HBAC rules from the sysdb */
- ret = hbac_get_cached_rules(hbac_ctx, be_ctx->domain,
- &hbac_ctx->rule_count, &hbac_ctx->rules);
+ ret = hbac_get_cached_rules(tmp_ctx, be_ctx->domain,
+ &hbac_ctx.rule_count, &hbac_ctx.rules);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve rules from the cache\n");
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+ goto done;
}
- ret = hbac_ctx_to_rules(hbac_ctx, hbac_ctx,
- &hbac_rules, &eval_req);
+ ret = hbac_ctx_to_rules(tmp_ctx, &hbac_ctx, &hbac_rules, &eval_req);
if (ret == EPERM) {
DEBUG(SSSDBG_CRIT_FAILURE,
"DENY rules detected. Denying access to all users\n");
- ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
- return;
+ ret = ERR_ACCESS_DENIED;
+ goto done;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct HBAC rules\n");
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
+ goto done;
}
hbac_enable_debug(hbac_debug_messages);
@@ -677,26 +616,27 @@ void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx)
result = hbac_evaluate(hbac_rules, eval_req, &info);
if (result == HBAC_EVAL_ALLOW) {
DEBUG(SSSDBG_MINOR_FAILURE, "Access granted by HBAC rule [%s]\n",
- info->rule_name);
- hbac_free_info(info);
- ipa_access_reply(hbac_ctx, PAM_SUCCESS);
- return;
+ info->rule_name);
+ ret = EOK;
+ goto done;
} else if (result == HBAC_EVAL_ERROR) {
DEBUG(SSSDBG_CRIT_FAILURE, "Error [%s] occurred in rule [%s]\n",
- hbac_error_string(info->code),
- info->rule_name);
- hbac_free_info(info);
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
+ hbac_error_string(info->code), info->rule_name);
+ ret = EIO;
+ goto done;
} else if (result == HBAC_EVAL_OOM) {
DEBUG(SSSDBG_CRIT_FAILURE, "Insufficient memory\n");
- ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
- return;
+ ret = ENOMEM;
+ goto done;
}
DEBUG(SSSDBG_MINOR_FAILURE, "Access denied by HBAC rules\n");
+ ret = ERR_ACCESS_DENIED;
+
+done:
hbac_free_info(info);
- ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
+ talloc_free(tmp_ctx);
+ return ret;
}
errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
@@ -761,3 +701,154 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+struct ipa_pam_access_handler_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct ipa_access_ctx *access_ctx;
+ struct pam_data *pd;
+};
+
+static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq);
+static void ipa_pam_access_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_pam_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_access_ctx *access_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
+{
+ struct ipa_pam_access_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_pam_access_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->access_ctx = access_ctx;
+
+ subreq = sdap_access_send(state, params->ev, params->be_ctx,
+ params->domain, access_ctx->sdap_access_ctx,
+ access_ctx->sdap_ctx->conn, pd);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_pam_access_handler_sdap_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);
+
+ return req;
+}
+
+static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq)
+{
+ struct ipa_pam_access_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 ipa_pam_access_handler_state);
+
+ ret = sdap_access_recv(subreq);
+ talloc_free(subreq);
+ switch (ret) {
+ case EOK:
+ /* Account wasn't locked. Continue below to HBAC processing. */
+ break;
+ case ERR_ACCESS_DENIED:
+ /* Account was locked. Return permission denied here. */
+ state->pd->pam_status = PAM_PERM_DENIED;
+ goto done;
+ case ERR_ACCOUNT_EXPIRED:
+ state->pd->pam_status = PAM_ACCT_EXPIRED;
+ goto done;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result "
+ "[%d]: %s.\n", ret, sss_strerror(ret));
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ break;
+ }
+
+ subreq = ipa_fetch_hbac_send(state, state->ev, state->be_ctx,
+ state->access_ctx);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_pam_access_handler_done, req);
+
+ return;
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+static void ipa_pam_access_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_pam_access_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 ipa_pam_access_handler_state);
+
+ ret = ipa_fetch_hbac_recv(subreq);
+ talloc_free(subreq);
+
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC rules find, denying access\n");
+ state->pd->pam_status = PAM_PERM_DENIED;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to fetch HBAC rules [%d]: %s\n",
+ ret, sss_strerror(ret));
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ ret = ipa_hbac_evaluate_rules(state->be_ctx,
+ state->access_ctx->ipa_options, state->pd);
+ if (ret == EOK) {
+ state->pd->pam_status = PAM_SUCCESS;
+ } else if (ret == ERR_ACCESS_DENIED) {
+ state->pd->pam_status = PAM_PERM_DENIED;
+ } else {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ }
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct ipa_pam_access_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_pam_access_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
+}
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index 024b57e7e..1e30a89a0 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -46,35 +46,23 @@ struct ipa_access_ctx {
};
struct hbac_ctx {
- struct sdap_id_ctx *sdap_ctx;
- struct ipa_access_ctx *access_ctx;
- struct sdap_id_op *sdap_op;
+ struct be_ctx *be_ctx;
struct dp_option *ipa_options;
- struct time_rules_ctx *tr_ctx;
- struct be_req *be_req;
struct pam_data *pd;
-
- struct sdap_search_base **search_bases;
-
- /* Hosts */
- size_t host_count;
- struct sysdb_attrs **hosts;
- size_t hostgroup_count;
- struct sysdb_attrs **hostgroups;
- struct sysdb_attrs *ipa_host;
-
- /* Rules */
size_t rule_count;
struct sysdb_attrs **rules;
-
- /* Services */
- size_t service_count;
- struct sysdb_attrs **services;
- size_t servicegroup_count;
- struct sysdb_attrs **servicegroups;
};
-void ipa_access_handler(struct be_req *be_req);
+struct tevent_req *
+ipa_pam_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_access_ctx *access_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+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,
diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c
index b1bfa3ffe..ad0a89bfe 100644
--- a/src/providers/ipa/ipa_auth.c
+++ b/src/providers/ipa/ipa_auth.c
@@ -168,92 +168,79 @@ static int get_password_migration_flag_recv(struct tevent_req *req,
return EOK;
}
-
-struct ipa_auth_state {
- struct be_req *be_req;
+struct ipa_pam_auth_handler_state {
struct tevent_context *ev;
- struct ipa_auth_ctx *ipa_auth_ctx;
+ struct ipa_auth_ctx *auth_ctx;
+ struct be_ctx *be_ctx;
struct pam_data *pd;
- bool password_migration;
- struct sdap_handle *sh;
};
-static void ipa_auth_handler_done(struct tevent_req *req);
-static void ipa_get_migration_flag_done(struct tevent_req *req);
-static void ipa_migration_flag_connect_done(struct tevent_req *req);
-static void ipa_auth_ldap_done(struct tevent_req *req);
-static void ipa_auth_handler_retry_done(struct tevent_req *req);
-
-void ipa_auth(struct be_req *be_req)
+static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq);
+static void ipa_pam_auth_handler_flag_done(struct tevent_req *subreq);
+static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq);
+static void ipa_pam_auth_handler_auth_done(struct tevent_req *subreq);
+static void ipa_pam_auth_handler_retry_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_pam_auth_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_auth_ctx *auth_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
{
+ struct ipa_pam_auth_handler_state *state;
+ struct tevent_req *subreq;
struct tevent_req *req;
- struct ipa_auth_state *state;
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(be_req), struct pam_data);
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
-
- state = talloc_zero(be_req, struct ipa_auth_state);
- if (state == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
- goto fail;
- }
-
- state->password_migration = false;
- state->sh = NULL;
- state->be_req = be_req;
- state->ev = be_ctx->ev;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_pam_auth_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
state->pd = pd;
+ state->ev = params->ev;
+ state->auth_ctx = auth_ctx;
+ state->be_ctx = params->be_ctx;
- switch (state->pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- case SSS_PAM_PREAUTH:
- state->ipa_auth_ctx = talloc_get_type(
- be_ctx->bet_info[BET_AUTH].pvt_bet_data,
- struct ipa_auth_ctx);
- break;
- case SSS_PAM_CHAUTHTOK:
- case SSS_PAM_CHAUTHTOK_PRELIM:
- state->ipa_auth_ctx = talloc_get_type(
- be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
- struct ipa_auth_ctx);
- break;
- default:
- DEBUG(SSSDBG_OP_FAILURE, "Unsupported PAM task.\n");
- goto fail;
- }
+ pd->pam_status = PAM_SYSTEM_ERR;
- req = krb5_auth_queue_send(state, state->ev, be_ctx, state->pd,
- state->ipa_auth_ctx->krb5_auth_ctx);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_send failed.\n");
- goto fail;
+ subreq = krb5_auth_queue_send(state, params->ev, params->be_ctx,
+ pd, auth_ctx->krb5_auth_ctx);
+ if (subreq == NULL) {
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
}
- tevent_req_set_callback(req, ipa_auth_handler_done, state);
- return;
+ tevent_req_set_callback(subreq, ipa_pam_auth_handler_krb5_done, req);
-fail:
- talloc_free(state);
- pd->pam_status = PAM_SYSTEM_ERR;
- be_req_terminate(be_req, DP_ERR_FATAL, pd->pam_status, NULL);
+ 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 ipa_auth_handler_done(struct tevent_req *req)
+static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq)
{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
- struct ipa_auth_state);
- int ret;
- int pam_status = PAM_SYSTEM_ERR;
+ struct ipa_pam_auth_handler_state *state;
+ struct tevent_req *req;
int dp_err;
+ char *realm;
+ errno_t ret;
- ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
- talloc_zfree(req);
- state->pd->pam_status = pam_status;
- if (ret != EOK && pam_status != PAM_CRED_ERR) {
- DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_recv request failed.\n");
- dp_err = DP_ERR_OK;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
+
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, &dp_err);
+ talloc_free(subreq);
+ if (ret != EOK && state->pd->pam_status != PAM_CRED_ERR) {
+ DEBUG(SSSDBG_OP_FAILURE, "KRB5 auth failed [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
@@ -261,201 +248,203 @@ static void ipa_auth_handler_done(struct tevent_req *req)
goto done;
}
- if (state->pd->cmd == SSS_PAM_AUTHENTICATE &&
- state->pd->pam_status == PAM_CRED_ERR) {
-
- req = get_password_migration_flag_send(state, state->ev,
- state->ipa_auth_ctx->sdap_id_ctx,
- dp_opt_get_string(
- state->ipa_auth_ctx->ipa_options,
- IPA_KRB5_REALM));
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE,
- "get_password_migration_flag failed.\n");
+ if (state->pd->cmd == SSS_PAM_AUTHENTICATE
+ && state->pd->pam_status == PAM_CRED_ERR) {
+ 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,
+ realm);
+ if (subreq == NULL) {
goto done;
}
- tevent_req_set_callback(req, ipa_get_migration_flag_done, state);
+ tevent_req_set_callback(subreq, ipa_pam_auth_handler_flag_done, req);
return;
}
done:
- be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static void ipa_get_migration_flag_done(struct tevent_req *req)
+static void ipa_pam_auth_handler_flag_done(struct tevent_req *subreq)
{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
- struct ipa_auth_state);
- int ret;
- int dp_err = DP_ERR_FATAL;
+ struct ipa_pam_auth_handler_state *state;
+ struct sdap_auth_ctx *sdap_auth_ctx;
+ bool password_migration = false;
+ struct tevent_req *req;
+ errno_t ret;
- ret = get_password_migration_flag_recv(req, &state->password_migration);
- talloc_zfree(req);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
+
+ ret = get_password_migration_flag_recv(subreq, &password_migration);
+ talloc_free(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "get_password_migration_flag "
- "request failed.\n");
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get password migration flag "
+ "[%d]: %s\n", ret, sss_strerror(ret));
state->pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
goto done;
}
- if (state->password_migration) {
- req = sdap_cli_connect_send(state, state->ev,
- state->ipa_auth_ctx->sdap_auth_ctx->opts,
- state->ipa_auth_ctx->sdap_auth_ctx->be,
- state->ipa_auth_ctx->sdap_auth_ctx->service,
- true, CON_TLS_ON, true);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_cli_connect_send failed.\n");
+ if (password_migration) {
+ sdap_auth_ctx = state->auth_ctx->sdap_auth_ctx;
+ subreq = sdap_cli_connect_send(state, state->ev,
+ sdap_auth_ctx->opts,
+ sdap_auth_ctx->be,
+ sdap_auth_ctx->service,
+ true, CON_TLS_ON, true);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
goto done;
}
- tevent_req_set_callback(req, ipa_migration_flag_connect_done, state);
+ tevent_req_set_callback(subreq, ipa_pam_auth_handler_connect_done, req);
return;
}
- DEBUG(SSSDBG_CONF_SETTINGS, "Password migration is not enabled.\n");
- dp_err = DP_ERR_OK;
done:
- be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static void ipa_migration_flag_connect_done(struct tevent_req *req)
+static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq)
{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
- struct ipa_auth_state);
- struct be_ctx *be_ctx = be_req_get_be_ctx(state->be_req);
- const char **attrs;
- struct ldb_message *user_msg;
+ struct ipa_pam_auth_handler_state *state;
+ struct tevent_req *req;
+ struct sdap_handle *sh;
+ const char *attrs[] = {SYSDB_ORIG_DN, NULL};
+ struct ldb_message *msg;
const char *dn;
- int dp_err = DP_ERR_FATAL;
- int ret;
- int auth_timeout;
+ int timeout;
+ errno_t ret;
- ret = sdap_cli_connect_recv(req, state, NULL, &state->sh, NULL);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Cannot connect to LDAP server to perform migration\n");
- goto done;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
state->pd->pam_status = PAM_SYSTEM_ERR;
- DEBUG(SSSDBG_TRACE_FUNC, "Assuming Kerberos password is missing, "
- "starting password migration.\n");
- attrs = talloc_array(state, const char *, 2);
- if (attrs == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
- state->pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
+ ret = sdap_cli_connect_recv(subreq, state, NULL, &sh, NULL);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot connect to LDAP server to perform "
+ "migration [%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- attrs[0] = SYSDB_ORIG_DN;
- attrs[1] = NULL;
- ret = sysdb_search_user_by_name(state, be_ctx->domain, state->pd->user,
- attrs, &user_msg);
+ DEBUG(SSSDBG_TRACE_FUNC, "Assuming Kerberos password is missing, "
+ "starting password migration.\n");
+
+ ret = sysdb_search_user_by_name(state, state->be_ctx->domain,
+ state->pd->user, attrs, &msg);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
goto done;
}
- dn = ldb_msg_find_attr_as_string(user_msg, SYSDB_ORIG_DN, NULL);
+ dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
if (dn == NULL) {
DEBUG(SSSDBG_MINOR_FAILURE, "Missing original DN for user [%s].\n",
- state->pd->user);
- state->pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
+ state->pd->user);
goto done;
}
- auth_timeout = dp_opt_get_int(
- state->ipa_auth_ctx->sdap_auth_ctx->opts->basic,
- SDAP_OPT_TIMEOUT);
+ timeout = dp_opt_get_int(state->auth_ctx->sdap_auth_ctx->opts->basic,
+ SDAP_OPT_TIMEOUT);
- req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,
- state->pd->authtok, auth_timeout);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_auth_send failed.\n");
+ subreq = sdap_auth_send(state, state->ev, sh, NULL, NULL, dn,
+ state->pd->authtok, timeout);
+ if (subreq == NULL) {
goto done;
}
- tevent_req_set_callback(req, ipa_auth_ldap_done, state);
+ tevent_req_set_callback(subreq, ipa_pam_auth_handler_auth_done, req);
return;
done:
- be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static void ipa_auth_ldap_done(struct tevent_req *req)
+static void ipa_pam_auth_handler_auth_done(struct tevent_req *subreq)
{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
- struct ipa_auth_state);
- struct be_ctx *be_ctx = be_req_get_be_ctx(state->be_req);
- int ret;
- int dp_err = DP_ERR_FATAL;
+ struct ipa_pam_auth_handler_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- ret = sdap_auth_recv(req, state, NULL);
- talloc_zfree(req);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
+
+ ret = sdap_auth_recv(subreq, state, NULL);
+
+ talloc_free(subreq);
switch (ret) {
case EOK:
break;
-
case ERR_AUTH_DENIED:
case ERR_AUTH_FAILED:
case ERR_PASSWORD_EXPIRED:
-/* TODO: do we need to handle expired passwords? */
+ /* TODO: do we need to handle expired passwords? */
DEBUG(SSSDBG_MINOR_FAILURE, "LDAP authentication failed, "
- "Password migration not possible.\n");
+ "password migration not possible.\n");
state->pd->pam_status = PAM_CRED_INSUFFICIENT;
- dp_err = DP_ERR_OK;
goto done;
default:
DEBUG(SSSDBG_OP_FAILURE, "auth_send request failed.\n");
state->pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
goto done;
}
-
DEBUG(SSSDBG_TRACE_FUNC, "LDAP authentication succeded, "
- "trying Kerberos authentication again.\n");
+ "trying Kerberos authentication again.\n");
- req = krb5_auth_queue_send(state, state->ev, be_ctx, state->pd,
- state->ipa_auth_ctx->krb5_auth_ctx);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_send failed.\n");
+ subreq = krb5_auth_queue_send(state, state->ev, state->be_ctx, state->pd,
+ state->auth_ctx->krb5_auth_ctx);
+ if (subreq == NULL) {
goto done;
}
- tevent_req_set_callback(req, ipa_auth_handler_retry_done, state);
+ tevent_req_set_callback(subreq, ipa_pam_auth_handler_retry_done, req);
return;
done:
- be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static void ipa_auth_handler_retry_done(struct tevent_req *req)
+static void ipa_pam_auth_handler_retry_done(struct tevent_req *subreq)
{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
- struct ipa_auth_state);
- int ret;
- int pam_status;
+ struct ipa_pam_auth_handler_state *state;
+ struct tevent_req *req;
int dp_err;
+ errno_t ret;
- ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
- talloc_zfree(req);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
+
+ ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, &dp_err);
+ talloc_free(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_recv request failed.\n");
state->pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
- goto done;
}
- state->pd->pam_status = pam_status;
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
-done:
- be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
+errno_t
+ipa_pam_auth_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct ipa_pam_auth_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
}
diff --git a/src/providers/ipa/ipa_auth.h b/src/providers/ipa/ipa_auth.h
index 5cd318bae..53666eb44 100644
--- a/src/providers/ipa/ipa_auth.h
+++ b/src/providers/ipa/ipa_auth.h
@@ -26,7 +26,17 @@
#define _IPA_AUTH_H_
#include "providers/backend.h"
-
-void ipa_auth(struct be_req *be_req);
+#include "providers/ipa/ipa_common.h"
+
+struct tevent_req *
+ipa_pam_auth_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_auth_ctx *auth_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+ipa_pam_auth_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data);
#endif /* _IPA_AUTH_H_ */
diff --git a/src/providers/ipa/ipa_autofs.c b/src/providers/ipa/ipa_autofs.c
index 504735d3e..b2e4cbc06 100644
--- a/src/providers/ipa/ipa_autofs.c
+++ b/src/providers/ipa/ipa_autofs.c
@@ -31,23 +31,14 @@
#include "providers/ipa/ipa_dyndns.h"
#include "providers/ipa/ipa_selinux.h"
-struct bet_ops ipa_autofs_ops = {
- .handler = sdap_autofs_handler,
- .finalize = NULL,
- .check_online = sdap_check_online
-};
-
-int ipa_autofs_init(struct be_ctx *be_ctx,
- struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_id_ctx *id_ctx,
+ struct dp_method *dp_methods)
{
int ret;
- DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing autofs LDAP back end\n");
-
- *ops = &ipa_autofs_ops;
- *pvt_data = id_ctx->sdap_id_ctx;
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing autofs IPA back end\n");
ret = ipa_get_autofs_options(id_ctx->ipa_options, be_ctx->cdb,
be_ctx->conf_path, &id_ctx->sdap_id_ctx->opts);
@@ -56,5 +47,9 @@ int ipa_autofs_init(struct be_ctx *be_ctx,
return ret;
}
+ dp_set_method(dp_methods, DPM_AUTOFS_HANDLER,
+ sdap_autofs_handler_send, sdap_autofs_handler_recv, id_ctx->sdap_id_ctx,
+ struct sdap_id_ctx, struct dp_autofs_data, struct dp_reply_std);
+
return ret;
}
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 51de819c8..939c898e1 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -258,10 +258,10 @@ int ipa_get_autofs_options(struct ipa_options *ipa_opts,
errno_t ipa_get_dyndns_options(struct be_ctx *be_ctx,
struct ipa_options *ctx);
-int ipa_autofs_init(struct be_ctx *be_ctx,
- struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data);
+errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_id_ctx *id_ctx,
+ struct dp_method *dp_methods);
int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
const char *primary_servers,
@@ -269,10 +269,10 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
struct ipa_options *options,
struct ipa_service **_service);
-int ipa_sudo_init(struct be_ctx *be_ctx,
+int ipa_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data);
+ struct dp_method *dp_methods);
errno_t get_idmap_data_from_range(struct range_info *r, char *domain_name,
char **_name, char **_sid, uint32_t *_rid,
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
index 82c531f15..7edaf576e 100644
--- a/src/providers/ipa/ipa_hbac_common.c
+++ b/src/providers/ipa/ipa_hbac_common.c
@@ -261,7 +261,6 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
size_t idx,
struct hbac_rule **rule)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
errno_t ret;
struct hbac_rule *new_rule;
struct ldb_message_element *el;
@@ -305,7 +304,7 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
}
/* Get the users */
- ret = hbac_user_attrs_to_rule(new_rule, be_ctx->domain,
+ ret = hbac_user_attrs_to_rule(new_rule, hbac_ctx->be_ctx->domain,
new_rule->name,
hbac_ctx->rules[idx],
&new_rule->users);
@@ -316,7 +315,7 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
}
/* Get the services */
- ret = hbac_service_attrs_to_rule(new_rule, be_ctx->domain,
+ ret = hbac_service_attrs_to_rule(new_rule, hbac_ctx->be_ctx->domain,
new_rule->name,
hbac_ctx->rules[idx],
&new_rule->services);
@@ -327,7 +326,7 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
}
/* Get the target hosts */
- ret = hbac_thost_attrs_to_rule(new_rule, be_ctx->domain,
+ ret = hbac_thost_attrs_to_rule(new_rule, hbac_ctx->be_ctx->domain,
new_rule->name,
hbac_ctx->rules[idx],
&new_rule->targethosts);
@@ -340,7 +339,7 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
/* Get the source hosts */
- ret = hbac_shost_attrs_to_rule(new_rule, be_ctx->domain,
+ ret = hbac_shost_attrs_to_rule(new_rule, hbac_ctx->be_ctx->domain,
new_rule->name,
hbac_ctx->rules[idx],
dp_opt_get_bool(hbac_ctx->ipa_options,
@@ -425,8 +424,7 @@ hbac_ctx_to_eval_request(TALLOC_CTX *mem_ctx,
struct pam_data *pd = hbac_ctx->pd;
TALLOC_CTX *tmp_ctx;
struct hbac_eval_req *eval_req;
- struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req);
- struct sss_domain_info *domain = be_ctx->domain;
+ struct sss_domain_info *domain = hbac_ctx->be_ctx->domain;
const char *rhost;
const char *thost;
struct sss_domain_info *user_dom;
diff --git a/src/providers/ipa/ipa_hostid.c b/src/providers/ipa/ipa_hostid.c
index 31fa29f91..87a36167b 100644
--- a/src/providers/ipa/ipa_hostid.c
+++ b/src/providers/ipa/ipa_hostid.c
@@ -39,104 +39,6 @@ struct hosts_get_state {
int dp_error;
};
-struct tevent_req *
-hosts_get_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct ipa_hostid_ctx *hostid_ctx,
- const char *name,
- const char *alias);
-static errno_t
-hosts_get_recv(struct tevent_req *req,
- int *dp_error_out);
-
-static void
-ipa_host_info_hosts_done(struct tevent_req *req);
-
-void
-ipa_host_info_handler(struct be_req *breq)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- struct ipa_hostid_ctx *hostid_ctx;
- struct sdap_id_ctx *ctx;
- struct be_host_req *hr;
- struct tevent_req *req;
- int dp_error = DP_ERR_FATAL;
- errno_t ret = EOK;
- const char *err = "Unknown Error";
-
- hostid_ctx = talloc_get_type(be_ctx->bet_info[BET_HOSTID].pvt_bet_data,
- struct ipa_hostid_ctx);
- ctx = hostid_ctx->sdap_id_ctx;
-
- if (be_is_offline(ctx->be)) {
- dp_error = DP_ERR_OFFLINE;
- ret = EAGAIN;
- err = "Offline";
- goto done;
- }
-
- hr = talloc_get_type(be_req_get_data(breq), struct be_host_req);
-
- if (hr->filter_type != BE_FILTER_NAME) {
- ret = EINVAL;
- err = "Invalid filter type";
- goto done;
- }
-
- req = hosts_get_send(breq, be_ctx->ev, hostid_ctx,
- hr->name, hr->alias);
- if (!req) {
- ret = ENOMEM;
- err = "Out of memory";
- goto done;
- }
-
- tevent_req_set_callback(req, ipa_host_info_hosts_done, breq);
-
- ret = EOK;
-
-done:
- if (ret != EOK) return sdap_handler_done(breq, dp_error, ret, err);
-}
-
-static void
-ipa_host_info_complete(struct be_req *breq, int dp_error,
- errno_t ret, const char *default_error_text)
-{
- const char* error_text;
-
- 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 = default_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 = default_error_text;
- }
-
- sdap_handler_done(breq, dp_error, ret, error_text);
-}
-
-static void
-ipa_host_info_hosts_done(struct tevent_req *req)
-{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
- int ret, dp_error;
-
- ret = hosts_get_recv(req, &dp_error);
- talloc_zfree(req);
-
- ipa_host_info_complete(breq, dp_error, ret, "Host lookup failed");
-}
-
static errno_t
hosts_get_retry(struct tevent_req *req);
static void
@@ -332,3 +234,82 @@ hosts_get_recv(struct tevent_req *req,
return EOK;
}
+
+struct ipa_hostid_handler_state {
+ struct dp_reply_std reply;
+};
+
+static void ipa_hostid_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_hostid_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_hostid_ctx *hostid_ctx,
+ struct dp_hostid_data *data,
+ struct dp_req_params *params)
+{
+ struct ipa_hostid_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ipa_hostid_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ subreq = hosts_get_send(state, params->ev, hostid_ctx,
+ data->name, data->alias);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request\n");
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_hostid_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 ipa_hostid_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_hostid_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 ipa_hostid_handler_state);
+
+ ret = hosts_get_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
+ipa_hostid_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct ipa_hostid_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_hostid_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
+}
diff --git a/src/providers/ipa/ipa_hostid.h b/src/providers/ipa/ipa_hostid.h
index f88c2a21d..2611e455e 100644
--- a/src/providers/ipa/ipa_hostid.h
+++ b/src/providers/ipa/ipa_hostid.h
@@ -28,6 +28,15 @@ struct ipa_hostid_ctx {
struct sdap_search_base **host_search_bases;
};
-void ipa_host_info_handler(struct be_req *be_req);
+struct tevent_req *
+ipa_hostid_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_hostid_ctx *hostid_ctx,
+ struct dp_hostid_data *data,
+ struct dp_req_params *params);
+
+errno_t
+ipa_hostid_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data);
#endif /* _IPA_HOSTID_H_ */
diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
index 29e22982c..e092cd2f8 100644
--- a/src/providers/ipa/ipa_id.c
+++ b/src/providers/ipa/ipa_id.c
@@ -30,6 +30,13 @@
#include "providers/ldap/sdap_async.h"
#include "providers/ipa/ipa_id.h"
+static struct tevent_req *
+ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+ struct ipa_id_ctx *ipa_ctx,
+ struct be_acct_req *ar);
+
+static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error);
+
static bool is_object_overridable(struct be_acct_req *ar)
{
bool ret = false;
@@ -51,129 +58,9 @@ static bool is_object_overridable(struct be_acct_req *ar)
return ret;
}
-static const char *ipa_account_info_error_text(int ret, int *dp_error,
- const char *default_text)
-{
- switch (*dp_error) {
- case DP_ERR_OK:
- if (ret == EOK) {
- return NULL;
- }
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Bug: dp_error is OK on failed request\n");
- *dp_error = DP_ERR_FATAL;
- break;
- case DP_ERR_OFFLINE:
- return "Offline";
- case DP_ERR_FATAL:
- if (ret == ENOMEM) {
- return "Out of memory";
- }
- break;
- default:
- break;
- }
-
- return default_text;
-}
-
-static struct tevent_req *
-ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
- struct ipa_id_ctx *ipa_ctx, struct be_req *be_req,
- struct be_acct_req *ar);
-
-static int ipa_id_get_account_info_recv(struct tevent_req *req, int *dp_error);
-
-static struct tevent_req *ipa_id_get_netgroup_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct ipa_id_ctx *ipa_ctx,
- const char *name);
-static int ipa_id_get_netgroup_recv(struct tevent_req *req, int *dp_error);
-
-static void ipa_account_info_done(struct tevent_req *req);
-
-void ipa_account_info_handler(struct be_req *breq)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- struct ipa_id_ctx *ipa_ctx;
- struct sdap_id_ctx *ctx;
- struct be_acct_req *ar;
- struct tevent_req *req = NULL;
-
- ipa_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct ipa_id_ctx);
- ctx = ipa_ctx->sdap_id_ctx;
-
- 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 (sdap_is_enum_request(ar)) {
- DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
- return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success");
- }
-
- if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
- /* if domain names do not match, this is a subdomain case
- * subdomain lookups are handled differently on the server
- * and the client
- */
- req = ipa_subdomain_account_send(breq, be_ctx->ev, ipa_ctx, breq, ar);
-
- } else if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
- /* netgroups are handled by a separate request function */
- if (ar->filter_type != BE_FILTER_NAME) {
- return sdap_handler_done(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
- }
- req = ipa_id_get_netgroup_send(breq, be_ctx->ev,
- ipa_ctx, ar->filter_value);
- } else {
- /* any account request is handled by sdap,
- * any invalid request is caught there. */
-
- req = ipa_id_get_account_info_send(breq, be_ctx->ev, ipa_ctx, breq,
- ar);
- }
-
- if (!req) {
- return sdap_handler_done(breq, DP_ERR_FATAL,
- ENOMEM, "Out of memory");
- }
- tevent_req_set_callback(req, ipa_account_info_done, breq);
-}
-
-static void ipa_account_info_done(struct tevent_req *req)
-{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
- struct be_acct_req *ar = talloc_get_type(be_req_get_data(breq),
- struct be_acct_req);
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- const char *error_text;
- int ret, dp_error;
-
- if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
- ret = ipa_id_get_netgroup_recv(req, &dp_error);
- } else {
- if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
- ret = ipa_subdomain_account_recv(req, &dp_error);
- } else {
- ret = ipa_id_get_account_info_recv(req, &dp_error);
- }
- }
- talloc_zfree(req);
-
- error_text = ipa_account_info_error_text(ret, &dp_error,
- "Account info lookup failed");
- sdap_handler_done(breq, dp_error, ret, error_text);
-}
-
struct ipa_resolve_user_list_state {
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
- struct be_req *be_req;
struct ldb_message_element *users;
const char *domain_name;
size_t user_idx;
@@ -186,7 +73,6 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq);
static struct tevent_req *
ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
- struct be_req *be_req,
struct ipa_id_ctx *ipa_ctx,
const char *domain_name,
struct ldb_message_element *users)
@@ -204,7 +90,6 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
state->ev = ev;
state->ipa_ctx = ipa_ctx;
- state->be_req = be_req;
state->domain_name = domain_name;
state->users = users;
state->user_idx = 0;
@@ -247,8 +132,7 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value);
- subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx,
- state->be_req, ar);
+ subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx, ar);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n");
return ENOMEM;
@@ -581,7 +465,6 @@ struct ipa_id_get_account_info_state {
struct sdap_id_op *op;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
- struct be_req *be_req;
struct be_acct_req *ar;
struct be_acct_req *orig_ar;
const char *realm;
@@ -607,7 +490,7 @@ static void ipa_id_get_user_list_done(struct tevent_req *subreq);
static struct tevent_req *
ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
- struct ipa_id_ctx *ipa_ctx, struct be_req *be_req,
+ struct ipa_id_ctx *ipa_ctx,
struct be_acct_req *ar)
{
int ret;
@@ -642,7 +525,6 @@ ipa_id_get_account_info_send(TALLOC_CTX *memctx, struct tevent_context *ev,
goto fail;
}
state->sysdb = state->domain->sysdb;
- state->be_req = be_req;
state->ar = ar;
state->realm = dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
IPA_KRB5_REALM);
@@ -855,6 +737,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
&state->obj_msg);
if (ret == ENOENT) {
DEBUG(SSSDBG_MINOR_FAILURE, "Object not found, ending request\n");
+ state->dp_error = DP_ERR_OK;
tevent_req_done(req);
return;
} else if (ret != EOK) {
@@ -939,7 +822,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
if (state->ghosts != NULL) {
/* Resolve ghost members */
- subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
+ subreq = ipa_resolve_user_list_send(state, state->ev,
state->ipa_ctx,
state->domain->name,
state->ghosts);
@@ -1019,7 +902,7 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq)
if (state->ghosts != NULL) {
/* Resolve ghost members */
- subreq = ipa_resolve_user_list_send(state, state->ev, state->be_req,
+ subreq = ipa_resolve_user_list_send(state, state->ev,
state->ipa_ctx,
state->domain->name,
state->ghosts);
@@ -1315,14 +1198,134 @@ static int ipa_id_get_netgroup_recv(struct tevent_req *req, int *dp_error)
return EOK;
}
+enum ipa_account_info_type {
+ IPA_ACCOUNT_INFO_SUBDOMAIN,
+ IPA_ACCOUNT_INFO_NETGROUP,
+ IPA_ACCOUNT_INFO_OTHER
+};
-void ipa_check_online(struct be_req *be_req)
+static enum ipa_account_info_type
+ipa_decide_account_info_type(struct be_acct_req *data, struct be_ctx *be_ctx)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ipa_id_ctx *ipa_ctx;
+ if (strcasecmp(data->domain, be_ctx->domain->name) != 0) {
+ return IPA_ACCOUNT_INFO_SUBDOMAIN;
+ } else if ((data->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_NETGROUP) {
+ return IPA_ACCOUNT_INFO_NETGROUP;
+ }
+
+ return IPA_ACCOUNT_INFO_OTHER;
+}
+
+struct ipa_account_info_handler_state {
+ enum ipa_account_info_type type;
+ struct dp_reply_std reply;
+};
+
+static void ipa_account_info_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params)
+{
+ struct ipa_account_info_handler_state *state;
+ struct tevent_req *subreq = NULL;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_account_info_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->type = ipa_decide_account_info_type(data, params->be_ctx);
+
+ if (sdap_is_enum_request(data)) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
+ ret = EOK;
+ goto immediately;
+ }
+
+ switch (state->type) {
+ case IPA_ACCOUNT_INFO_SUBDOMAIN:
+ /* Subdomain lookups are handled differently on server and client. */
+ subreq = ipa_subdomain_account_send(state, params->ev, id_ctx, data);
+ break;
+ case IPA_ACCOUNT_INFO_NETGROUP:
+ if (data->filter_type != BE_FILTER_NAME) {
+ ret = EINVAL;
+ goto immediately;
+ }
- ipa_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct ipa_id_ctx);
+ subreq = ipa_id_get_netgroup_send(state, params->ev, id_ctx,
+ data->filter_value);
+ break;
+ case IPA_ACCOUNT_INFO_OTHER:
+ subreq = ipa_id_get_account_info_send(state, params->ev, id_ctx, data);
+ break;
+ }
- return sdap_do_online_check(be_req, ipa_ctx->sdap_id_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_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 ipa_account_info_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_account_info_handler_state *state;
+ struct tevent_req *req;
+ int dp_error;
+ errno_t ret = ERR_INTERNAL;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_account_info_handler_state);
+
+ switch (state->type) {
+ case IPA_ACCOUNT_INFO_SUBDOMAIN:
+ ret = ipa_subdomain_account_recv(subreq, &dp_error);
+ break;
+ case IPA_ACCOUNT_INFO_NETGROUP:
+ ret = ipa_id_get_netgroup_recv(subreq, &dp_error);
+ break;
+ case IPA_ACCOUNT_INFO_OTHER:
+ ret = ipa_id_get_account_info_recv(subreq, &dp_error);
+ break;
+ }
+ 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 ipa_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct ipa_account_info_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_account_info_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
}
diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h
index f59bc6a8e..17db5226a 100644
--- a/src/providers/ipa/ipa_id.h
+++ b/src/providers/ipa/ipa_id.h
@@ -33,7 +33,16 @@
#define IPA_DEFAULT_VIEW_NAME "Default Trust View"
-void ipa_account_info_handler(struct be_req *breq);
+struct tevent_req *
+ipa_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params);
+
+errno_t ipa_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data);
+
struct tevent_req *ipa_get_netgroups_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sysdb_ctx *sysdb,
@@ -50,8 +59,6 @@ int ipa_get_netgroups_recv(struct tevent_req *req,
size_t *reply_count,
struct sysdb_attrs ***reply);
-void ipa_check_online(struct be_req *be_req);
-
struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
@@ -98,7 +105,6 @@ errno_t ipa_get_ad_override_recv(struct tevent_req *req, int *dp_error_out,
struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
- struct be_req *be_req,
struct be_acct_req *ar);
errno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out);
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index 6ef8ecafc..d3093b3b5 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -43,41 +43,20 @@
#include "providers/ipa/ipa_srv.h"
#include "providers/be_dyndns.h"
-struct ipa_options *ipa_options = NULL;
+#define DNS_SRV_MISCONFIGURATION "SRV discovery is enabled on the IPA " \
+ "server while using custom dns_discovery_domain. DNS discovery of " \
+ "trusted AD domain will likely fail. It is recommended not to use " \
+ "SRV discovery or the dns_discovery_domain option for the IPA " \
+ "domain while running on the server itself\n"
-/* Id Handler */
-struct bet_ops ipa_id_ops = {
- .handler = ipa_account_info_handler,
- .finalize = NULL,
- .check_online = ipa_check_online
-};
-
-struct bet_ops ipa_auth_ops = {
- .handler = ipa_auth,
- .finalize = NULL,
-};
-
-struct bet_ops ipa_chpass_ops = {
- .handler = ipa_auth,
- .finalize = NULL,
-};
-
-struct bet_ops ipa_access_ops = {
- .handler = ipa_access_handler,
- .finalize = NULL
-};
-
-struct bet_ops ipa_selinux_ops = {
- .handler = ipa_selinux_handler,
- .finalize = NULL
-};
+#define PREAUTH_INDICATOR_ERROR "Failed to create preauth indicator file, " \
+ "special password prompting might not be available.\n"
-#ifdef BUILD_SSH
-struct bet_ops ipa_hostid_ops = {
- .handler = ipa_host_info_handler,
- .finalize = NULL
+struct ipa_init_ctx {
+ struct ipa_options *options;
+ struct ipa_id_ctx *id_ctx;
+ struct ipa_auth_ctx *auth_ctx;
};
-#endif
static bool srv_in_server_list(const char *servers)
{
@@ -112,15 +91,17 @@ done:
return has_srv;
}
-int common_ipa_init(struct be_ctx *bectx)
+static errno_t ipa_init_options(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_options **_ipa_options)
{
+ struct ipa_options *ipa_options;
const char *ipa_servers;
const char *ipa_backup_servers;
- int ret;
+ errno_t ret;
- ret = ipa_get_options(bectx, bectx->cdb,
- bectx->conf_path,
- bectx->domain, &ipa_options);
+ ret = ipa_get_options(mem_ctx, be_ctx->cdb, be_ctx->conf_path,
+ be_ctx->domain, &ipa_options);
if (ret != EOK) {
return ret;
}
@@ -128,278 +109,319 @@ int common_ipa_init(struct be_ctx *bectx)
ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER);
ipa_backup_servers = dp_opt_get_string(ipa_options->basic, IPA_BACKUP_SERVER);
- ret = ipa_service_init(ipa_options, bectx, ipa_servers,
+ ret = ipa_service_init(ipa_options, be_ctx, ipa_servers,
ipa_backup_servers, ipa_options,
&ipa_options->service);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init IPA failover service!\n");
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init IPA service [%d]: %s\n",
+ ret, sss_strerror(ret));
+ talloc_free(ipa_options);
return ret;
}
+ *_ipa_options = ipa_options;
return EOK;
}
-static struct sdap_ext_member_ctx *
-ipa_create_ext_members_ctx(TALLOC_CTX *mem_ctx,
- struct ipa_id_ctx *id_ctx)
+static errno_t ipa_init_id_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx **_ipa_id_ctx)
{
- struct sdap_ext_member_ctx *ext_ctx = NULL;
+ struct ipa_id_ctx *ipa_id_ctx = NULL;
+ struct sdap_id_ctx *sdap_id_ctx = NULL;
+ errno_t ret;
- ext_ctx = talloc_zero(mem_ctx, struct sdap_ext_member_ctx);
- if (ext_ctx == NULL) {
- return NULL;
+ ipa_id_ctx = talloc_zero(mem_ctx, struct ipa_id_ctx);
+ if (ipa_id_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
}
- ext_ctx->pvt = id_ctx;
- ext_ctx->ext_member_resolve_send = ipa_ext_group_member_send;
- ext_ctx->ext_member_resolve_recv = ipa_ext_group_member_recv;
+ sdap_id_ctx = sdap_id_ctx_new(mem_ctx, be_ctx, ipa_options->service->sdap);
+ if (sdap_id_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
- return ext_ctx;
-}
+ ipa_id_ctx->ipa_options = ipa_options;
+ ipa_id_ctx->sdap_id_ctx = sdap_id_ctx;
+ ipa_options->id_ctx = ipa_id_ctx;
-int sssm_ipa_id_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
-{
- struct ipa_id_ctx *ipa_ctx;
- struct sdap_id_ctx *sdap_ctx;
- const char *hostname;
- const char *ipa_domain;
- const char *ipa_servers;
- struct ipa_srv_plugin_ctx *srv_ctx;
- bool server_mode;
- int ret;
-
- if (!ipa_options) {
- ret = common_ipa_init(bectx);
- if (ret != EOK) {
- return ret;
- }
+ ret = ipa_get_id_options(ipa_options, be_ctx->cdb, be_ctx->conf_path,
+ &sdap_id_ctx->opts);
+ if (ret != EOK) {
+ goto done;
}
- if (ipa_options->id_ctx) {
- /* already initialized */
- *ops = &ipa_id_ops;
- *pvt_data = ipa_options->id_ctx;
- return EOK;
- }
+ *_ipa_id_ctx = ipa_id_ctx;
- ipa_ctx = talloc_zero(ipa_options, struct ipa_id_ctx);
- if (!ipa_ctx) {
- return ENOMEM;
- }
- ipa_options->id_ctx = ipa_ctx;
- ipa_ctx->ipa_options = ipa_options;
+ ret = EOK;
- sdap_ctx = sdap_id_ctx_new(ipa_options, bectx, ipa_options->service->sdap);
- if (sdap_ctx == NULL) {
- return ENOMEM;
+done:
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init id context [%d]: %s\n",
+ ret, sss_strerror(ret));
+
+ talloc_free(ipa_id_ctx);
+ talloc_free(sdap_id_ctx);
}
- ipa_ctx->sdap_id_ctx = sdap_ctx;
- ret = ipa_get_id_options(ipa_options, bectx->cdb,
- bectx->conf_path,
- &sdap_ctx->opts);
+ return ret;
+}
+
+
+static errno_t ipa_init_dyndns(struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options)
+{
+ bool enabled;
+ errno_t ret;
+
+ ret = ipa_get_dyndns_options(be_ctx, ipa_options);
if (ret != EOK) {
- goto done;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get dyndns options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- ret = ipa_get_dyndns_options(bectx, ipa_options);
- if (ret != EOK) {
- goto done;
+ enabled = dp_opt_get_bool(ipa_options->dyndns_ctx->opts,
+ DP_OPT_DYNDNS_UPDATE);
+ if (!enabled) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "Dynamic DNS updates are of.\n");
+ return EOK;
}
- if (dp_opt_get_bool(ipa_options->dyndns_ctx->opts, DP_OPT_DYNDNS_UPDATE)) {
- /* Perform automatic DNS updates when the
- * IP address changes.
- * Register a callback for successful LDAP
- * reconnections. This is the easiest way to
- * identify that we have gone online.
- */
+ /* Perform automatic DNS updates when the IP address changes.
+ * Register a callback for successful LDAP reconnections.
+ * This is the easiest way to identify that we have gone online.
+ */
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Dynamic DNS updates are on. Checking for nsupdate..\n");
- ret = be_nsupdate_check();
- if (ret == EOK) {
- /* nsupdate is available. Dynamic updates
- * are supported
- */
- ret = ipa_dyndns_init(sdap_ctx->be, ipa_options);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failure setting up automatic DNS update\n");
- /* We will continue without DNS updating */
- }
- }
- }
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Dynamic DNS updates are on. Checking for nsupdate...\n");
- ret = setup_tls_config(sdap_ctx->opts->basic);
+ ret = be_nsupdate_check();
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d][%s].\n",
- ret, strerror(ret));
- goto done;
+ DEBUG(SSSDBG_CONF_SETTINGS, "nsupdate is not availabe, "
+ "dynamic DNS updates will not work\n");
+ return EOK;
}
+ DEBUG(SSSDBG_CONF_SETTINGS, "nsupdate is available\n");
- /* Set up the ID mapping object */
- ret = ipa_idmap_init(sdap_ctx, sdap_ctx, &sdap_ctx->opts->idmap_ctx);
+ ret = ipa_dyndns_init(be_ctx, ipa_options);
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");
- goto done;
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Failure setting up automatic DNS update\n");
+ /* We will continue without DNS updating */
}
+ return EOK;
+}
- ret = ldap_id_setup_tasks(sdap_ctx);
- if (ret != EOK) {
- goto done;
+static errno_t ipa_init_server_mode(struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx *ipa_id_ctx)
+{
+ const char *ipa_servers;
+ const char *dnsdomain;
+ const char *hostname;
+ bool sites_enabled;
+ errno_t ret;
+
+ ipa_id_ctx->view_name = talloc_strdup(ipa_id_ctx, SYSDB_DEFAULT_VIEW_NAME);
+ if (ipa_id_ctx->view_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup() failed.\n");
+ return ENOMEM;
}
- ret = sdap_setup_child();
+ ret = sysdb_update_view_name(be_ctx->domain->sysdb, ipa_id_ctx->view_name);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "setup_child failed [%d][%s].\n",
- ret, strerror(ret));
- goto done;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add/update view name to sysdb.\n");
+ return ret;
}
- /* setup SRV lookup plugin */
hostname = dp_opt_get_string(ipa_options->basic, IPA_HOSTNAME);
- server_mode = dp_opt_get_bool(ipa_options->basic, IPA_SERVER_MODE);
-
- if (server_mode == true) {
- ipa_ctx->view_name = talloc_strdup(ipa_ctx, SYSDB_DEFAULT_VIEW_NAME);
- if (ipa_ctx->view_name == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
- ret = ENOMEM;
- goto done;
+ ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER);
+ sites_enabled = dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES);
+ dnsdomain = dp_opt_get_string(be_ctx->be_res->opts, DP_RES_OPT_DNS_DOMAIN);
+
+ if (srv_in_server_list(ipa_servers) || sites_enabled) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "SRV resolution or IPA sites enabled "
+ "on the IPA server. Site discovery of trusted AD servers "
+ "might not work.\n");
+
+ /* If SRV discovery is enabled on the server and
+ * dns_discovery_domain is set explicitly, then
+ * the current failover code would use the dns_discovery
+ * domain to try to find AD servers and fail.
+ */
+ if (dnsdomain != NULL) {
+ sss_log(SSS_LOG_ERR, DNS_SRV_MISCONFIGURATION);
+ DEBUG(SSSDBG_CRIT_FAILURE, DNS_SRV_MISCONFIGURATION);
}
- ret = sysdb_update_view_name(bectx->domain->sysdb, ipa_ctx->view_name);
+ ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, hostname);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot add/update view name to sysdb.\n");
- goto done;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
}
- ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER);
- if (srv_in_server_list(ipa_servers) == true
- || dp_opt_get_bool(ipa_options->basic,
- IPA_ENABLE_DNS_SITES) == true) {
- DEBUG(SSSDBG_MINOR_FAILURE, "SRV resolution or IPA sites enabled "
- "on the IPA server. Site discovery of trusted AD servers "
- "might not work\n");
-
- /* If SRV discovery is enabled on the server and
- * dns_discovery_domain is set explicitly, then
- * the current failover code would use the dns_discovery
- * domain to try to find AD servers and fail
- */
- if (dp_opt_get_string(bectx->be_res->opts,
- DP_RES_OPT_DNS_DOMAIN)) {
- sss_log(SSS_LOG_ERR, ("SRV discovery is enabled on the IPA "
- "server while using custom dns_discovery_domain. "
- "DNS discovery of trusted AD domain will likely fail. "
- "It is recommended not to use SRV discovery or the "
- "dns_discovery_domain option for the IPA domain while "
- "running on the server itself\n"));
- DEBUG(SSSDBG_CRIT_FAILURE, "SRV discovery is enabled on IPA "
- "server while using custom dns_discovery_domain. "
- "DNS discovery of trusted AD domain will likely fail. "
- "It is recommended not to use SRV discovery or the "
- "dns_discovery_domain option for the IPA domain while "
- "running on the server itself\n");
- }
-
- ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
- "[%d]: %s\n", ret, strerror(ret));
- goto done;
- }
+ return EOK;
+ } else {
+ /* In server mode we need to ignore the dns_discovery_domain if set
+ * and only discover servers based on AD domains. */
+ ret = dp_opt_set_string(be_ctx->be_res->opts, DP_RES_OPT_DNS_DOMAIN,
+ NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Could not reset the "
+ "dns_discovery_domain, trusted AD domains discovery "
+ "might fail. Please remove dns_discovery_domain "
+ "from the config file and restart the SSSD\n");
} else {
- /* In server mode we need to ignore the dns_discovery_domain if set
- * and only discover servers based on AD domains
- */
- ret = dp_opt_set_string(bectx->be_res->opts, DP_RES_OPT_DNS_DOMAIN,
- NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Could not reset the "
- "dns_discovery_domain, trusted AD domains discovery "
- "might fail. Please remove dns_discovery_domain "
- "from the config file and restart the SSSD\n");
- } else {
- DEBUG(SSSDBG_CONF_SETTINGS, "The value of dns_discovery_domain "
- "will be ignored in ipa_server_mode\n");
- }
+ DEBUG(SSSDBG_CONF_SETTINGS, "The value of dns_discovery_domain "
+ "will be ignored in ipa_server_mode\n");
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t ipa_init_client_mode(struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx *ipa_id_ctx)
+{
+ struct ipa_srv_plugin_ctx *srv_ctx;
+ const char *ipa_domain;
+ const char *hostname;
+ bool sites_enabled;
+ errno_t ret;
+
+ ret = sysdb_get_view_name(ipa_id_ctx, be_ctx->domain->sysdb,
+ &ipa_id_ctx->view_name);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find view name in the cache. "
+ "Will do online lookup later.\n");
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ hostname = dp_opt_get_string(ipa_options->basic, IPA_HOSTNAME);
+ sites_enabled = dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES);
+
+ if (sites_enabled) {
+ /* use IPA plugin */
+ ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN);
+ srv_ctx = ipa_srv_plugin_ctx_init(be_ctx, be_ctx->be_res->resolv,
+ hostname, ipa_domain);
+ if (srv_ctx == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
+ return ENOMEM;
}
+
+ be_fo_set_srv_lookup_plugin(be_ctx, ipa_srv_plugin_send,
+ ipa_srv_plugin_recv, srv_ctx, "IPA");
} else {
- ret = sysdb_get_view_name(ipa_ctx, bectx->domain->sysdb,
- &ipa_ctx->view_name);
+ /* fall back to standard plugin on clients. */
+ ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, hostname);
if (ret != EOK) {
- if (ret == ENOENT) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot find view name in the cache. " \
- "Will do online lookup later.\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
- goto done;
- }
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
+ "[%d]: %s\n", ret, strerror(ret));
+ return ret;
}
+ }
- if (dp_opt_get_bool(ipa_options->basic, IPA_ENABLE_DNS_SITES)) {
- /* use IPA plugin */
- ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN);
- srv_ctx = ipa_srv_plugin_ctx_init(bectx, bectx->be_res->resolv,
- hostname, ipa_domain);
- if (srv_ctx == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
- ret = ENOMEM;
- goto done;
- }
-
- be_fo_set_srv_lookup_plugin(bectx, ipa_srv_plugin_send,
- ipa_srv_plugin_recv, srv_ctx, "IPA");
- } else {
- /* fall back to standard plugin on clients. */
- ret = be_fo_set_dns_srv_lookup_plugin(bectx, hostname);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin "
- "[%d]: %s\n", ret, strerror(ret));
- goto done;
- }
- }
+ return EOK;
+}
+
+static errno_t ipa_init_ipa_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx *ipa_id_ctx,
+ struct ipa_auth_ctx **_ipa_auth_ctx)
+{
+ struct ipa_auth_ctx *ipa_auth_ctx;
+ errno_t ret;
+
+ ipa_auth_ctx = talloc_zero(mem_ctx, struct ipa_auth_ctx);
+ if (ipa_auth_ctx == NULL) {
+ return ENOMEM;
}
- /* setup periodical refresh of expired records */
- ret = sdap_refresh_init(bectx->refresh_ctx, sdap_ctx);
- if (ret != EOK && ret != EEXIST) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
- "will not work [%d]: %s\n", ret, strerror(ret));
+ ipa_auth_ctx->sdap_id_ctx = ipa_id_ctx->sdap_id_ctx;
+
+ ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic,
+ IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options failed.\n");
+ talloc_free(ipa_auth_ctx);
+ return ret;
}
- ipa_ctx->sdap_id_ctx->opts->ext_ctx = ipa_create_ext_members_ctx(
- ipa_ctx->sdap_id_ctx->opts,
- ipa_ctx);
- if (ipa_ctx->sdap_id_ctx->opts->ext_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Unable to set SRV the extrernal group ctx\n");
- ret = ENOMEM;
- goto done;
+ *_ipa_auth_ctx = ipa_auth_ctx;
+
+ return EOK;
+}
+
+static errno_t ipa_init_krb5_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct krb5_ctx **_krb5_auth_ctx)
+{
+ struct krb5_ctx *krb5_auth_ctx;
+ bool server_mode;
+ errno_t ret;
+
+ krb5_auth_ctx = talloc_zero(mem_ctx, struct krb5_ctx);
+ if (krb5_auth_ctx == NULL) {
+ return ENOMEM;
}
- *ops = &ipa_id_ops;
- *pvt_data = ipa_ctx;
- ret = EOK;
+ krb5_auth_ctx->service = ipa_options->service->krb5_service;
-done:
+ server_mode = dp_opt_get_bool(ipa_options->basic, IPA_SERVER_MODE);
+ krb5_auth_ctx->config_type = server_mode ? K5C_IPA_SERVER : K5C_IPA_CLIENT;
+
+ ret = ipa_get_auth_options(ipa_options, be_ctx->cdb, be_ctx->conf_path,
+ &krb5_auth_ctx->opts);
if (ret != EOK) {
- talloc_zfree(ipa_options->id_ctx);
+ talloc_free(krb5_auth_ctx);
+ return ret;
}
- return ret;
+
+ *_krb5_auth_ctx = krb5_auth_ctx;
+ return EOK;
+}
+
+static errno_t ipa_init_sdap_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct sdap_auth_ctx **_sdap_auth_ctx)
+{
+ struct sdap_auth_ctx *sdap_auth_ctx;
+
+ sdap_auth_ctx = talloc_zero(mem_ctx, struct sdap_auth_ctx);
+ if (sdap_auth_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ sdap_auth_ctx->be = be_ctx;
+ sdap_auth_ctx->service = ipa_options->service->sdap;
+
+ if (ipa_options->id == NULL) {
+ talloc_free(sdap_auth_ctx);
+ return EINVAL;
+ }
+
+ sdap_auth_ctx->opts = ipa_options->id;
+
+ *_sdap_auth_ctx = sdap_auth_ctx;
+
+ return EOK;
}
-void cleanup_ipa_preauth_indicator(void)
+static void cleanup_ipa_preauth_indicator(void)
{
int ret;
@@ -413,8 +435,8 @@ void cleanup_ipa_preauth_indicator(void)
static errno_t create_ipa_preauth_indicator(void)
{
- int ret;
- TALLOC_CTX *tmp_ctx = NULL;
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
int fd;
tmp_ctx = talloc_new(NULL);
@@ -455,324 +477,452 @@ done:
return ret;
}
-int sssm_ipa_auth_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+static struct sdap_ext_member_ctx *
+ipa_create_ext_members_ctx(TALLOC_CTX *mem_ctx,
+ struct ipa_id_ctx *id_ctx)
+{
+ struct sdap_ext_member_ctx *ext_ctx = NULL;
+
+ ext_ctx = talloc_zero(mem_ctx, struct sdap_ext_member_ctx);
+ if (ext_ctx == NULL) {
+ return NULL;
+ }
+
+ ext_ctx->pvt = id_ctx;
+ ext_ctx->ext_member_resolve_send = ipa_ext_group_member_send;
+ ext_ctx->ext_member_resolve_recv = ipa_ext_group_member_recv;
+
+ return ext_ctx;
+}
+
+static errno_t ipa_init_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx *id_ctx,
+ struct ipa_auth_ctx **_auth_ctx)
{
+ struct sdap_auth_ctx *sdap_auth_ctx;
struct ipa_auth_ctx *ipa_auth_ctx;
- struct ipa_id_ctx *id_ctx;
struct krb5_ctx *krb5_auth_ctx;
- struct sdap_auth_ctx *sdap_auth_ctx;
- struct bet_ops *id_ops;
- int ret;
+ errno_t ret;
- if (!ipa_options) {
- ret = common_ipa_init(bectx);
- if (ret != EOK) {
- return ret;
- }
+ ret = ipa_init_ipa_auth_ctx(mem_ctx, ipa_options, id_ctx, &ipa_auth_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init IPA auth context\n");
+ return ret;
}
- if (ipa_options->auth_ctx) {
- /* already initialized */
- *ops = &ipa_auth_ops;
- *pvt_data = ipa_options->auth_ctx;
- return EOK;
- }
+ ipa_options->auth_ctx = ipa_auth_ctx;
- ipa_auth_ctx = talloc_zero(ipa_options, struct ipa_auth_ctx);
- if (!ipa_auth_ctx) {
- return ENOMEM;
+ ret = ipa_init_krb5_auth_ctx(ipa_auth_ctx, be_ctx, ipa_options,
+ &krb5_auth_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init KRB5 auth context\n");
+ goto done;
}
- ipa_options->auth_ctx = ipa_auth_ctx;
+ ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx;
- ret = sssm_ipa_id_init(bectx, &id_ops, (void **) &id_ctx);
+ ret = ipa_init_sdap_auth_ctx(ipa_auth_ctx, be_ctx, ipa_options,
+ &sdap_auth_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init SDAP auth context\n");
goto done;
}
- ipa_auth_ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
+ ipa_options->auth_ctx->sdap_auth_ctx = sdap_auth_ctx;
- ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic,
- IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options);
+ ret = setup_tls_config(sdap_auth_ctx->opts->basic);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- krb5_auth_ctx = talloc_zero(ipa_auth_ctx, struct krb5_ctx);
- if (!krb5_auth_ctx) {
- ret = ENOMEM;
+ /* Initialize features needed by the krb5_child */
+ ret = krb5_child_init(krb5_auth_ctx, be_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize krb5_child "
+ "settings [%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- krb5_auth_ctx->service = ipa_options->service->krb5_service;
- if (dp_opt_get_bool(id_ctx->ipa_options->basic,
- IPA_SERVER_MODE) == true) {
- krb5_auth_ctx->config_type = K5C_IPA_SERVER;
- } else {
- krb5_auth_ctx->config_type = K5C_IPA_CLIENT;
+ ret = create_ipa_preauth_indicator();
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, PREAUTH_INDICATOR_ERROR);
+ sss_log(SSSDBG_CRIT_FAILURE, PREAUTH_INDICATOR_ERROR);
}
- ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx;
- ret = ipa_get_auth_options(ipa_options, bectx->cdb, bectx->conf_path,
- &krb5_auth_ctx->opts);
+ *_auth_ctx = ipa_auth_ctx;
+ ret = EOK;
+
+done:
if (ret != EOK) {
- goto done;
+ talloc_free(ipa_auth_ctx);
}
- sdap_auth_ctx = talloc_zero(ipa_auth_ctx, struct sdap_auth_ctx);
- if (!sdap_auth_ctx) {
- ret = ENOMEM;
- goto done;
+ return ret;
+}
+
+static errno_t ipa_init_misc(struct be_ctx *be_ctx,
+ struct ipa_options *ipa_options,
+ struct ipa_id_ctx *ipa_id_ctx,
+ struct sdap_id_ctx *sdap_id_ctx)
+{
+ errno_t ret;
+
+ ret = ipa_init_dyndns(be_ctx, ipa_options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init dyndns [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- sdap_auth_ctx->be = bectx;
- sdap_auth_ctx->service = ipa_options->service->sdap;
- if (ipa_options->id == NULL) {
- ret = EINVAL;
- goto done;
+ ret = setup_tls_config(sdap_id_ctx->opts->basic);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get TLS options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- sdap_auth_ctx->opts = ipa_options->id;
- ipa_options->auth_ctx->sdap_auth_ctx = sdap_auth_ctx;
+ ret = ipa_idmap_init(sdap_id_ctx, sdap_id_ctx,
+ &sdap_id_ctx->opts->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 = setup_tls_config(sdap_auth_ctx->opts->basic);
+ ret = ldap_id_setup_tasks(sdap_id_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "setup_tls_config failed [%d][%s].\n",
- ret, strerror(ret));
+ 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;
+ }
+
+ if (dp_opt_get_bool(ipa_options->basic, IPA_SERVER_MODE)) {
+ ret = ipa_init_server_mode(be_ctx, ipa_options, ipa_id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init server mode "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
+ } else {
+ ret = ipa_init_client_mode(be_ctx, ipa_options, ipa_id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init client mode "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
+ }
+
+ ret = sdap_refresh_init(be_ctx->refresh_ctx, sdap_id_ctx);
+ if (ret != EOK && ret != EEXIST) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Periodical refresh "
+ "will not work [%d]: %s\n", ret, sss_strerror(ret));
+ }
+
+ ipa_id_ctx->sdap_id_ctx->opts->ext_ctx = ipa_create_ext_members_ctx(
+ ipa_id_ctx->sdap_id_ctx->opts, ipa_id_ctx);
+ if (ipa_id_ctx->sdap_id_ctx->opts->ext_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set the extrernal group ctx\n");
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+errno_t sssm_ipa_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct data_provider *provider,
+ const char *module_name,
+ void **_module_data)
+{
+ struct ipa_init_ctx *init_ctx;
+ errno_t ret;
+
+ init_ctx = talloc_zero(mem_ctx, struct ipa_init_ctx);
+ if (init_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ /* Always initialize options since it is needed everywhere. */
+ ret = ipa_init_options(init_ctx, be_ctx, &init_ctx->options);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init IPA options "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- /* Initialize features needed by the krb5_child */
- ret = krb5_child_init(krb5_auth_ctx, bectx);
+ /* Always initialize id_ctx since it is needed everywhere. */
+ ret = ipa_init_id_ctx(init_ctx, be_ctx, init_ctx->options,
+ &init_ctx->id_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not initialize krb5_child settings: [%s]\n",
- strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init IPA ID context "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- ret = create_ipa_preauth_indicator();
+ /* Setup miscellaneous things. */
+ ret = ipa_init_misc(be_ctx, init_ctx->options, init_ctx->id_ctx,
+ init_ctx->id_ctx->sdap_id_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failed to create preauth indicator file, special password "
- "prompting might not be available.\n");
- sss_log(SSSDBG_CRIT_FAILURE,
- "Failed to create preauth indicator file, special password "
- "prompting might not be available.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init IPA 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 = ipa_init_auth_ctx(init_ctx, be_ctx, init_ctx->options,
+ init_ctx->id_ctx, &init_ctx->auth_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init IPA auth context "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
}
- *ops = &ipa_auth_ops;
- *pvt_data = ipa_auth_ctx;
+ *_module_data = init_ctx;
+
ret = EOK;
done:
if (ret != EOK) {
- talloc_zfree(ipa_options->auth_ctx);
+ talloc_free(init_ctx);
}
+
return ret;
}
-int sssm_ipa_chpass_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_id_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- ret = sssm_ipa_auth_init(bectx, ops, pvt_data);
- *ops = &ipa_chpass_ops;
- return ret;
+ struct ipa_init_ctx *init_ctx;
+ struct ipa_id_ctx *id_ctx;
+
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
+ id_ctx = init_ctx->id_ctx;
+
+ dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER,
+ ipa_account_info_handler_send, ipa_account_info_handler_recv, id_ctx,
+ struct ipa_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->sdap_id_ctx,
+ struct sdap_id_ctx, void, struct dp_reply_std);
+
+ return EOK;
}
-int sssm_ipa_access_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_auth_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- struct ipa_access_ctx *ipa_access_ctx;
+ struct ipa_init_ctx *init_ctx;
+ struct ipa_auth_ctx *auth_ctx;
+
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
+ auth_ctx = init_ctx->auth_ctx;
+
+ dp_set_method(dp_methods, DPM_AUTH_HANDLER,
+ ipa_pam_auth_handler_send, ipa_pam_auth_handler_recv, auth_ctx,
+ struct ipa_auth_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
+}
+
+errno_t sssm_ipa_chpass_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ return sssm_ipa_auth_init(mem_ctx, be_ctx, module_data, dp_methods);
+}
+
+errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ struct ipa_access_ctx *access_ctx;
+ struct ipa_init_ctx *init_ctx;
struct ipa_id_ctx *id_ctx;
+ errno_t ret;
- ipa_access_ctx = talloc_zero(bectx, struct ipa_access_ctx);
- if (ipa_access_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
+ id_ctx = init_ctx->id_ctx;
+
+ access_ctx = talloc_zero(mem_ctx, struct ipa_access_ctx);
+ if (access_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed.\n");
return ENOMEM;
}
- ret = sssm_ipa_id_init(bectx, ops, (void **) &id_ctx);
+ access_ctx->sdap_ctx = id_ctx->sdap_id_ctx;
+ access_ctx->host_map = id_ctx->ipa_options->host_map;
+ access_ctx->hostgroup_map = id_ctx->ipa_options->hostgroup_map;
+ access_ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
+ access_ctx->hbac_search_bases = id_ctx->ipa_options->hbac_search_bases;
+
+ ret = dp_copy_options(access_ctx, id_ctx->ipa_options->basic,
+ IPA_OPTS_BASIC, &access_ctx->ipa_options);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options() failed.\n");
goto done;
}
- ipa_access_ctx->sdap_ctx = id_ctx->sdap_id_ctx;
- ipa_access_ctx->host_map = id_ctx->ipa_options->host_map;
- ipa_access_ctx->hostgroup_map = id_ctx->ipa_options->hostgroup_map;
- ipa_access_ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
- ipa_access_ctx->hbac_search_bases = id_ctx->ipa_options->hbac_search_bases;
- ret = dp_copy_options(ipa_access_ctx, ipa_options->basic,
- IPA_OPTS_BASIC, &ipa_access_ctx->ipa_options);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "dp_copy_options failed.\n");
+ /* Set up an sdap_access_ctx for checking expired/locked accounts. */
+ access_ctx->sdap_access_ctx = talloc_zero(access_ctx, struct sdap_access_ctx);
+ if (access_ctx->sdap_access_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
+ ret = ENOMEM;
goto done;
}
- /* Set up an sdap_access_ctx for checking expired/locked
- * accounts.
- */
- ipa_access_ctx->sdap_access_ctx =
- talloc_zero(ipa_access_ctx, struct sdap_access_ctx);
+ access_ctx->sdap_access_ctx->id_ctx = access_ctx->sdap_ctx;
+ access_ctx->sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
+ access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
- ipa_access_ctx->sdap_access_ctx->id_ctx = ipa_access_ctx->sdap_ctx;
- ipa_access_ctx->sdap_access_ctx->access_rule[0] = LDAP_ACCESS_EXPIRE;
- ipa_access_ctx->sdap_access_ctx->access_rule[1] = LDAP_ACCESS_EMPTY;
+ dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+ ipa_pam_access_handler_send, ipa_pam_access_handler_recv, access_ctx,
+ struct ipa_access_ctx, struct pam_data, struct pam_data *);
- *ops = &ipa_access_ops;
- *pvt_data = ipa_access_ctx;
+ ret = EOK;
done:
if (ret != EOK) {
- talloc_free(ipa_access_ctx);
+ talloc_free(access_ctx);
}
+
return ret;
}
-int sssm_ipa_selinux_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_selinux_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
+#if defined HAVE_SELINUX && defined HAVE_SELINUX_LOGIN_DIR
struct ipa_selinux_ctx *selinux_ctx;
+ struct ipa_init_ctx *init_ctx;
struct ipa_options *opts;
- selinux_ctx = talloc_zero(bectx, struct ipa_selinux_ctx);
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
+ opts = init_ctx->options;
+
+ selinux_ctx = talloc_zero(mem_ctx, struct ipa_selinux_ctx);
if (selinux_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed.\n");
return ENOMEM;
}
- ret = sssm_ipa_id_init(bectx, ops, (void **) &selinux_ctx->id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
- goto done;
- }
-
- opts = selinux_ctx->id_ctx->ipa_options;
-
+ selinux_ctx->id_ctx = init_ctx->id_ctx;
selinux_ctx->hbac_search_bases = opts->hbac_search_bases;
selinux_ctx->host_search_bases = opts->host_search_bases;
selinux_ctx->selinux_search_bases = opts->selinux_search_bases;
- *ops = &ipa_selinux_ops;
- *pvt_data = selinux_ctx;
+ dp_set_method(dp_methods, DPM_SELINUX_HANDLER,
+ ipa_selinux_handler_send, ipa_selinux_handler_recv, selinux_ctx,
+ struct ipa_selinux_ctx, struct pam_data, struct pam_data *);
-done:
- if (ret != EOK) {
- talloc_free(selinux_ctx);
- }
- return ret;
+ return EOK;
+#else
+ DEBUG(SSSDBG_MINOR_FAILURE, "SELinux init handler called but SSSD is "
+ "built without SSH support, ignoring\n");
+ return EOK;
+#endif
}
-#ifdef BUILD_SSH
-int sssm_ipa_hostid_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_hostid_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
+#ifdef BUILD_SSH
struct ipa_hostid_ctx *hostid_ctx;
- struct ipa_id_ctx *id_ctx;
+ struct ipa_init_ctx *init_ctx;
+
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
- hostid_ctx = talloc_zero(bectx, struct ipa_hostid_ctx);
+ hostid_ctx = talloc_zero(mem_ctx, struct ipa_hostid_ctx);
if (hostid_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
return ENOMEM;
}
- ret = sssm_ipa_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
- goto done;
- }
- hostid_ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
- hostid_ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
- hostid_ctx->ipa_opts = ipa_options;
+ hostid_ctx->sdap_id_ctx = init_ctx->id_ctx->sdap_id_ctx;
+ hostid_ctx->host_search_bases = init_ctx->options->host_search_bases;
+ hostid_ctx->ipa_opts = init_ctx->options;
- *ops = &ipa_hostid_ops;
- *pvt_data = hostid_ctx;
+ dp_set_method(dp_methods, DPM_HOSTID_HANDLER,
+ ipa_hostid_handler_send, ipa_hostid_handler_recv, hostid_ctx,
+ struct ipa_hostid_ctx, struct dp_hostid_data, struct dp_reply_std);
-done:
- if (ret != EOK) {
- talloc_free(hostid_ctx);
- }
- return ret;
-}
+ return EOK;
+#else
+ DEBUG(SSSDBG_MINOR_FAILURE, "HostID init handler called but SSSD is "
+ "built without SSH support, ignoring\n");
+ return EOK;
#endif
+}
-int sssm_ipa_autofs_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_autofs_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
#ifdef BUILD_AUTOFS
- struct ipa_id_ctx *id_ctx;
- int ret;
+ struct ipa_init_ctx *init_ctx;
DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA autofs handler\n");
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
- ret = sssm_ipa_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
- return ret;
- }
-
- return ipa_autofs_init(bectx, id_ctx, ops, pvt_data);
+ return ipa_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");
+ "built without autofs support, ignoring\n");
return EOK;
#endif
}
-int sssm_ipa_subdomains_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- struct ipa_id_ctx *id_ctx;
+ struct ipa_init_ctx *init_ctx;
- ret = sssm_ipa_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
- return ret;
- }
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA subdomains handler\n");
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
- ret = ipa_subdom_init(bectx, id_ctx, ops, pvt_data);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "ipa_subdom_init failed.\n");
- return ret;
- }
-
- return EOK;
+ return ipa_subdomains_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods);
}
-int sssm_ipa_sudo_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_ipa_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
#ifdef BUILD_SUDO
- struct ipa_id_ctx *id_ctx;
- int ret;
+ struct ipa_init_ctx *init_ctx;
DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA sudo handler\n");
+ init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
- ret = sssm_ipa_id_init(bectx, ops, (void **) &id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "sssm_ipa_id_init failed.\n");
- return ret;
- }
-
- return ipa_sudo_init(bectx, id_ctx, ops, pvt_data);
+ return ipa_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");
+ "built without sudo support, ignoring\n");
return EOK;
#endif
}
diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
index 13eabc00b..78fe9e3d2 100644
--- a/src/providers/ipa/ipa_selinux.c
+++ b/src/providers/ipa/ipa_selinux.c
@@ -37,8 +37,6 @@
#include "providers/ipa/ipa_selinux_maps.h"
#include "providers/ipa/ipa_subdomains.h"
-#if defined HAVE_SELINUX && defined HAVE_SELINUX_LOGIN_DIR
-
#ifndef SELINUX_CHILD_DIR
#ifndef SSSD_LIBEXEC_PATH
#error "SSSD_LIBEXEC_PATH not defined"
@@ -70,15 +68,6 @@ static errno_t ipa_get_selinux_recv(struct tevent_req *req,
char **default_user,
char **map_order);
-static struct ipa_selinux_op_ctx *
-ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
- struct sss_domain_info *ipa_domain,
- struct sss_domain_info *user_domain,
- struct be_req *be_req, const char *username,
- const char *hostname,
- struct ipa_selinux_ctx *selinux_ctx);
-static void ipa_selinux_handler_done(struct tevent_req *subreq);
-
static void ipa_get_selinux_connect_done(struct tevent_req *subreq);
static void ipa_get_selinux_hosts_done(struct tevent_req *subreq);
static void ipa_get_config_step(struct tevent_req *req);
@@ -94,83 +83,6 @@ static errno_t ipa_selinux_process_maps(TALLOC_CTX *mem_ctx,
size_t hbac_rule_count,
struct sysdb_attrs ***usermaps);
-struct ipa_selinux_op_ctx {
- struct be_req *be_req;
- struct sss_domain_info *user_domain;
- struct sss_domain_info *ipa_domain;
- struct ipa_selinux_ctx *selinux_ctx;
-
- struct sysdb_attrs *user;
- struct sysdb_attrs *host;
-};
-
-void ipa_selinux_handler(struct be_req *be_req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ipa_selinux_ctx *selinux_ctx;
- struct ipa_selinux_op_ctx *op_ctx;
- struct tevent_req *req;
- struct pam_data *pd;
- const char *hostname;
- struct sss_domain_info *user_domain;
- struct be_ctx *subdom_be_ctx;
-
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
-
- selinux_ctx = talloc_get_type(be_ctx->bet_info[BET_SELINUX].pvt_bet_data,
- struct ipa_selinux_ctx);
-
- hostname = dp_opt_get_string(selinux_ctx->id_ctx->ipa_options->basic,
- IPA_HOSTNAME);
- if (!hostname) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot determine this machine's host name\n");
- goto fail;
- }
-
- if (strcasecmp(pd->domain, be_ctx->domain->name) != 0) {
- subdom_be_ctx = ipa_get_subdomains_be_ctx(be_ctx);
- if (subdom_be_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Subdomains are not configured, " \
- "cannot lookup domain [%s].\n",
- pd->domain);
- goto fail;
- } else {
- user_domain = find_domain_by_name(subdom_be_ctx->domain,
- pd->domain, true);
- if (user_domain == NULL) {
- DEBUG(SSSDBG_MINOR_FAILURE, "No domain entry found " \
- "for [%s].\n", pd->domain);
- goto fail;
- }
- }
- } else {
- user_domain = be_ctx->domain;
- }
-
- op_ctx = ipa_selinux_create_op_ctx(be_req, user_domain->sysdb,
- be_ctx->domain,
- user_domain,
- be_req, pd->user, hostname,
- selinux_ctx);
- if (op_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot create op context\n");
- goto fail;
- }
-
- req = ipa_get_selinux_send(be_req, be_ctx,
- op_ctx->user, op_ctx->host, selinux_ctx);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot initiate the search\n");
- goto fail;
- }
-
- tevent_req_set_callback(req, ipa_selinux_handler_done, op_ctx);
- return;
-
-fail:
- be_req_terminate(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
-}
-
static errno_t
ipa_save_user_maps(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
@@ -217,246 +129,18 @@ done:
return ret;
}
-static struct ipa_selinux_op_ctx *
-ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
- struct sss_domain_info *ipa_domain,
- struct sss_domain_info *user_domain,
- struct be_req *be_req, const char *username,
- const char *hostname,
- struct ipa_selinux_ctx *selinux_ctx)
-{
- struct ipa_selinux_op_ctx *op_ctx;
- struct ldb_dn *host_dn;
- const char *attrs[] = { SYSDB_ORIG_DN,
- SYSDB_ORIG_MEMBEROF,
- NULL };
- size_t count;
- struct ldb_message **msgs;
- struct sysdb_attrs **hosts;
- errno_t ret;
-
- op_ctx = talloc_zero(mem_ctx, struct ipa_selinux_op_ctx);
- if (op_ctx == NULL) {
- return NULL;
- }
- op_ctx->be_req = be_req;
- op_ctx->ipa_domain = ipa_domain;
- op_ctx->user_domain = user_domain;
- op_ctx->selinux_ctx = selinux_ctx;
-
- ret = sss_selinux_extract_user(op_ctx, user_domain, username, &op_ctx->user);
- if (ret != EOK) {
- goto fail;
- }
-
- host_dn = sysdb_custom_dn(op_ctx, ipa_domain, hostname, HBAC_HOSTS_SUBDIR);
- if (host_dn == NULL) {
- goto fail;
- }
-
- /* Look up the host to get its originalMemberOf entries */
- ret = sysdb_search_entry(op_ctx, sysdb, host_dn,
- LDB_SCOPE_BASE, NULL,
- attrs, &count, &msgs);
- if (ret == ENOENT || count == 0) {
- op_ctx->host = NULL;
- return op_ctx;
- } else if (ret != EOK) {
- goto fail;
- } else if (count > 1) {
- DEBUG(SSSDBG_OP_FAILURE, "More than one result for a BASE search!\n");
- goto fail;
- }
-
- ret = sysdb_msg2attrs(op_ctx, count, msgs, &hosts);
- talloc_free(msgs);
- if (ret != EOK) {
- goto fail;
- }
-
- op_ctx->host = hosts[0];
- return op_ctx;
-
-fail:
- talloc_free(op_ctx);
- return NULL;
-}
-
struct map_order_ctx {
char *order;
char **order_array;
size_t order_count;
};
-static errno_t init_map_order_ctx(TALLOC_CTX *mem_ctx, const char *map_order,
- struct map_order_ctx **_mo_ctx);
-
struct selinux_child_input {
const char *seuser;
const char *mls_range;
const char *username;
};
-static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx,
- struct sysdb_attrs **usermaps,
- struct pam_data *pd,
- struct sss_domain_info *user_domain,
- struct map_order_ctx *mo_ctx,
- const char *default_user,
- struct selinux_child_input **_sci);
-
-static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct selinux_child_input *sci);
-static errno_t selinux_child_recv(struct tevent_req *req);
-
-static void ipa_selinux_child_done(struct tevent_req *child_req);
-
-static void ipa_selinux_handler_done(struct tevent_req *req)
-{
- struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx);
- struct be_req *breq = op_ctx->be_req;
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- struct sysdb_ctx *sysdb = op_ctx->ipa_domain->sysdb;
- errno_t ret, sret;
- size_t map_count = 0;
- struct sysdb_attrs **maps = NULL;
- bool in_transaction = false;
- char *default_user = NULL;
- struct pam_data *pd =
- talloc_get_type(be_req_get_data(breq), struct pam_data);
- char *map_order = NULL;
- size_t hbac_count = 0;
- struct sysdb_attrs **hbac_rules = 0;
- struct sysdb_attrs **best_match_maps;
- struct map_order_ctx *map_order_ctx;
- struct selinux_child_input *sci = NULL;
- struct tevent_req *child_req;
-
- ret = ipa_get_selinux_recv(req, breq, &map_count, &maps,
- &hbac_count, &hbac_rules,
- &default_user, &map_order);
- if (ret != EOK) {
- goto fail;
- }
-
- ret = sysdb_transaction_start(sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
- goto fail;
- }
- in_transaction = true;
-
- ret = sysdb_delete_usermaps(op_ctx->ipa_domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot delete existing maps from sysdb\n");
- goto fail;
- }
-
- ret = sysdb_store_selinux_config(op_ctx->ipa_domain,
- default_user, map_order);
- if (ret != EOK) {
- goto fail;
- }
-
- if (map_count > 0) {
- ret = ipa_save_user_maps(sysdb, op_ctx->ipa_domain, map_count, maps);
- if (ret != EOK) {
- goto fail;
- }
- }
-
- ret = sysdb_transaction_commit(sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not commit transaction\n");
- goto fail;
- }
- in_transaction = false;
-
- /* Process the maps and return list of best matches (maps with
- * highest priority). The input maps are also parent memory
- * context for the output list of best matches. The best match
- * maps should never be freed explicitly but always through
- * their parent (or any indirect parent) */
- ret = ipa_selinux_process_maps(maps, op_ctx->user, op_ctx->host,
- maps, map_count,
- hbac_rules, hbac_count, &best_match_maps);
- if (ret != EOK) {
- goto fail;
- }
-
- ret = init_map_order_ctx(op_ctx, map_order, &map_order_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failed to create ordered SELinux users array.\n");
- goto fail;
- }
-
- ret = choose_best_seuser(breq,
- best_match_maps, pd, op_ctx->user_domain,
- map_order_ctx, default_user, &sci);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Failed to evaluate ordered SELinux users array.\n");
- goto fail;
- }
-
- /* Update the SELinux context in a privileged child as the back end is
- * running unprivileged
- */
- child_req = selinux_child_send(breq, be_ctx->ev, sci);
- if (child_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "selinux_child_send() failed\n");
- ret = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(child_req, ipa_selinux_child_done, op_ctx);
- return;
-
-fail:
- if (in_transaction) {
- sret = sysdb_transaction_cancel(sysdb);
- if (sret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
- }
- }
- if (ret == EAGAIN) {
- be_req_terminate(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
- } else {
- be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
- }
-}
-
-static void ipa_selinux_child_done(struct tevent_req *child_req)
-{
- errno_t ret;
- struct ipa_selinux_op_ctx *op_ctx;
- struct be_req *breq;
- struct pam_data *pd;
- struct be_ctx *be_ctx;
-
- op_ctx = tevent_req_callback_data(child_req, struct ipa_selinux_op_ctx);
- breq = op_ctx->be_req;
- pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
- be_ctx = be_req_get_be_ctx(breq);
-
- ret = selinux_child_recv(child_req);
- talloc_free(child_req);
- if (ret != EOK) {
- be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
- return;
- }
-
- /* If we got here in online mode, set last_update to current time */
- if (!be_is_offline(be_ctx)) {
- op_ctx->selinux_ctx->last_update = time(NULL);
- }
-
- pd->pam_status = PAM_SUCCESS;
- be_req_terminate(breq, DP_ERR_OK, EOK, "Success");
-}
-
static errno_t
ipa_selinux_process_seealso_maps(struct sysdb_attrs *user,
struct sysdb_attrs *host,
@@ -1023,8 +707,8 @@ static errno_t selinux_child_create_buffer(struct selinux_child_state *state)
static errno_t selinux_fork_child(struct selinux_child_state *state)
{
- int pipefd_to_child[2] = PIPE_INIT;
- int pipefd_from_child[2] = PIPE_INIT;
+ int pipefd_to_child[2];
+ int pipefd_from_child[2];
pid_t pid;
errno_t ret;
@@ -1033,7 +717,7 @@ static errno_t selinux_fork_child(struct selinux_child_state *state)
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"pipe failed [%d][%s].\n", errno, sss_strerror(errno));
- goto fail;
+ return ret;
}
ret = pipe(pipefd_to_child);
@@ -1041,23 +725,22 @@ static errno_t selinux_fork_child(struct selinux_child_state *state)
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"pipe failed [%d][%s].\n", errno, sss_strerror(errno));
- goto fail;
+ return ret;
}
pid = fork();
if (pid == 0) { /* child */
- exec_child(state,
- pipefd_to_child, pipefd_from_child,
+ exec_child(state, pipefd_to_child, pipefd_from_child,
SELINUX_CHILD, selinux_child_debug_fd);
-
- /* We should never get here */
- DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec selinux_child\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n",
+ ret, sss_strerror(ret));
+ return ret;
} else if (pid > 0) { /* parent */
state->io->read_from_child_fd = pipefd_from_child[0];
- PIPE_FD_CLOSE(pipefd_from_child[1]);
+ close(pipefd_from_child[1]);
state->io->write_to_child_fd = pipefd_to_child[1];
- PIPE_FD_CLOSE(pipefd_to_child[0]);
+ close(pipefd_to_child[0]);
sss_fd_nonblocking(state->io->read_from_child_fd);
sss_fd_nonblocking(state->io->write_to_child_fd);
@@ -1065,21 +748,16 @@ static errno_t selinux_fork_child(struct selinux_child_state *state)
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not set up child signal handler\n");
- goto fail;
+ return ret;
}
} else { /* error */
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"fork failed [%d][%s].\n", errno, sss_strerror(errno));
- goto fail;
+ return ret;
}
return EOK;
-
-fail:
- PIPE_CLOSE(pipefd_from_child);
- PIPE_CLOSE(pipefd_to_child);
- return ret;
}
static void selinux_child_step(struct tevent_req *subreq)
@@ -1099,7 +777,8 @@ static void selinux_child_step(struct tevent_req *subreq)
return;
}
- PIPE_FD_CLOSE(state->io->write_to_child_fd);
+ close(state->io->write_to_child_fd);
+ state->io->write_to_child_fd = -1;
subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
if (subreq == NULL) {
@@ -1128,7 +807,8 @@ static void selinux_child_done(struct tevent_req *subreq)
return;
}
- PIPE_FD_CLOSE(state->io->read_from_child_fd);
+ close(state->io->read_from_child_fd);
+ state->io->read_from_child_fd = -1;
ret = selinux_child_parse_response(buf, len, &child_result);
if (ret != EOK) {
@@ -1278,9 +958,8 @@ static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
int dp_error = DP_ERR_FATAL;
int ret;
struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx;
-
- const char *access_name;
- const char *selinux_name;
+ struct dp_module *access_mod;
+ struct dp_module *selinux_mod;
const char *hostname;
ret = sdap_id_op_connect_recv(subreq, &dp_error);
@@ -1300,9 +979,9 @@ static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
goto fail;
}
- access_name = state->be_ctx->bet_info[BET_ACCESS].mod_name;
- selinux_name = state->be_ctx->bet_info[BET_SELINUX].mod_name;
- if (strcasecmp(access_name, selinux_name) == 0 && state->host != NULL) {
+ 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 && state->host != NULL) {
/* If the access control module is the same as the selinux module
* and the access control had already discovered the host
*/
@@ -1506,11 +1185,9 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ipa_get_selinux_state *state;
-
struct ipa_id_ctx *id_ctx;
-
- char *selinux_name;
- char *access_name;
+ struct dp_module *access_mod;
+ struct dp_module *selinux_mod;
const char *tmp_str;
bool check_hbac;
@@ -1548,9 +1225,9 @@ static void ipa_get_selinux_maps_done(struct tevent_req *subreq)
}
if (check_hbac) {
- access_name = state->be_ctx->bet_info[BET_ACCESS].mod_name;
- selinux_name = state->be_ctx->bet_info[BET_SELINUX].mod_name;
- if (strcasecmp(access_name, selinux_name) == 0) {
+ 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);
@@ -1656,16 +1333,367 @@ ipa_get_selinux_recv(struct tevent_req *req,
return EOK;
}
-/*end of #if defined HAVE_SELINUX && defined HAVE_SELINUX_LOGIN_DIR */
-#else
-/* Simply return success if HAVE_SELINUX_LOGIN_DIR is not defined. */
-void ipa_selinux_handler(struct be_req *be_req)
+static errno_t
+ipa_selinux_init_attrs(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *ipa_domain,
+ struct sss_domain_info *user_domain,
+ const char *username,
+ const char *hostname,
+ struct sysdb_attrs **_user,
+ struct sysdb_attrs **_host)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *host_dn;
+ const char *attrs[] = { SYSDB_ORIG_DN,
+ SYSDB_ORIG_MEMBEROF,
+ NULL };
+ size_t count;
+ struct ldb_message **msgs;
+ struct sysdb_attrs **hosts;
+ struct sysdb_attrs *user = NULL;
+ struct sysdb_attrs *host = NULL;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sss_selinux_extract_user(tmp_ctx, user_domain, username, &user);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ host_dn = sysdb_custom_dn(tmp_ctx, ipa_domain, hostname, HBAC_HOSTS_SUBDIR);
+ if (host_dn == NULL) {
+ goto done;
+ }
+
+ /* Look up the host to get its originalMemberOf entries */
+ ret = sysdb_search_entry(tmp_ctx, sysdb, host_dn, LDB_SCOPE_BASE, NULL,
+ attrs, &count, &msgs);
+ if (ret == ENOENT || count == 0) {
+ host = NULL;
+ ret = EOK;
+ goto done;
+ } else if (ret != EOK) {
+ goto done;
+ } else if (count > 1) {
+ DEBUG(SSSDBG_OP_FAILURE, "More than one result for a BASE search!\n");
+ goto done;
+ }
+
+ ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &hosts);
+ talloc_free(msgs);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ host = hosts[0];
+
+ ret = EOK;
+
+done:
+ if (ret == EOK) {
+ *_user = talloc_steal(mem_ctx, user);
+ *_host = talloc_steal(mem_ctx, host);
+ }
+
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t
+ipa_selinux_store_config(struct sysdb_ctx *sysdb,
+ struct sss_domain_info *ipa_domain,
+ const char *default_user,
+ const char *map_order,
+ size_t map_count,
+ struct sysdb_attrs **maps)
+{
+ bool in_transaction = false;
+ errno_t sret;
+ errno_t ret;
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+ goto done;
+ }
+ in_transaction = true;
+
+ ret = sysdb_delete_usermaps(ipa_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot delete existing maps from sysdb\n");
+ goto done;
+ }
+
+ ret = sysdb_store_selinux_config(ipa_domain, default_user, map_order);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (map_count > 0) {
+ ret = ipa_save_user_maps(sysdb, ipa_domain, map_count, maps);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not commit transaction\n");
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
+ }
+ }
+
+ return ret;
+}
+
+static errno_t
+ipa_selinux_create_child_input(TALLOC_CTX *mem_ctx,
+ struct sysdb_attrs *user,
+ struct sysdb_attrs *host,
+ struct sysdb_attrs **maps,
+ size_t map_count,
+ struct sysdb_attrs **hbac_rules,
+ size_t hbac_count,
+ const char *map_order,
+ struct pam_data *pd,
+ struct sss_domain_info *user_domain,
+ const char *default_user,
+ struct selinux_child_input **_sci)
{
+ struct sysdb_attrs **best_match_maps = NULL;
+ struct map_order_ctx *map_order_ctx = NULL;
+ struct selinux_child_input *sci = NULL;
+ errno_t ret;
+
+ /* Process the maps and return list of best matches
+ * (maps with highest priority). */
+ ret = ipa_selinux_process_maps(mem_ctx, user, host, maps, map_count,
+ hbac_rules, hbac_count, &best_match_maps);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = init_map_order_ctx(mem_ctx, map_order, &map_order_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to create ordered SELinux users array.\n");
+ goto done;
+ }
+
+ ret = choose_best_seuser(mem_ctx, best_match_maps, pd, user_domain,
+ map_order_ctx, default_user, &sci);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to evaluate ordered SELinux users array.\n");
+ goto done;
+ }
+
+ *_sci = sci;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(best_match_maps);
+ talloc_free(map_order_ctx);
+ talloc_free(sci);
+ }
+
+ return ret;
+}
+
+struct ipa_selinux_handler_state {
+ struct be_ctx *be_ctx;
+ struct tevent_context *ev;
struct pam_data *pd;
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
+ struct sss_domain_info *user_domain;
+ struct sss_domain_info *ipa_domain;
+ struct ipa_selinux_ctx *selinux_ctx;
+
+ struct sysdb_attrs *user;
+ struct sysdb_attrs *host;
+};
- pd->pam_status = PAM_SUCCESS;
- be_req_terminate(be_req, DP_ERR_OK, EOK, "Success");
+static void ipa_selinux_handler_get_done(struct tevent_req *subreq);
+static void ipa_selinux_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_selinux_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_selinux_ctx *selinux_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
+{
+ struct ipa_selinux_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ const char *hostname;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_selinux_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->be_ctx = params->be_ctx;
+ state->ev = params->ev;
+ state->pd = pd;
+ state->user_domain = params->domain;
+ state->ipa_domain = params->be_ctx->domain;
+ state->selinux_ctx = selinux_ctx;
+
+ pd->pam_status = PAM_SYSTEM_ERR;
+
+ hostname = dp_opt_get_string(selinux_ctx->id_ctx->ipa_options->basic,
+ IPA_HOSTNAME);
+ if (hostname == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot determine this machine's host name\n");
+ ret = EINVAL;
+ goto immediately;
+ }
+
+ ret = ipa_selinux_init_attrs(state, state->user_domain->sysdb,
+ state->ipa_domain, state->user_domain,
+ pd->user, hostname,
+ &state->user, &state->host);
+ if (ret != EOK) {
+ goto immediately;
+ }
+
+ subreq = ipa_get_selinux_send(state, params->be_ctx, state->user,
+ state->host, selinux_ctx);
+ if (subreq == NULL) {
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_selinux_handler_get_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);
+
+ return req;
+}
+
+static void ipa_selinux_handler_get_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct ipa_selinux_handler_state *state;
+ struct selinux_child_input *sci;
+ struct sysdb_attrs **hbac_rules = NULL;
+ struct sysdb_attrs **maps = NULL;
+ size_t map_count = 0;
+ size_t hbac_count = 0;
+ char *default_user = NULL;
+ char *map_order = NULL;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_selinux_handler_state);
+
+ ret = ipa_get_selinux_recv(subreq, state, &map_count, &maps,
+ &hbac_count, &hbac_rules,
+ &default_user, &map_order);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = ipa_selinux_store_config(state->ipa_domain->sysdb, state->ipa_domain,
+ default_user, map_order, map_count, maps);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store SELinux config [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = ipa_selinux_create_child_input(state, state->user, state->host,
+ maps, map_count, hbac_rules,
+ hbac_count, map_order, state->pd,
+ state->user_domain, default_user,
+ &sci);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create child input [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Update the SELinux context in a privileged child as the back end is
+ * running unprivileged
+ */
+ subreq = selinux_child_send(state, state->ev, sci);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(subreq, ipa_selinux_handler_done, req);
+ return;
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+static void ipa_selinux_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_selinux_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 ipa_selinux_handler_state);
+
+ ret = selinux_child_recv(subreq);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ if (!be_is_offline(state->be_ctx)) {
+ state->selinux_ctx->last_update = time(NULL);
+ }
+
+ state->pd->pam_status = PAM_SUCCESS;
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+ipa_selinux_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct ipa_selinux_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_selinux_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
}
-#endif
diff --git a/src/providers/ipa/ipa_selinux.h b/src/providers/ipa/ipa_selinux.h
index 08cdaef7e..65ca037ee 100644
--- a/src/providers/ipa/ipa_selinux.h
+++ b/src/providers/ipa/ipa_selinux.h
@@ -43,6 +43,15 @@ struct ipa_selinux_ctx {
struct sdap_search_base **hbac_search_bases;
};
-void ipa_selinux_handler(struct be_req *be_req);
+struct tevent_req *
+ipa_selinux_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_selinux_ctx *selinux_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+ipa_selinux_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data);
#endif
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index bfe770be6..cb443db9c 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -24,6 +24,7 @@
#include "providers/ldap/sdap_async.h"
#include "providers/ldap/sdap_idmap.h"
+#include "providers/ldap/sdap_ops.h"
#include "providers/ipa/ipa_subdomains.h"
#include "providers/ipa/ipa_common.h"
#include "providers/ipa/ipa_id.h"
@@ -53,23 +54,9 @@
#define IPA_SUBDOMAIN_DISABLED_PERIOD 3600
-enum ipa_subdomains_req_type {
- IPA_SUBDOMAINS_MASTER,
- IPA_SUBDOMAINS_SLAVE,
- IPA_SUBDOMAINS_RANGES,
-
- IPA_SUBDOMAINS_MAX /* Counter */
-};
-
-struct ipa_subdomains_req_params {
- const char *filter;
- tevent_req_fn cb;
- const char *attrs[9];
-};
-
struct ipa_subdomains_ctx {
struct be_ctx *be_ctx;
- struct ipa_id_ctx *id_ctx;
+ struct ipa_id_ctx *ipa_id_ctx;
struct sdap_id_ctx *sdap_id_ctx;
struct sdap_search_base **search_bases;
struct sdap_search_base **master_search_bases;
@@ -77,34 +64,9 @@ struct ipa_subdomains_ctx {
struct sdap_search_base **host_search_bases;
time_t last_refreshed;
- struct tevent_timer *timer_event;
- bool configured_explicit;
- time_t disabled_until;
bool view_read_at_init;
};
-static void ipa_subdomains_done(struct ipa_subdomains_ctx *sd_ctx,
- struct be_req *req, int dp_err,
- int error, const char *errstr)
-{
- sd_ctx->view_read_at_init = true;
- return be_req_terminate(req, dp_err, error, errstr);
-}
-
-struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx)
-{
- struct ipa_subdomains_ctx *subdom_ctx;
-
- subdom_ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
- struct ipa_subdomains_ctx);
- if (subdom_ctx == NULL) {
- DEBUG(SSSDBG_TRACE_ALL, "Subdomains are not configured.\n");
- return NULL;
- }
-
- return subdom_ctx->be_ctx;
-}
-
static errno_t
ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
{
@@ -114,7 +76,7 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
"Re-initializing domain %s\n", ctx->be_ctx->domain->name);
ret = sss_write_krb5_conf_snippet(
- dp_opt_get_string(ctx->id_ctx->ipa_options->basic,
+ dp_opt_get_string(ctx->ipa_id_ctx->ipa_options->basic,
IPA_KRB5_CONFD_PATH));
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
@@ -535,10 +497,10 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
}
/* Remove the AD ID ctx from the list of LDAP domains */
- ipa_ad_subdom_remove(ctx->be_ctx, ctx->id_ctx, dom);
+ ipa_ad_subdom_remove(ctx->be_ctx, ctx->ipa_id_ctx, dom);
} else {
/* ok let's try to update it */
- ipa_subdom_store_step(parent, ctx->id_ctx,
+ ipa_subdom_store_step(parent, ctx->ipa_id_ctx,
ctx->sdap_id_ctx->opts->idmap_ctx,
reply[c]);
handled[c] = true;
@@ -560,7 +522,7 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
continue;
}
- ipa_subdom_store_step(parent, ctx->id_ctx,
+ ipa_subdom_store_step(parent, ctx->ipa_id_ctx,
ctx->sdap_id_ctx->opts->idmap_ctx,
reply[c]);
}
@@ -576,948 +538,1101 @@ done:
return ret;
}
-struct ipa_subdomains_req_ctx {
- struct be_req *be_req;
- struct ipa_subdomains_ctx *sd_ctx;
- struct sdap_id_op *sdap_op;
+static errno_t ipa_apply_view(struct sss_domain_info *domain,
+ struct ipa_id_ctx *ipa_id_ctx,
+ const char *view_name,
+ bool read_at_init)
+{
+ const char *current = ipa_id_ctx->view_name;
+ struct sysdb_ctx *sysdb = domain->sysdb;
+ bool in_transaction = false;
+ errno_t sret;
+ errno_t ret;
- char *current_filter;
+ DEBUG(SSSDBG_TRACE_ALL, "read_at_init [%s] current view [%s]\n",
+ read_at_init ? "true" : "false", ipa_id_ctx->view_name);
- struct sdap_search_base **search_bases;
- int search_base_iter;
-
- size_t reply_count;
- struct sysdb_attrs **reply;
-};
+ if (current != NULL && strcmp(current, view_name) != 0 && read_at_init) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "View name changed, this is not supported "
+ "at runtime. Please restart SSSD to get the new view applied.\n");
+ return EOK;
+ }
-static void ipa_subdomains_get_conn_done(struct tevent_req *req);
-static errno_t
-ipa_subdomains_handler_get_start(struct ipa_subdomains_req_ctx *ctx,
- struct sdap_search_base **search_bases,
- enum ipa_subdomains_req_type type);
-static errno_t
-ipa_subdomains_handler_get_cont(struct ipa_subdomains_req_ctx *ctx,
- enum ipa_subdomains_req_type type);
-static void ipa_subdomains_handler_done(struct tevent_req *req);
-static void ipa_subdomains_handler_master_done(struct tevent_req *req);
-static void ipa_subdomains_handler_ranges_done(struct tevent_req *req);
-
-static struct ipa_subdomains_req_params subdomain_requests[] = {
- { MASTER_DOMAIN_FILTER,
- ipa_subdomains_handler_master_done,
- { IPA_CN, IPA_FLATNAME, IPA_SID, NULL }
- },
- { SUBDOMAINS_FILTER,
- ipa_subdomains_handler_done,
- { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
- IPA_TRUST_DIRECTION, NULL }
- },
- { RANGE_FILTER,
- ipa_subdomains_handler_ranges_done,
- { OBJECTCLASS, IPA_CN,
- IPA_BASE_ID, IPA_BASE_RID, IPA_SECONDARY_BASE_RID,
- IPA_ID_RANGE_SIZE, IPA_TRUSTED_DOMAIN_SID, IPA_RANGE_TYPE, NULL
- }
+ if (current != NULL && strcmp(current, view_name) == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "View name did not change.\n");
+ return EOK;
}
-};
-static void ipa_subdomains_retrieve(struct ipa_subdomains_ctx *ctx, struct be_req *be_req)
-{
- struct ipa_subdomains_req_ctx *req_ctx = NULL;
- struct tevent_req *req;
- int dp_error = DP_ERR_FATAL;
- int ret;
+ DEBUG(SSSDBG_TRACE_FUNC, "View name changed to [%s].\n", view_name);
- req_ctx = talloc(be_req, struct ipa_subdomains_req_ctx);
- if (req_ctx == NULL) {
- ret = ENOMEM;
- goto done;
- }
+ /* View name changed. If there was a non-default non-local view
+ * was used the tree in cache containing the override values is
+ * removed. In all cases sysdb_invalidate_overrides() is called to
+ * remove the override attribute from the cached user objects.
+ *
+ * Typically ctx->sd_ctx->id_ctx->view_name == NULL means that the
+ * cache was empty but there was a bug in with caused that the
+ * view name was not written to the cache at all. In this case the
+ * cache must be invalidated if the new view is not the
+ * default-view as well. */
- req_ctx->be_req = be_req;
- req_ctx->sd_ctx = ctx;
- req_ctx->search_base_iter = 0;
- req_ctx->search_bases = ctx->ranges_search_bases;
- req_ctx->current_filter = NULL;
- req_ctx->reply_count = 0;
- req_ctx->reply = NULL;
+ if (current != NULL || !is_default_view(view_name)) {
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to start transaction "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
- req_ctx->sdap_op = sdap_id_op_create(req_ctx,
- ctx->sdap_id_ctx->conn->conn_cache);
- if (req_ctx->sdap_op == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
- ret = ENOMEM;
+ in_transaction = true;
+
+ if (!is_default_view(current) && !is_local_view(current)) {
+ /* Old view was not the default view, delete view tree */
+ ret = sysdb_delete_view_tree(sysdb, current);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to delete old view tree "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = sysdb_invalidate_overrides(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, " Unable to invalidate overrides "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to commint transaction "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ in_transaction = false;
+ }
+
+ ret = sysdb_update_view_name(sysdb, view_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot update view name "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
- ret, strerror(ret));
+ talloc_free(ipa_id_ctx->view_name);
+ ipa_id_ctx->view_name = talloc_strdup(ipa_id_ctx, view_name);
+ if (ipa_id_ctx->view_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
+ ret = ENOMEM;
goto done;
}
- tevent_req_set_callback(req, ipa_subdomains_get_conn_done, req_ctx);
+ if (!read_at_init) {
+ /* refresh view data of all domains at startup */
+ ret = sysdb_master_domain_update(domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
- return;
+ ret = sysdb_update_subdomains(domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+ }
done:
- talloc_free(req_ctx);
- if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
+ }
}
- ipa_subdomains_done(ctx, be_req, dp_error, ret, NULL);
+
+ return ret;
}
-static void ipa_subdomains_get_conn_done(struct tevent_req *req)
-{
- int ret;
- int dp_error = DP_ERR_FATAL;
- struct ipa_subdomains_req_ctx *ctx;
+struct ipa_subdomains_ranges_state {
+ struct sss_domain_info *domain;
+};
- ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
+static void ipa_subdomains_ranges_done(struct tevent_req *subreq);
- ret = sdap_id_op_connect_recv(req, &dp_error);
- talloc_zfree(req);
- if (ret) {
- if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No IPA server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to connect to IPA server: [%d](%s)\n",
- ret, strerror(ret));
- }
+static struct tevent_req *
+ipa_subdomains_ranges_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
+{
+ struct ipa_subdomains_ranges_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+ const char *attrs[] = { OBJECTCLASS, IPA_CN,
+ IPA_BASE_ID, IPA_BASE_RID, IPA_SECONDARY_BASE_RID,
+ IPA_ID_RANGE_SIZE, IPA_TRUSTED_DOMAIN_SID,
+ IPA_RANGE_TYPE, NULL };
- goto fail;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_ranges_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ret = ipa_subdomains_handler_get_start(ctx,
- ctx->sd_ctx->ranges_search_bases,
- IPA_SUBDOMAINS_RANGES);
- if (ret != EOK && ret != EAGAIN) {
- goto fail;
+ if (sd_ctx->ranges_search_bases == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No search base is set\n");
+ ret = EOK;
+ goto immediately;
}
- return;
+ state->domain = sd_ctx->be_ctx->domain;
-fail:
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ subreq = sdap_search_bases_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+ sd_ctx->ranges_search_bases, NULL, false,
+ 0, RANGE_FILTER, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_ranges_done, req);
+
+ 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_subdomains_handler_get(struct ipa_subdomains_req_ctx *ctx,
- enum ipa_subdomains_req_type type)
+static void ipa_subdomains_ranges_done(struct tevent_req *subreq)
{
+ struct ipa_subdomains_ranges_state *state;
struct tevent_req *req;
- struct sdap_search_base *base;
- struct ipa_subdomains_req_params *params;
-
- if (type >= IPA_SUBDOMAINS_MAX) {
- return EINVAL;
- }
+ struct range_info **range_list;
+ struct sysdb_attrs **reply;
+ size_t reply_count;
+ errno_t ret;
- params = &subdomain_requests[type];
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_ranges_state);
- base = ctx->search_bases[ctx->search_base_iter];
- if (base == NULL) {
- return EOK;
+ ret = sdap_search_bases_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- talloc_free(ctx->current_filter);
- ctx->current_filter = sdap_combine_filters(ctx, params->filter,
- base->filter);
- if (ctx->current_filter == NULL) {
- return ENOMEM;
+ ret = ipa_ranges_parse_results(state, state->domain->name,
+ reply_count, reply, &range_list);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse range resulg [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->sd_ctx->sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->sdap_op),
- base->basedn, base->scope,
- ctx->current_filter, params->attrs, NULL, 0,
- dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT), false);
-
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
+ ret = sysdb_update_ranges(state->domain->sysdb, range_list);
+ talloc_free(range_list);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to update ranges [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- tevent_req_set_callback(req, params->cb, ctx);
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
- return EAGAIN;
+ tevent_req_done(req);
}
-static errno_t
-ipa_subdomains_handler_get_start(struct ipa_subdomains_req_ctx *ctx,
- struct sdap_search_base **search_bases,
- enum ipa_subdomains_req_type type)
+static errno_t ipa_subdomains_ranges_recv(struct tevent_req *req)
{
- ctx->search_base_iter = 0;
- ctx->search_bases = search_bases;
- return ipa_subdomains_handler_get(ctx, type);
-}
+ TEVENT_REQ_RETURN_ON_ERROR(req);
-static errno_t
-ipa_subdomains_handler_get_cont(struct ipa_subdomains_req_ctx *ctx,
- enum ipa_subdomains_req_type type)
-{
- ctx->search_base_iter++;
- return ipa_subdomains_handler_get(ctx, type);
+ return EOK;
}
-static void ipa_get_view_name_done(struct tevent_req *req);
-static void ipa_server_create_trusts_done(struct tevent_req *trust_req);
-static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx);
+struct ipa_subdomains_master_state {
+ struct sss_domain_info *domain;
+ struct ipa_options *ipa_options;
+};
-static errno_t ipa_get_view_name(struct ipa_subdomains_req_ctx *ctx)
+static void ipa_subdomains_master_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_master_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
{
+ struct ipa_subdomains_master_state *state;
+ struct sss_domain_info *domain;
+ struct tevent_req *subreq;
struct tevent_req *req;
- struct sdap_search_base *base;
- const char *attrs[] = {IPA_CN, OBJECTCLASS, NULL};
- struct sdap_attr_map_info *maps;
+ errno_t ret;
+ const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_SID, NULL };
- maps = talloc_zero(ctx, struct sdap_attr_map_info);
- if (maps == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
- return ENOMEM;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_master_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- maps->map = ctx->sd_ctx->id_ctx->ipa_options->view_map;
- maps->num_attrs = IPA_OPTS_VIEW;
- base = ctx->search_bases[ctx->search_base_iter];
- if (base == NULL) {
- return EOK;
+ if (sd_ctx->master_search_bases == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No search base is set\n");
+ ret = EOK;
+ goto immediately;
}
- /* We add SDAP_DEREF_FLG_SILENT because old IPA servers don't have
- * the attribute we dereference, causing the deref call to fail
- */
- req = sdap_deref_search_with_filter_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->sd_ctx->sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->sdap_op),
- base->basedn,
- ctx->current_filter, IPA_ASSIGNED_ID_VIEW, attrs,
- 1, maps,
- dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT),
- SDAP_DEREF_FLG_SILENT);
+ state->domain = domain = sd_ctx->be_ctx->domain;
+ state->ipa_options = sd_ctx->ipa_id_ctx->ipa_options;
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
+ ret = sysdb_master_domain_update(domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to update master domain [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto immediately;
}
- tevent_req_set_callback(req, ipa_get_view_name_done, ctx);
+ if (domain->flat_name != NULL && domain->domain_id != NULL
+ && domain->realm != NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Master record is up to date.\n");
+ ret = EOK;
+ goto immediately;
+ }
- return EAGAIN;
+ subreq = sdap_search_bases_return_first_send(state, ev,
+ sd_ctx->sdap_id_ctx->opts, sh,
+ sd_ctx->master_search_bases, NULL, false,
+ 0, MASTER_DOMAIN_FILTER, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_master_done, req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ipa_get_view_name_done(struct tevent_req *req)
+static void ipa_subdomains_master_done(struct tevent_req *subreq)
{
- int ret;
- int sret;
- struct ipa_subdomains_req_ctx *ctx;
+ struct ipa_subdomains_master_state *state;
+ struct tevent_req *req;
+ struct sysdb_attrs **reply;
size_t reply_count;
- struct sdap_deref_attrs **reply = NULL;
- const char *view_name;
- int dp_error = DP_ERR_FATAL;
+ const char *flat = NULL;
+ const char *id = NULL;
+ const char *realm = NULL;
+ errno_t ret;
- ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_master_state);
- ret = sdap_deref_search_with_filter_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
+ ret = sdap_search_bases_return_first_recv(subreq, state,
+ &reply_count, &reply);
+ talloc_zfree(subreq);
if (ret != EOK) {
- /* Depending on the version 389ds return a different error code if the
- * search for the view name failed because our dereference attribute
- * ipaAssignedIDView is not known. Newer version return
- * LDAP_UNAVAILABLE_CRITICAL_EXTENSION(12) which is translated to
- * EOPNOTSUPP and older versions return LDAP_PROTOCOL_ERROR(2) which
- * is returned as EIO. In both cases we have to assume that the server
- * is not view aware and keep the view name unset. */
- if (ret == EOPNOTSUPP || ret == EIO) {
- DEBUG(SSSDBG_TRACE_FUNC, "get_view_name request failed, looks " \
- "like server does not support views.\n");
- ret = EOK;
- } else {
- DEBUG(SSSDBG_OP_FAILURE, "get_view_name request failed.\n");
- }
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- if (reply_count == 0) {
- ctx->search_base_iter++;
- ret = ipa_get_view_name(ctx);
- if (ret == EAGAIN) {
- return;
- } else if (ret == EOK) {
- DEBUG(SSSDBG_TRACE_FUNC, "No view found, using default.\n");
- view_name = SYSDB_DEFAULT_VIEW_NAME;
- } else {
+ if (reply_count > 0) {
+ ret = sysdb_attrs_get_string(reply[0], IPA_FLATNAME, &flat);
+ if (ret != EOK) {
goto done;
}
- } else if (reply_count > 1) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "get_view_name request returned more than one object.\n");
- ret = EINVAL;
- goto done;
- } else {
- ret = sysdb_attrs_get_string(reply[0]->attrs, SYSDB_VIEW_NAME,
- &view_name);
+
+ ret = sysdb_attrs_get_string(reply[0], IPA_SID, &id);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
goto done;
}
+ } else {
+ /* All search paths are searched and no master domain record was
+ * found.
+ *
+ * A default IPA installation will not have a master domain record,
+ * this is only created by ipa-adtrust-install. Nevertheless we should
+ * continue to read other data like the idview on IPA clients. */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Master domain record not found!\n");
}
- DEBUG(SSSDBG_TRACE_FUNC, "Found view name [%s].\n", view_name);
- if (is_default_view(view_name)) {
- DEBUG(SSSDBG_TRACE_ALL,
- "Found IPA default view name, replacing with sysdb default.\n");
- view_name = SYSDB_DEFAULT_VIEW_NAME;
+ realm = dp_opt_get_string(state->ipa_options->basic, IPA_KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
+ ret = EINVAL;
+ goto done;
}
- DEBUG(SSSDBG_TRACE_ALL, "read_at_init [%s] current view [%s].\n",
- ctx->sd_ctx->view_read_at_init ? "true" : "false",
- ctx->sd_ctx->id_ctx->view_name);
+ ret = sysdb_master_domain_add_info(state->domain, realm, flat, id, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add master domain info "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
- if (ctx->sd_ctx->id_ctx->view_name != NULL
- && strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0
- && ctx->sd_ctx->view_read_at_init) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "View name changed, this is not supported at runtime. " \
- "Please restart SSSD to get the new view applied.\n");
- } else {
- if (ctx->sd_ctx->id_ctx->view_name == NULL
- || strcmp(ctx->sd_ctx->id_ctx->view_name, view_name) != 0) {
- /* View name changed. If there was a non-default non-local view
- * was used the tree in cache containing the override values is
- * removed. In all cases sysdb_invalidate_overrides() is called to
- * remove the override attribute from the cached user objects.
- *
- * Typically ctx->sd_ctx->id_ctx->view_name == NULL means that the
- * cache was empty but there was a bug in with caused that the
- * view name was not written to the cache at all. In this case the
- * cache must be invalidated if the new view is not the
- * default-view as well. */
-
- if (ctx->sd_ctx->id_ctx->view_name != NULL
- || !is_default_view(view_name)) {
- ret = sysdb_transaction_start(
- ctx->sd_ctx->be_ctx->domain->sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_transaction_start failed.\n");
- goto done;
- }
-
- if (!is_default_view(ctx->sd_ctx->id_ctx->view_name)
- && !is_local_view(ctx->sd_ctx->id_ctx->view_name)) {
- /* Old view was not the default view, delete view tree */
- ret = sysdb_delete_view_tree(
- ctx->sd_ctx->be_ctx->domain->sysdb,
- ctx->sd_ctx->id_ctx->view_name);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_delete_view_tree failed.\n");
- sret = sysdb_transaction_cancel(
- ctx->sd_ctx->be_ctx->domain->sysdb);
- if (sret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_transaction_cancel failed.\n");
- goto done;
- }
- goto done;
- }
- }
-
- ret = sysdb_invalidate_overrides(
- ctx->sd_ctx->be_ctx->domain->sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_invalidate_overrides failed.\n");
- sret = sysdb_transaction_cancel(
- ctx->sd_ctx->be_ctx->domain->sysdb);
- if (sret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_transaction_cancel failed.\n");
- goto done;
- }
- goto done;
- }
-
- ret = sysdb_transaction_commit(
- ctx->sd_ctx->be_ctx->domain->sysdb);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_transaction_commit failed.\n");
- goto done;
- }
-
- /* TODO: start referesh task */
- }
+ ret = EOK;
- ret = sysdb_update_view_name(ctx->sd_ctx->be_ctx->domain->sysdb,
- view_name);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot add/update view name to sysdb.\n");
- } else {
- talloc_free(ctx->sd_ctx->id_ctx->view_name);
- ctx->sd_ctx->id_ctx->view_name = talloc_strdup(
- ctx->sd_ctx->id_ctx,
- view_name);
- if (ctx->sd_ctx->id_ctx->view_name == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot copy view name.\n");
- }
- }
- }
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
- if (!ctx->sd_ctx->view_read_at_init) {
- /* refresh view data of all domains at startup */
- ret = sysdb_master_domain_update(ctx->sd_ctx->be_ctx->domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sysdb_master_domain_update failed.\n");
- goto done;
- }
+ tevent_req_done(req);
+}
- ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
- goto done;
- }
- }
+static errno_t ipa_subdomains_master_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- ctx->sd_ctx->view_read_at_init = true;
+ return EOK;
+}
+
+struct ipa_subdomains_slave_state {
+ struct ipa_subdomains_ctx *sd_ctx;
+ struct be_ctx *be_ctx;
+ struct ipa_id_ctx *ipa_id_ctx;
+};
+static void ipa_subdomains_slave_search_done(struct tevent_req *subreq);
+static void ipa_subdomains_slave_trusts_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
+{
+ struct ipa_subdomains_slave_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+ const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID,
+ IPA_TRUST_DIRECTION, NULL };
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_slave_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ret = EOK;
-done:
+ if (sd_ctx->search_bases == NULL) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No search base is set\n");
+ ret = EOK;
+ goto immediately;
+ }
+
+ state->sd_ctx = sd_ctx;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->ipa_id_ctx = sd_ctx->ipa_id_ctx;
+
+ subreq = sdap_search_bases_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh,
+ sd_ctx->search_bases, NULL, false,
+ 0, SUBDOMAINS_FILTER, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_subdomains_slave_search_done, req);
+
+ return req;
+
+immediately:
if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ipa_subdomains_handler_done(struct tevent_req *req)
+static void ipa_subdomains_slave_search_done(struct tevent_req *subreq)
{
- int ret;
+ struct ipa_subdomains_slave_state *state;
+ struct tevent_req *req;
+ struct sysdb_attrs **reply;
size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ipa_subdomains_req_ctx *ctx;
- struct sss_domain_info *domain;
- bool refresh_has_changes = false;
- int dp_error = DP_ERR_FATAL;
- struct tevent_req *trust_req;
+ bool has_changes;
+ errno_t ret;
- ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
- domain = ctx->sd_ctx->be_ctx->domain;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_slave_state);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
+ ret = sdap_search_bases_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- if (reply_count) {
- ctx->reply = talloc_realloc(ctx, ctx->reply, struct sysdb_attrs *,
- ctx->reply_count + reply_count);
- if (ctx->reply == NULL) {
- ret = ENOMEM;
- goto done;
- }
- memcpy(ctx->reply+ctx->reply_count, reply,
- reply_count * sizeof(struct sysdb_attrs *));
- ctx->reply_count += reply_count;
+ ret = ipa_subdomains_refresh(state->sd_ctx, reply_count, reply,
+ &has_changes);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ goto done;
}
- ret = ipa_subdomains_handler_get_cont(ctx, IPA_SUBDOMAINS_SLAVE);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
+ if (!has_changes) {
+ ret = EOK;
goto done;
}
- ret = ipa_subdomains_refresh(ctx->sd_ctx, ctx->reply_count, ctx->reply,
- &refresh_has_changes);
+ ret = ipa_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
goto done;
}
- if (refresh_has_changes) {
- ret = ipa_subdom_reinit(ctx->sd_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
- goto done;
- }
-
- if (ctx->sd_ctx->id_ctx->server_mode != NULL) {
- trust_req = ipa_server_create_trusts_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->sd_ctx->be_ctx,
- ctx->sd_ctx->id_ctx,
- domain);
- if (trust_req == NULL) {
- ret = ENOMEM;
- goto done;
- }
- tevent_req_set_callback(trust_req, ipa_server_create_trusts_done, ctx);
- return;
- }
+ if (state->sd_ctx->ipa_id_ctx->server_mode == NULL) {
+ ret = EOK;
+ goto done;
}
- ctx->search_base_iter = 0;
- ctx->search_bases = ctx->sd_ctx->host_search_bases;
- talloc_zfree(ctx->current_filter);
- ctx->current_filter = talloc_asprintf(ctx, "(&(objectClass=%s)(%s=%s))",
- ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_OC_HOST].name,
- ctx->sd_ctx->id_ctx->ipa_options->host_map[IPA_AT_HOST_FQDN].name,
- dp_opt_get_string(ctx->sd_ctx->id_ctx->ipa_options->basic,
- IPA_HOSTNAME));
- if (ctx->current_filter == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+ subreq = ipa_server_create_trusts_send(state, state->be_ctx->ev,
+ state->be_ctx, state->ipa_id_ctx,
+ state->be_ctx->domain);
+ if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
+ tevent_req_set_callback(subreq, ipa_subdomains_slave_trusts_done, req);
+ return;
- if (ctx->sd_ctx->id_ctx->server_mode == NULL) {
- /* Only get view on clients, on servers it is always 'default' */
- ret = ipa_get_view_name(ctx);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto done;
- }
- }
-
- ret = EOK;
done:
- if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+
+ tevent_req_done(req);
}
-static void ipa_server_create_trusts_done(struct tevent_req *trust_req)
+static void ipa_subdomains_slave_trusts_done(struct tevent_req *subreq)
{
+ struct tevent_req *req;
errno_t ret;
- int dp_error = DP_ERR_FATAL;
- struct ipa_subdomains_req_ctx *ctx;
- ctx = tevent_req_callback_data(trust_req, struct ipa_subdomains_req_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
- ret = ipa_server_create_trusts_recv(trust_req);
- talloc_zfree(trust_req);
- if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ ret = ipa_server_create_trusts_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create trusts [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
}
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ tevent_req_done(req);
}
-static errno_t ipa_check_master(struct ipa_subdomains_req_ctx *ctx)
+static errno_t ipa_subdomains_slave_recv(struct tevent_req *req)
{
- int ret;
- struct sss_domain_info *domain;
-
- domain = ctx->sd_ctx->be_ctx->domain;
-
- ret = sysdb_master_domain_update(domain);
- if (ret != EOK) {
- return ret;
- }
-
- if (domain->flat_name == NULL ||
- domain->domain_id == NULL ||
- domain->realm == NULL) {
-
- ret = ipa_subdomains_handler_get_start(ctx,
- ctx->sd_ctx->master_search_bases,
- IPA_SUBDOMAINS_MASTER);
- if (ret == EAGAIN) {
- return EAGAIN;
- } else if (ret != EOK) {
- return ret;
- }
- }
+ TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
+struct ipa_subdomains_view_name_state {
+ struct ipa_subdomains_ctx *sd_ctx;
+};
+
+static void ipa_subdomains_view_name_done(struct tevent_req *subreq);
-static void ipa_subdomains_handler_ranges_done(struct tevent_req *req)
+static struct tevent_req *
+ipa_subdomains_view_name_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct sdap_handle *sh)
{
+ struct ipa_subdomains_view_name_state *state;
+ struct sdap_attr_map_info *maps;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ struct ipa_options *ipa_options;
+ const char *filter;
+ const char *attrs[] = {IPA_CN, OBJECTCLASS, NULL};
errno_t ret;
- int dp_error = DP_ERR_FATAL;
- size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ipa_subdomains_req_ctx *ctx;
- struct range_info **range_list = NULL;
- struct sysdb_ctx *sysdb;
- struct sss_domain_info *domain;
-
- ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
- domain = ctx->sd_ctx->be_ctx->domain;
- sysdb = domain->sysdb;
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto done;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_view_name_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ret = ipa_ranges_parse_results(ctx, domain->name,
- reply_count, reply, &range_list);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "ipa_ranges_parse_results request failed.\n");
- goto done;
+ if (sd_ctx->ipa_id_ctx->server_mode != NULL) {
+ /* Only get view on clients, on servers it is always 'default'. */
+ ret = EOK;
+ goto immediately;
}
- ret = sysdb_update_ranges(sysdb, range_list);
- talloc_free(range_list);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_ranges failed.\n");
- goto done;
+ state->sd_ctx = sd_ctx;
+
+ ipa_options = sd_ctx->ipa_id_ctx->ipa_options;
+
+ maps = talloc_zero_array(state, struct sdap_attr_map_info, 2);
+ if (maps == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero() failed\n");
+ ret = ENOMEM;
+ goto immediately;
}
+ maps[0].map = ipa_options->view_map;
+ maps->num_attrs = IPA_OPTS_VIEW;
- ret = ipa_check_master(ctx);
- if (ret == EAGAIN) {
- DEBUG(SSSDBG_TRACE_ALL, "Checking master record..\n");
- return;
- } else if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "ipa_check_master failed.\n");
- goto done;
+ filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
+ ipa_options->host_map[IPA_OC_HOST].name,
+ ipa_options->host_map[IPA_AT_HOST_FQDN].name,
+ dp_opt_get_string(ipa_options->basic, IPA_HOSTNAME));
+ if (filter == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- /* Master domain is up-to-date. Continue checking subdomains */
- DEBUG(SSSDBG_TRACE_ALL, "Master record up2date, checking subdomains\n");
- ret = ipa_subdomains_handler_get_start(ctx, ctx->sd_ctx->search_bases,
- IPA_SUBDOMAINS_SLAVE);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto done;
+ /* We add SDAP_DEREF_FLG_SILENT because old IPA servers don't have
+ * the attribute we dereference, causing the deref call to fail. */
+ subreq = sdap_deref_bases_return_first_send(state, ev,
+ sd_ctx->sdap_id_ctx->opts, sh, sd_ctx->host_search_bases,
+ maps, filter, attrs, IPA_ASSIGNED_ID_VIEW,
+ SDAP_DEREF_FLG_SILENT, 0);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- DEBUG(SSSDBG_OP_FAILURE, "No search base for ranges available.\n");
- ret = EINVAL;
+ tevent_req_set_callback(subreq, ipa_subdomains_view_name_done, req);
-done:
+ return req;
+
+immediately:
if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ipa_subdomains_handler_master_done(struct tevent_req *req)
+static void ipa_subdomains_view_name_done(struct tevent_req *subreq)
{
+ struct ipa_subdomains_view_name_state *state;
+ struct tevent_req *req;
+ size_t reply_count;
+ struct sdap_deref_attrs **reply;
+ const char *view_name;
errno_t ret;
- int dp_error = DP_ERR_FATAL;
- size_t reply_count = 0;
- struct sysdb_attrs **reply = NULL;
- struct ipa_subdomains_req_ctx *ctx;
- const char *flat = NULL;
- const char *id = NULL;
- const char *realm = NULL;
- ctx = tevent_req_callback_data(req, struct ipa_subdomains_req_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_view_name_state);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
+ ret = sdap_deref_bases_return_first_recv(subreq, state,
+ &reply_count, &reply);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto done;
- }
-
- if (reply_count) {
- ret = sysdb_attrs_get_string(reply[0], IPA_FLATNAME, &flat);
- if (ret != EOK) {
+ /* Depending on the version 389ds return a different error code if the
+ * search for the view name failed because our dereference attribute
+ * ipaAssignedIDView is not known. Newer version return
+ * LDAP_UNAVAILABLE_CRITICAL_EXTENSION(12) which is translated to
+ * EOPNOTSUPP and older versions return LDAP_PROTOCOL_ERROR(2) which
+ * is returned as EIO. In both cases we have to assume that the server
+ * is not view aware and keep the view name unset. */
+ if (ret == EOPNOTSUPP || ret == EIO) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to get view name, looks " \
+ "like server does not support views.\n");
+ ret = EOK;
goto done;
}
- ret = sysdb_attrs_get_string(reply[0], IPA_SID, &id);
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get view name [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (reply_count == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No view found, using default.\n");
+ view_name = SYSDB_DEFAULT_VIEW_NAME;
+ } else if (reply_count == 1) {
+ ret = sysdb_attrs_get_string(reply[0]->attrs, SYSDB_VIEW_NAME,
+ &view_name);
if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
goto done;
}
-
- /* There is only one master record. Don't bother checking other IPA
- * search bases; move to checking subdomains instead
- */
} else {
- ret = ipa_subdomains_handler_get_cont(ctx, IPA_SUBDOMAINS_MASTER);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto done;
- }
-
- /* All search paths are searched and no master domain record was
- * found.
- *
- * A default IPA installation will not have a master domain record,
- * this is only created by ipa-adtrust-install. Nevertheless we should
- * continue to read other data like the idview on IPA clients. */
-
- DEBUG(SSSDBG_TRACE_INTERNAL, "Master domain record not found!\n");
-
- }
-
- realm = dp_opt_get_string(ctx->sd_ctx->id_ctx->ipa_options->basic,
- IPA_KRB5_REALM);
- if (realm == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm for IPA?\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "More than one object returned.\n");
ret = EINVAL;
goto done;
}
- ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
- realm, flat, id, NULL);
+ ret = ipa_apply_view(state->sd_ctx->be_ctx->domain,
+ state->sd_ctx->ipa_id_ctx, view_name,
+ state->sd_ctx->view_read_at_init);
if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set view [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- ret = ipa_subdomains_handler_get_start(ctx,
- ctx->sd_ctx->search_bases,
- IPA_SUBDOMAINS_SLAVE);
- if (ret == EAGAIN) {
- return;
- } else if (ret == EOK) {
- /* If there are no search bases defined for subdomains try to get the
- * idview before ending the request */
- if (ctx->sd_ctx->id_ctx->server_mode == NULL) {
- /* Only get view on clients, on servers it is always 'default' */
- ret = ipa_get_view_name(ctx);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto done;
- }
- }
- }
+ state->sd_ctx->view_read_at_init = true;
done:
- if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- ipa_subdomains_done(ctx->sd_ctx, ctx->be_req, dp_error, ret, NULL);
-}
-static void ipa_subdom_online_cb(void *pvt);
+ tevent_req_done(req);
+}
-static void ipa_subdom_timer_refresh(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
+static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req)
{
- ipa_subdom_online_cb(pvt);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
}
-static void ipa_subdom_be_req_callback(struct be_req *be_req,
- int dp_err, int dp_ret,
- const char *errstr)
+
+struct ipa_subdomains_refresh_state {
+ struct tevent_context *ev;
+ struct ipa_subdomains_ctx *sd_ctx;
+ struct sdap_id_op *sdap_op;
+};
+
+static errno_t ipa_subdomains_refresh_retry(struct tevent_req *req);
+static void ipa_subdomains_refresh_connect_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq);
+static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ipa_subdomains_ctx *sd_ctx)
{
- talloc_free(be_req);
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_refresh_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->sd_ctx = sd_ctx;
+
+ state->sdap_op = sdap_id_op_create(state,
+ sd_ctx->sdap_id_ctx->conn->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ ret = ipa_subdomains_refresh_retry(req);
+ if (ret == EAGAIN) {
+ /* asynchronous processing */
+ return req;
+ }
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ipa_subdom_reset_timeouts_cb(void *pvt)
+static errno_t ipa_subdomains_refresh_retry(struct tevent_req *req)
{
- struct ipa_subdomains_ctx *ctx;
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *subreq;
+ int ret;
- ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
- if (ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
- return;
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_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, sss_strerror(ret));
+ return ret;
}
- DEBUG(SSSDBG_TRACE_ALL, "Resetting last_refreshed and disabled_until.\n");
- ctx->last_refreshed = 0;
- ctx->disabled_until = 0;
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_connect_done, req);
+
+ return EAGAIN;
}
-static void ipa_subdom_online_cb(void *pvt)
+static void ipa_subdomains_refresh_connect_done(struct tevent_req *subreq)
{
- struct ipa_subdomains_ctx *ctx;
- struct be_req *be_req;
- struct timeval tv;
- uint32_t refresh_interval;
-
- ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
- if (!ctx) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
- return;
- }
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ int dp_error;
+ errno_t ret;
- ctx->disabled_until = 0;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
- refresh_interval = ctx->be_ctx->domain->subdomain_refresh_interval;
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
- be_req = be_req_create(ctx, NULL, ctx->be_ctx, "IPA subdomains",
- ipa_subdom_be_req_callback, NULL);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_req_create() failed.\n");
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ if (dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "No IPA server is available, "
+ "cannot get the subdomain list while offline\n");
+ ret = ERR_OFFLINE;
+ }
+ tevent_req_error(req, ret);
return;
}
- ipa_subdomains_retrieve(ctx, be_req);
-
- tv = tevent_timeval_current_ofs(refresh_interval, 0);
- ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
- ipa_subdom_timer_refresh, ctx);
- if (!ctx->timer_event) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom timer event\n");
+ subreq = ipa_subdomains_ranges_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
}
+
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_ranges_done, req);
+ return;
}
-static void ipa_subdom_offline_cb(void *pvt)
+static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq)
{
- struct ipa_subdomains_ctx *ctx;
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
+
+ ret = ipa_subdomains_ranges_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get IPA ranges "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
- if (ctx) {
- talloc_zfree(ctx->timer_event);
+ subreq = ipa_subdomains_master_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
}
+
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_master_done, req);
+ return;
}
-static errno_t get_config_status(struct be_ctx *be_ctx,
- bool *configured_explicit)
+static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq)
{
- int ret;
- TALLOC_CTX *tmp_ctx = NULL;
- char *tmp_str;
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
- return ENOMEM;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
- ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
- CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, NULL,
- &tmp_str);
+ ret = ipa_subdomains_master_recv(subreq);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "confdb_get_string failed.\n");
- goto done;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
}
- if (tmp_str == NULL) {
- *configured_explicit = false;
- } else {
- *configured_explicit = true;
+ subreq = ipa_subdomains_slave_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
}
- DEBUG(SSSDBG_TRACE_ALL, "IPA subdomain provider is configured %s.\n",
- *configured_explicit ? "explicit" : "implicit");
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_slave_done, req);
+ return;
+}
- ret = EOK;
+static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
-done:
- talloc_free(tmp_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
- return ret;
-}
+ ret = ipa_subdomains_slave_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get subdomains "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
-void ipa_subdomains_handler(struct be_req *be_req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ipa_subdomains_ctx *ctx;
- time_t now;
-
- ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
- struct ipa_subdomains_ctx);
- if (!ctx) {
- be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
+ subreq = ipa_subdomains_view_name_send(state, state->ev, state->sd_ctx,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
return;
}
- now = time(NULL);
+ tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_done, req);
+ return;
+}
+
+static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ int dp_error;
+ errno_t ret;
- if (ctx->disabled_until > now) {
- DEBUG(SSSDBG_TRACE_ALL, "Subdomain provider disabled.\n");
- ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_subdomains_refresh_state);
+
+ ret = ipa_subdomains_view_name_recv(subreq);
+ talloc_zfree(subreq);
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ipa_subdomains_refresh_retry(req);
+ if (ret != EOK) {
+ goto done;
+ }
return;
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ ret = ERR_OFFLINE;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get view name "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- if (ctx->last_refreshed > now - IPA_SUBDOMAIN_REFRESH_LIMIT) {
- ipa_subdomains_done(ctx, be_req, DP_ERR_OK, EOK, NULL);
+done:
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
return;
}
- ipa_subdomains_retrieve(ctx, be_req);
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n");
+ tevent_req_done(req);
}
-struct bet_ops ipa_subdomains_ops = {
- .handler = ipa_subdomains_handler,
- .finalize = NULL
+static errno_t ipa_subdomains_refresh_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+struct ipa_subdomains_handler_state {
+ struct dp_reply_std reply;
};
-int ipa_subdom_init(struct be_ctx *be_ctx,
- struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+static void ipa_subdomains_handler_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_subdomains_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_subdomains_ctx *sd_ctx,
+ struct dp_subdomains_data *data,
+ struct dp_req_params *params)
{
- struct ipa_subdomains_ctx *ctx;
- int ret;
- bool configured_explicit = false;
+ struct ipa_subdomains_handler_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ errno_t ret;
- ret = get_config_status(be_ctx, &configured_explicit);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "get_config_status failed.\n");
- return ret;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_subdomains_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ctx = talloc_zero(id_ctx, struct ipa_subdomains_ctx);
- if (ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- return ENOMEM;
+
+ if (sd_ctx->last_refreshed > time(NULL) - IPA_SUBDOMAIN_REFRESH_LIMIT) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains were recently refreshed, "
+ "nothing to do\n");
+ ret = EOK;
+ goto immediately;
}
- ctx->be_ctx = be_ctx;
- ctx->id_ctx = id_ctx;
- ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
- ctx->search_bases = id_ctx->ipa_options->subdomains_search_bases;
- ctx->master_search_bases = id_ctx->ipa_options->master_domain_search_bases;
- ctx->ranges_search_bases = id_ctx->ipa_options->ranges_search_bases;
- ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
- ctx->configured_explicit = configured_explicit;
- ctx->disabled_until = 0;
- *ops = &ipa_subdomains_ops;
- *pvt_data = ctx;
-
- ret = be_add_unconditional_online_cb(ctx, be_ctx,
- ipa_subdom_reset_timeouts_cb, ctx,
- NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to add subdom reset timeouts callback\n");
+ subreq = ipa_subdomains_refresh_send(state, params->ev, sd_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- ret = be_add_online_cb(ctx, be_ctx, ipa_subdom_online_cb, ctx, NULL);
+ tevent_req_set_callback(subreq, ipa_subdomains_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 ipa_subdomains_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_subdomains_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 ipa_subdomains_handler_state);
+
+ ret = ipa_subdomains_refresh_recv(subreq);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom online callback\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to refresh subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+
+ /* 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);
+}
+
+static errno_t ipa_subdomains_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct ipa_subdomains_handler_state *state;
+
+ state = tevent_req_data(req, struct ipa_subdomains_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
+}
+
+static struct tevent_req *
+ipa_subdomains_ptask_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct be_ptask *be_ptask,
+ void *pvt)
+{
+ struct ipa_subdomains_ctx *sd_ctx;
+ sd_ctx = talloc_get_type(pvt, struct ipa_subdomains_ctx);
+
+ return ipa_subdomains_refresh_send(mem_ctx, ev, sd_ctx);
+}
+
+static errno_t
+ipa_subdomains_ptask_recv(struct tevent_req *req)
+{
+ return ipa_subdomains_refresh_recv(req);
+}
+
+errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_id_ctx *ipa_id_ctx,
+ struct dp_method *dp_methods)
+{
+ struct ipa_subdomains_ctx *sd_ctx;
+ struct ipa_options *ipa_options;
+ time_t period;
+ errno_t ret;
+
+ ipa_options = ipa_id_ctx->ipa_options;
+
+ sd_ctx = talloc_zero(mem_ctx, struct ipa_subdomains_ctx);
+ if (sd_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
+ return ENOMEM;
}
- ret = be_add_offline_cb(ctx, be_ctx, ipa_subdom_offline_cb, ctx, NULL);
+ sd_ctx->be_ctx = be_ctx;
+ sd_ctx->ipa_id_ctx = ipa_id_ctx;
+ sd_ctx->sdap_id_ctx = ipa_id_ctx->sdap_id_ctx;
+ sd_ctx->search_bases = ipa_options->subdomains_search_bases;
+ sd_ctx->master_search_bases = ipa_options->master_domain_search_bases;
+ sd_ctx->ranges_search_bases = ipa_options->ranges_search_bases;
+ sd_ctx->host_search_bases = ipa_options->host_search_bases;
+
+ dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
+ ipa_subdomains_handler_send, ipa_subdomains_handler_recv, sd_ctx,
+ struct ipa_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
+
+ period = be_ctx->domain->subdomain_refresh_interval;
+ ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
+ BE_PTASK_OFFLINE_DISABLE, 0,
+ ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx,
+ "Subdomains Refresh", NULL);
if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom offline callback\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ /* Ignore, responders will trigger refresh from time to time. */
}
- ret = ipa_subdom_reinit(ctx);
+ ret = ipa_subdom_reinit(sd_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Could not load the list of subdomains. "
+ DEBUG(SSSDBG_MINOR_FAILURE, "Could not reinitialize subdomains. "
"Users from trusted domains might not be resolved correctly\n");
+ /* Ignore this error and try to discover the subdomains later */
}
- ret = ipa_ad_subdom_init(be_ctx, id_ctx);
+ ret = ipa_ad_subdom_init(be_ctx, ipa_id_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "ipa_ad_subdom_init failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "ipa_ad_subdom_init() failed.\n");
return ret;
}
diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h
index 270867fb0..8e66ca977 100644
--- a/src/providers/ipa/ipa_subdomains.h
+++ b/src/providers/ipa/ipa_subdomains.h
@@ -37,12 +37,10 @@
#define EXOP_SID2NAME_OID "2.16.840.1.113730.3.8.10.4"
#define EXOP_SID2NAME_V1_OID "2.16.840.1.113730.3.8.10.4.1"
-struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx);
-
-int ipa_subdom_init(struct be_ctx *be_ctx,
- struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data);
+errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ipa_id_ctx *ipa_id_ctx,
+ struct dp_method *dp_methods);
/* The following are used in server mode only */
struct ipa_ad_server_ctx {
diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
index a8ba4dfe8..93ef1f4a1 100644
--- a/src/providers/ipa/ipa_subdomains_ext_groups.c
+++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
@@ -1108,8 +1108,9 @@ struct tevent_req *ipa_ext_group_member_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- subreq = be_get_account_info_send(state, ev, NULL,
- ipa_ctx->sdap_id_ctx->be, ar);
+ subreq = dp_req_send(state, ipa_ctx->sdap_id_ctx->be->provider, NULL,
+ ar->domain, "External Member",
+ DPT_ID, DPM_ACCOUNT_HANDLER, 0, ar, NULL);
if (subreq == NULL) {
ret = ENOMEM;
goto immediate;
@@ -1135,20 +1136,23 @@ static void ipa_ext_group_member_done(struct tevent_req *subreq)
struct ipa_ext_member_state *state = tevent_req_data(req,
struct ipa_ext_member_state);
errno_t ret;
- int err_maj;
- int err_min;
- const char *err_msg;
struct ldb_message *msg;
struct sysdb_attrs **members;
+ struct dp_reply_std *reply;
- ret = be_get_account_info_recv(subreq, state,
- &err_maj, &err_min, &err_msg);
+
+ ret = dp_req_recv_ptr(state, subreq, struct dp_reply_std, &reply);
talloc_free(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "be request failed %d:%d: %s\n", err_maj, err_min, err_msg);
+ DEBUG(SSSDBG_OP_FAILURE, "dp_req_recv failed\n");
tevent_req_error(req, ret);
return;
+ } else if (reply->dp_error != DP_ERR_OK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot refresh data from DP: %u,%u: %s\n",
+ reply->dp_error, reply->error, reply->message);
+ tevent_req_error(req, EIO);
+ return;
}
ret = search_user_or_group_by_sid_str(state,
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index 665ff635b..f06eff7a7 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -40,7 +40,6 @@ static struct tevent_req *
ipa_srv_ad_acct_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
- struct be_req *be_req,
struct sysdb_attrs *override_attrs,
struct be_acct_req *ar);
static errno_t
@@ -53,7 +52,6 @@ struct ipa_subdomain_account_state {
struct sdap_id_op *op;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
- struct be_req *be_req;
struct be_acct_req *ar;
bool ipa_server_mode;
@@ -75,7 +73,6 @@ static errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
- struct be_req *be_req,
struct be_acct_req *ar)
{
struct tevent_req *req;
@@ -109,7 +106,6 @@ struct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
goto fail;
}
state->sysdb = state->domain->sysdb;
- state->be_req = be_req;
state->ar = ar;
state->ipa_server_mode = dp_opt_get_bool(state->ipa_ctx->ipa_options->basic,
IPA_SERVER_MODE);
@@ -277,7 +273,7 @@ static errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
if (state->ipa_server_mode) {
subreq = ipa_srv_ad_acct_send(state, state->ev, state->ipa_ctx,
- state->be_req, state->override_attrs, ar);
+ state->override_attrs, ar);
} else {
subreq = ipa_get_subdom_acct_send(state, state->ev, state->ipa_ctx,
state->override_attrs, ar);
@@ -402,7 +398,6 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
case BE_REQ_USER:
case BE_REQ_GROUP:
case BE_REQ_BY_SECID:
- case BE_REQ_BY_CERT:
case BE_REQ_USER_AND_GROUP:
ret = EOK;
break;
@@ -625,7 +620,6 @@ struct ipa_get_ad_acct_state {
int dp_error;
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
- struct be_req *be_req;
struct be_acct_req *ar;
struct sss_domain_info *obj_dom;
char *object_sid;
@@ -646,7 +640,6 @@ static struct tevent_req *
ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
- struct be_req *be_req,
struct sysdb_attrs *override_attrs,
struct be_acct_req *ar)
{
@@ -665,7 +658,6 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
state->dp_error = -1;
state->ev = ev;
state->ipa_ctx = ipa_ctx;
- state->be_req = be_req;
state->ar = ar;
state->obj_msg = NULL;
state->override_attrs = override_attrs;
@@ -715,7 +707,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
goto fail;
}
- subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx,
+ subreq = ad_handle_acct_info_send(req, ar, sdap_id_ctx,
ad_id_ctx->ad_options, sdom, clist);
if (subreq == NULL) {
ret = ENOMEM;
@@ -1404,7 +1396,6 @@ ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
struct ipa_srv_ad_acct_state {
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
- struct be_req *be_req;
struct sysdb_attrs *override_attrs;
struct be_acct_req *ar;
@@ -1423,7 +1414,6 @@ static struct tevent_req *
ipa_srv_ad_acct_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
- struct be_req *be_req,
struct sysdb_attrs *override_attrs,
struct be_acct_req *ar)
{
@@ -1438,12 +1428,11 @@ ipa_srv_ad_acct_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->ipa_ctx = ipa_ctx;
- state->be_req = be_req;
state->override_attrs = override_attrs;
state->ar = ar;
state->retry = true;
state->dp_error = DP_ERR_FATAL;
- state->be_ctx = be_req_get_be_ctx(state->be_req);
+ state->be_ctx = ipa_ctx->sdap_id_ctx->be;
state->obj_dom = find_domain_by_name(
state->ipa_ctx->sdap_id_ctx->be->domain,
@@ -1475,7 +1464,7 @@ static int ipa_srv_ad_acct_lookup_step(struct tevent_req *req)
DEBUG(SSSDBG_TRACE_FUNC, "Looking up AD account\n");
subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
- state->be_req, state->override_attrs,
+ state->override_attrs,
state->ar);
if (subreq == NULL) {
return ENOMEM;
diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
index b870d5552..43636098f 100644
--- a/src/providers/ipa/ipa_subdomains_server.c
+++ b/src/providers/ipa/ipa_subdomains_server.c
@@ -961,7 +961,7 @@ void ipa_ad_subdom_remove(struct be_ctx *be_ctx,
DLIST_REMOVE(id_ctx->server_mode->trusts, iter);
/* terminate all requests for this subdomain so we can free it */
- be_terminate_domain_requests(be_ctx, subdom->name);
+ dp_terminate_domain_requests(be_ctx->provider, subdom->name);
talloc_zfree(sdom);
}
diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c
index b4633858f..c93d8ca29 100644
--- a/src/providers/ipa/ipa_sudo.c
+++ b/src/providers/ipa/ipa_sudo.c
@@ -24,13 +24,119 @@
#include "providers/ipa/ipa_sudo.h"
#include "db/sysdb_sudo.h"
-static void ipa_sudo_handler(struct be_req *breq);
-
-struct bet_ops ipa_sudo_ops = {
- .handler = ipa_sudo_handler,
- .finalize = NULL,
+struct ipa_sudo_handler_state {
+ uint32_t type;
+ struct dp_reply_std reply;
};
+static void ipa_sudo_handler_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_sudo_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_sudo_ctx *sudo_ctx,
+ struct dp_sudo_data *data,
+ struct dp_req_params *params)
+{
+ struct ipa_sudo_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct ipa_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 = ipa_sudo_full_refresh_send(state, params->ev, sudo_ctx);
+ break;
+ case BE_REQ_SUDO_RULES:
+ DEBUG(SSSDBG_TRACE_FUNC, "Issuing a refresh of specific sudo rules\n");
+ subreq = ipa_sudo_rules_refresh_send(state, params->ev, 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, ipa_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 ipa_sudo_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_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 ipa_sudo_handler_state);
+
+ switch (state->type) {
+ case BE_REQ_SUDO_FULL:
+ ret = ipa_sudo_full_refresh_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+ break;
+ case BE_REQ_SUDO_RULES:
+ ret = ipa_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
+ipa_sudo_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct ipa_sudo_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_sudo_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
+}
+
enum sudo_schema {
SUDO_SCHEMA_IPA,
SUDO_SCHEMA_LDAP
@@ -95,10 +201,10 @@ done:
}
static int
-ipa_sudo_init_ipa_schema(struct be_ctx *be_ctx,
+ipa_sudo_init_ipa_schema(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+ struct dp_method *dp_methods)
{
struct ipa_sudo_ctx *sudo_ctx;
errno_t ret;
@@ -154,8 +260,9 @@ ipa_sudo_init_ipa_schema(struct be_ctx *be_ctx,
goto done;
}
- *ops = &ipa_sudo_ops;
- *pvt_data = sudo_ctx;
+ dp_set_method(dp_methods, DPM_SUDO_HANDLER,
+ ipa_sudo_handler_send, ipa_sudo_handler_recv, sudo_ctx,
+ struct ipa_sudo_ctx, struct dp_sudo_data, struct dp_reply_std);
ret = EOK;
@@ -167,10 +274,10 @@ done:
return ret;
}
-int ipa_sudo_init(struct be_ctx *be_ctx,
+int ipa_sudo_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
struct ipa_id_ctx *id_ctx,
- struct bet_ops **ops,
- void **pvt_data)
+ struct dp_method *dp_methods)
{
enum sudo_schema schema;
errno_t ret;
@@ -189,11 +296,11 @@ int ipa_sudo_init(struct be_ctx *be_ctx,
switch (schema) {
case SUDO_SCHEMA_IPA:
DEBUG(SSSDBG_TRACE_FUNC, "Using IPA schema for sudo\n");
- ret = ipa_sudo_init_ipa_schema(be_ctx, id_ctx, ops, pvt_data);
+ ret = ipa_sudo_init_ipa_schema(mem_ctx, be_ctx, id_ctx, dp_methods);
break;
case SUDO_SCHEMA_LDAP:
DEBUG(SSSDBG_TRACE_FUNC, "Using LDAP schema for sudo\n");
- ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data);
+ ret = sdap_sudo_init(mem_ctx, be_ctx, id_ctx->sdap_id_ctx, dp_methods);
break;
}
@@ -205,86 +312,3 @@ int ipa_sudo_init(struct be_ctx *be_ctx,
return EOK;
}
-
-static void
-ipa_sudo_reply(struct tevent_req *req)
-{
- struct be_sudo_req *sudo_req;
- struct be_req *be_req;
- bool deleted;
- int dp_error;
- 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 = ipa_sudo_full_refresh_recv(req, &dp_error);
- break;
- case BE_REQ_SUDO_RULES:
- ret = ipa_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, sss_strerror(ret));
-}
-
-static void
-ipa_sudo_handler(struct be_req *be_req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ipa_sudo_ctx *sudo_ctx;
- struct be_sudo_req *sudo_req;
- struct tevent_req *req;
- int ret;
-
- 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 ipa_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:
- req = ipa_sudo_full_refresh_send(be_req, be_ctx->ev, sudo_ctx);
- break;
- case BE_REQ_SUDO_RULES:
- req = ipa_sudo_rules_refresh_send(be_req, be_ctx->ev, 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, ipa_sudo_reply, be_req);
-
- return;
-
-fail:
- sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL);
-}
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 7ed7bd73d..dabf55cf2 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -137,34 +137,6 @@ static int krb5_delete_ccname(TALLOC_CTX *mem_ctx,
SYSDB_MOD_DEL);
}
-static struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct pam_data *pd;
-
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
-
- switch (pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- case SSS_CMD_RENEW:
- return talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
- struct krb5_ctx);
- break;
- case SSS_PAM_ACCT_MGMT:
- return talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct krb5_ctx);
- break;
- case SSS_PAM_CHAUTHTOK:
- case SSS_PAM_CHAUTHTOK_PRELIM:
- return talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
- struct krb5_ctx);
- break;
- default:
- DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
- return NULL;
- }
-}
-
static int krb5_cleanup(void *ptr)
{
struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
@@ -1165,115 +1137,137 @@ int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)
return EOK;
}
-void krb5_pam_handler_auth_done(struct tevent_req *req);
-static void krb5_pam_handler_access_done(struct tevent_req *req);
+struct krb5_pam_handler_state {
+ struct pam_data *pd;
+};
+
+static void krb5_pam_handler_auth_done(struct tevent_req *subreq);
+static void krb5_pam_handler_access_done(struct tevent_req *subreq);
-void krb5_pam_handler(struct be_req *be_req)
+struct tevent_req *
+krb5_pam_handler_send(TALLOC_CTX *mem_ctx,
+ struct krb5_ctx *krb5_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
+ struct krb5_pam_handler_state *state;
+ struct tevent_req *subreq;
struct tevent_req *req;
- struct pam_data *pd;
- struct krb5_ctx *krb5_ctx;
- int dp_err = DP_ERR_FATAL;
-
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
- pd->pam_status = PAM_SYSTEM_ERR;
- krb5_ctx = get_krb5_ctx(be_req);
- if (krb5_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Kerberos context not available.\n");
- goto done;
+ req = tevent_req_create(mem_ctx, &state,
+ struct krb5_pam_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
+ state->pd = pd;
+
switch (pd->cmd) {
case SSS_PAM_AUTHENTICATE:
case SSS_CMD_RENEW:
case SSS_PAM_CHAUTHTOK_PRELIM:
case SSS_PAM_CHAUTHTOK:
- req = krb5_auth_queue_send(be_req, be_ctx->ev, be_ctx, pd, krb5_ctx);
- if (req == NULL) {
+ subreq = krb5_auth_queue_send(state, params->ev, params->be_ctx,
+ pd, krb5_ctx);
+ if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
- goto done;
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
}
- tevent_req_set_callback(req, krb5_pam_handler_auth_done, be_req);
+ tevent_req_set_callback(subreq, krb5_pam_handler_auth_done, req);
break;
case SSS_PAM_ACCT_MGMT:
- req = krb5_access_send(be_req, be_ctx->ev, be_ctx, pd, krb5_ctx);
- if (req == NULL) {
+ subreq = krb5_access_send(state, params->ev, params->be_ctx,
+ pd, krb5_ctx);
+ if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "krb5_access_send failed.\n");
- goto done;
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
}
- tevent_req_set_callback(req, krb5_pam_handler_access_done, be_req);
+ tevent_req_set_callback(subreq, krb5_pam_handler_access_done, req);
break;
case SSS_PAM_SETCRED:
case SSS_PAM_OPEN_SESSION:
case SSS_PAM_CLOSE_SESSION:
pd->pam_status = PAM_SUCCESS;
- dp_err = DP_ERR_OK;
- goto done;
+ goto immediately;
break;
default:
DEBUG(SSSDBG_CONF_SETTINGS,
"krb5 does not handles pam task %d.\n", pd->cmd);
pd->pam_status = PAM_MODULE_UNKNOWN;
- dp_err = DP_ERR_OK;
- goto done;
+ goto immediately;
}
- return;
+ return req;
-done:
- be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
+immediately:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+ tevent_req_post(req, params->ev);
+
+ return req;
}
-void krb5_pam_handler_auth_done(struct tevent_req *req)
+static void krb5_pam_handler_auth_done(struct tevent_req *subreq)
{
- int ret;
- struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
- int pam_status;
- int dp_err;
- struct pam_data *pd;
+ struct krb5_pam_handler_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct krb5_pam_handler_state);
- ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
- talloc_zfree(req);
- if (ret) {
- pd->pam_status = PAM_SYSTEM_ERR;
- dp_err = DP_ERR_OK;
- } else {
- pd->pam_status = pam_status;
+ ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, NULL);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
}
- be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static void krb5_pam_handler_access_done(struct tevent_req *req)
+static void krb5_pam_handler_access_done(struct tevent_req *subreq)
{
- int ret;
- struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
+ struct krb5_pam_handler_state *state;
+ struct tevent_req *req;
bool access_allowed;
- struct pam_data *pd;
- int dp_err = DP_ERR_OK;
+ errno_t ret;
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
- pd->pam_status = PAM_SYSTEM_ERR;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct krb5_pam_handler_state);
- ret = krb5_access_recv(req, &access_allowed);
- talloc_zfree(req);
+ ret = krb5_access_recv(subreq, &access_allowed);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "krb5_access request failed [%d][%s]\n", ret, strerror(ret));
- goto done;
+ state->pd->pam_status = PAM_SYSTEM_ERR;
}
+
DEBUG(SSSDBG_TRACE_LIBS, "Access %s for user [%s].\n",
- access_allowed ? "allowed" : "denied", pd->user);
- pd->pam_status = access_allowed ? PAM_SUCCESS : PAM_PERM_DENIED;
- dp_err = DP_ERR_OK;
+ access_allowed ? "allowed" : "denied", state->pd->user);
+ state->pd->pam_status = access_allowed ? PAM_SUCCESS : PAM_PERM_DENIED;
-done:
- be_req_terminate(be_req, dp_err, pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+krb5_pam_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct krb5_pam_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct krb5_pam_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
}
diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
index 1822f2b98..dbad061f0 100644
--- a/src/providers/krb5/krb5_auth.h
+++ b/src/providers/krb5/krb5_auth.h
@@ -63,8 +63,16 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
struct krb5_ctx *krb5_ctx, bool case_sensitive,
struct krb5child_req **krb5_req);
-void krb5_pam_handler(struct be_req *be_req);
-void krb5_pam_handler_auth_done(struct tevent_req *req);
+struct tevent_req *
+krb5_pam_handler_send(TALLOC_CTX *mem_ctx,
+ struct krb5_ctx *krb5_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+krb5_pam_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data);
/* Please use krb5_auth_send/recv *only* if you're certain there can't
* be concurrent logins happening. With some ccache back ends, the ccache
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index 367b56e08..3bd5ed1c8 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -190,10 +190,6 @@ errno_t krb5_get_simple_upn(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx,
errno_t compare_principal_realm(const char *upn, const char *realm,
bool *different_realm);
-int sssm_krb5_auth_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_auth_data);
-
/* from krb5_keytab.c */
/**
diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
index 4f36d905b..d356491e5 100644
--- a/src/providers/krb5/krb5_init.c
+++ b/src/providers/krb5/krb5_init.c
@@ -30,171 +30,202 @@
#include "providers/krb5/krb5_auth.h"
#include "providers/krb5/krb5_common.h"
#include "providers/krb5/krb5_init_shared.h"
+#include "providers/data_provider.h"
-struct krb5_options {
- struct dp_option *opts;
- struct krb5_ctx *auth_ctx;
-};
+static errno_t krb5_init_kpasswd(struct krb5_ctx *ctx,
+ struct be_ctx *be_ctx)
+{
+ const char *realm;
+ const char *primary_servers;
+ const char *backup_servers;
+ const char *kdc_servers;
+ bool use_kdcinfo;
+ errno_t ret;
+
+ realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Missing krb5_realm option!\n");
+ return EINVAL;
+ }
-struct krb5_options *krb5_options = NULL;
+ kdc_servers = dp_opt_get_string(ctx->opts, KRB5_KDC);
+ primary_servers = dp_opt_get_string(ctx->opts, KRB5_KPASSWD);
+ backup_servers = dp_opt_get_string(ctx->opts, KRB5_BACKUP_KPASSWD);
+ use_kdcinfo = dp_opt_get_bool(ctx->opts, KRB5_USE_KDCINFO);
-struct bet_ops krb5_auth_ops = {
- .handler = krb5_pam_handler,
- .finalize = NULL,
-};
+ if (primary_servers == NULL && backup_servers != NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "kpasswd server wasn't specified but "
+ "backup_servers kpasswd given. Using it as primary_servers\n");
+ primary_servers = backup_servers;
+ backup_servers = NULL;
+ }
-int krb5_ctx_re_destructor(void *memctx)
+ if (primary_servers == NULL && kdc_servers != NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Missing krb5_kpasswd option and KDC set "
+ "explicitly, will use KDC for pasword change operations!\n");
+ ctx->kpasswd_service = NULL;
+ } else {
+ ret = krb5_service_init(ctx, be_ctx, SSS_KRB5KPASSWD_FO_SRV,
+ primary_servers, backup_servers, realm,
+ use_kdcinfo, &ctx->kpasswd_service);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to init KRB5KPASSWD failover service!\n");
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t krb5_init_kdc(struct krb5_ctx *ctx, struct be_ctx *be_ctx)
{
- struct krb5_ctx *ctx = (struct krb5_ctx *) memctx;
+ const char *primary_servers;
+ const char *backup_servers;
+ const char *realm;
+ bool use_kdcinfo;
+ errno_t ret;
+
+ realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Missing krb5_realm option!\n");
+ return EINVAL;
+ }
+
+ primary_servers = dp_opt_get_string(ctx->opts, KRB5_KDC);
+ backup_servers = dp_opt_get_string(ctx->opts, KRB5_BACKUP_KDC);
+
+ use_kdcinfo = dp_opt_get_bool(ctx->opts, KRB5_USE_KDCINFO);
+
+ ret = krb5_service_init(ctx, be_ctx, SSS_KRB5KDC_FO_SRV,
+ primary_servers, backup_servers, realm,
+ use_kdcinfo, &ctx->service);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init KRB5 failover service!\n");
+ return ret;
+ }
- if (ctx->illegal_path_re) {
+ return EOK;
+}
+
+int krb5_ctx_re_destructor(struct krb5_ctx *ctx)
+{
+ if (ctx->illegal_path_re != NULL) {
pcre_free(ctx->illegal_path_re);
ctx->illegal_path_re = NULL;
}
+
return 0;
}
-int sssm_krb5_auth_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_auth_data)
+errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct data_provider *provider,
+ const char *module_name,
+ void **_module_data)
{
- struct krb5_ctx *ctx = NULL;
- int ret;
- const char *krb5_servers;
- const char *krb5_backup_servers;
- const char *krb5_kpasswd_servers;
- const char *krb5_backup_kpasswd_servers;
- const char *krb5_realm;
+ struct krb5_ctx *ctx;
const char *errstr;
int errval;
int errpos;
+ errno_t ret;
- if (krb5_options == NULL) {
- krb5_options = talloc_zero(bectx, struct krb5_options);
- if (krb5_options == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
- return ENOMEM;
- }
- ret = krb5_get_options(krb5_options, bectx->cdb, bectx->conf_path,
- &krb5_options->opts);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "krb5_get_options failed.\n");
- return ret;
- }
- }
-
- if (krb5_options->auth_ctx != NULL) {
- *ops = &krb5_auth_ops;
- *pvt_auth_data = krb5_options->auth_ctx;
- return EOK;
+ ctx = talloc_zero(mem_ctx, struct krb5_ctx);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
+ return ENOMEM;
}
- ctx = talloc_zero(bectx, struct krb5_ctx);
- if (!ctx) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
- return ENOMEM;
+ ret = krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- krb5_options->auth_ctx = ctx;
ctx->action = INIT_PW;
- ctx->opts = krb5_options->opts;
ctx->config_type = K5C_GENERIC;
- krb5_servers = dp_opt_get_string(ctx->opts, KRB5_KDC);
- krb5_backup_servers = dp_opt_get_string(ctx->opts, KRB5_BACKUP_KDC);
-
- krb5_realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
- if (krb5_realm == NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Missing krb5_realm option!\n");
- return EINVAL;
- }
-
- ret = krb5_service_init(ctx, bectx,
- SSS_KRB5KDC_FO_SRV, krb5_servers,
- krb5_backup_servers, krb5_realm,
- dp_opt_get_bool(krb5_options->opts,
- KRB5_USE_KDCINFO),
- &ctx->service);
+ ret = krb5_init_kdc(ctx, be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init KRB5 failover service!\n");
- return ret;
- }
-
- krb5_kpasswd_servers = dp_opt_get_string(ctx->opts, KRB5_KPASSWD);
- krb5_backup_kpasswd_servers = dp_opt_get_string(ctx->opts,
- KRB5_BACKUP_KPASSWD);
- if (krb5_kpasswd_servers == NULL && krb5_backup_kpasswd_servers != NULL) {
- DEBUG(SSSDBG_CONF_SETTINGS, "kpasswd server wasn't specified but "
- "backup kpasswd given. Using it as primary\n");
- krb5_kpasswd_servers = krb5_backup_kpasswd_servers;
- krb5_backup_kpasswd_servers = NULL;
+ goto done;
}
- if (krb5_kpasswd_servers == NULL && krb5_servers != NULL) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Missing krb5_kpasswd option and KDC set explicitly, "
- "will use KDC for pasword change operations!\n");
- ctx->kpasswd_service = NULL;
- } else {
- ret = krb5_service_init(ctx, bectx,
- SSS_KRB5KPASSWD_FO_SRV, krb5_kpasswd_servers,
- krb5_backup_kpasswd_servers, krb5_realm,
- dp_opt_get_bool(krb5_options->opts,
- KRB5_USE_KDCINFO),
- &ctx->kpasswd_service);
- if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to init KRB5KPASSWD failover service!\n");
- return ret;
- }
+ ret = krb5_init_kpasswd(ctx, be_ctx);
+ if (ret != EOK) {
+ goto done;
}
- /* Initialize features needed by the krb5_child */
- ret = krb5_child_init(ctx, bectx);
+ ret = krb5_child_init(ctx, be_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Could not initialize krb5_child settings: [%s]\n",
- strerror(ret));
- goto fail;
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize krb5_child settings "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
&errval, &errstr, &errpos, NULL);
if (ctx->illegal_path_re == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Invalid Regular Expression pattern at position %d. "
- "(Error: %d [%s])\n", errpos, errval, errstr);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid Regular Expression pattern "
+ "at position %d. (Error: %d [%s])\n", errpos, errval, errstr);
ret = EFAULT;
- goto fail;
+ goto done;
}
- talloc_set_destructor((TALLOC_CTX *) ctx, krb5_ctx_re_destructor);
+ talloc_set_destructor(ctx, krb5_ctx_re_destructor);
- ret = be_fo_set_dns_srv_lookup_plugin(bectx, NULL);
+ 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));
- goto fail;
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- *ops = &krb5_auth_ops;
- *pvt_auth_data = ctx;
- return EOK;
+ *_module_data = ctx;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(ctx);
+ }
-fail:
- talloc_zfree(krb5_options->auth_ctx);
return ret;
}
-int sssm_krb5_chpass_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_auth_data)
+errno_t sssm_krb5_auth_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- return sssm_krb5_auth_init(bectx, ops, pvt_auth_data);
+ struct krb5_ctx *ctx;
+
+ ctx = talloc_get_type(module_data, struct krb5_ctx);
+ dp_set_method(dp_methods, DPM_AUTH_HANDLER,
+ krb5_pam_handler_send, krb5_pam_handler_recv, ctx,
+ struct krb5_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
}
-int sssm_krb5_access_init(struct be_ctx *bectx,
- struct bet_ops **ops,
- void **pvt_auth_data)
+errno_t sssm_krb5_chpass_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- return sssm_krb5_auth_init(bectx, ops, pvt_auth_data);
+ return sssm_krb5_auth_init(mem_ctx, be_ctx, module_data, dp_methods);
+}
+
+errno_t sssm_krb5_access_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ struct krb5_ctx *ctx;
+
+ ctx = talloc_get_type(module_data, struct krb5_ctx);
+ dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+ krb5_pam_handler_send, krb5_pam_handler_recv, ctx,
+ struct krb5_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
}
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,
diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h
index 65479a448..11c85c54e 100644
--- a/src/providers/proxy/proxy.h
+++ b/src/providers/proxy/proxy.h
@@ -137,15 +137,34 @@ struct pc_init_ctx {
struct sbus_connection *conn;
};
+//int proxy_client_init(struct sbus_connection *conn, void *data);
+
#define PROXY_CHILD_PIPE "private/proxy_child"
#define DEFAULT_BUFSIZE 4096
#define MAX_BUF_SIZE 1024*1024 /* max 1MiB */
/* From proxy_id.c */
-void proxy_get_account_info(struct be_req *breq);
+struct tevent_req *
+proxy_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct proxy_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params);
+
+errno_t proxy_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data);
/* From proxy_auth.c */
-void proxy_pam_handler(struct be_req *req);
+struct tevent_req *
+proxy_pam_handler_send(TALLOC_CTX *mem_ctx,
+ struct proxy_auth_ctx *proxy_auth_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params);
+
+errno_t
+proxy_pam_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data);
/* From proxy_netgroup.c */
errno_t get_netgroup(struct proxy_id_ctx *ctx,
@@ -167,4 +186,6 @@ errno_t enum_services(struct proxy_id_ctx *ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *dom);
+int proxy_client_init(struct sbus_connection *conn, void *data);
+
#endif /* __PROXY_H__ */
diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c
index edf058edc..6e7139aaa 100644
--- a/src/providers/proxy/proxy_auth.c
+++ b/src/providers/proxy/proxy_auth.c
@@ -24,75 +24,6 @@
#include "providers/proxy/proxy.h"
-struct proxy_client_ctx {
- struct be_req *be_req;
- struct proxy_auth_ctx *auth_ctx;
-};
-
-static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
- struct proxy_auth_ctx *ctx,
- struct be_req *be_req);
-static void proxy_child_done(struct tevent_req *child_req);
-void proxy_pam_handler(struct be_req *req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(req);
- struct pam_data *pd;
- struct proxy_auth_ctx *ctx;
- struct tevent_req *child_req = NULL;
- struct proxy_client_ctx *client_ctx;
-
- pd = talloc_get_type(be_req_get_data(req), struct pam_data);
-
- switch (pd->cmd) {
- case SSS_PAM_AUTHENTICATE:
- ctx = talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
- struct proxy_auth_ctx);
- break;
- case SSS_PAM_CHAUTHTOK:
- case SSS_PAM_CHAUTHTOK_PRELIM:
- ctx = talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
- struct proxy_auth_ctx);
- break;
- case SSS_PAM_ACCT_MGMT:
- ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct proxy_auth_ctx);
- break;
- case SSS_PAM_SETCRED:
- case SSS_PAM_OPEN_SESSION:
- case SSS_PAM_CLOSE_SESSION:
- pd->pam_status = PAM_SUCCESS;
- be_req_terminate(req, DP_ERR_OK, EOK, NULL);
- return;
- default:
- DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
- pd->pam_status = PAM_MODULE_UNKNOWN;
- be_req_terminate(req, DP_ERR_OK, EINVAL, "Unsupported PAM task");
- return;
- }
-
- client_ctx = talloc(req, struct proxy_client_ctx);
- if (client_ctx == NULL) {
- be_req_terminate(req, DP_ERR_FATAL, ENOMEM, NULL);
- return;
- }
- client_ctx->auth_ctx = ctx;
- client_ctx->be_req = req;
-
- /* Queue the request and spawn a child if there
- * is an available slot.
- */
- child_req = proxy_child_send(req, ctx, req);
- if (child_req == NULL) {
- /* Could not queue request
- * Return an error
- */
- be_req_terminate(req, DP_ERR_FATAL, EINVAL, "Could not queue request\n");
- return;
- }
- tevent_req_set_callback(child_req, proxy_child_done, client_ctx);
- return;
-}
-
struct pc_init_ctx;
static int proxy_child_destructor(TALLOC_CTX *ctx)
@@ -122,7 +53,7 @@ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
static void proxy_child_init_done(struct tevent_req *subreq);
static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
struct proxy_auth_ctx *auth_ctx,
- struct be_req *be_req)
+ struct pam_data *pd)
{
struct tevent_req *req;
struct tevent_req *subreq;
@@ -138,9 +69,8 @@ static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
return NULL;
}
- state->be_req = be_req;
state->auth_ctx = auth_ctx;
- state->pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
+ state->pd = pd;
/* Find an available key */
key.type = HASH_KEY_ULONG;
@@ -731,69 +661,6 @@ static int proxy_child_recv(struct tevent_req *req,
return EOK;
}
-static void proxy_child_done(struct tevent_req *req)
-{
- struct proxy_client_ctx *client_ctx =
- tevent_req_callback_data(req, struct proxy_client_ctx);
- struct be_ctx *be_ctx = be_req_get_be_ctx(client_ctx->be_req);
- struct pam_data *pd = NULL;
- const char *password;
- int ret;
- struct tevent_immediate *imm;
-
- ret = proxy_child_recv(req, client_ctx, &pd);
- talloc_zfree(req);
-
- /* Start the next auth in the queue, if any */
- client_ctx->auth_ctx->running--;
- imm = tevent_create_immediate(be_ctx->ev);
- if (imm == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
- /* We'll still finish the current request, but we're
- * likely to have problems if there are queued events
- * if we've gotten into this state.
- * Hopefully this is impossible, since freeing req
- * above should guarantee that we have enough memory
- * to create this immediate event.
- */
- } else {
- tevent_schedule_immediate(imm, be_ctx->ev,
- run_proxy_child_queue,
- client_ctx->auth_ctx);
- }
-
- if (ret != EOK) {
- /* Pam child failed */
- be_req_terminate(client_ctx->be_req, DP_ERR_FATAL, ret,
- "PAM child failed");
- return;
- }
-
- /* Check if we need to save the cached credentials */
- if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) &&
- (pd->pam_status == PAM_SUCCESS) && be_ctx->domain->cache_credentials) {
-
- ret = sss_authtok_get_password(pd->authtok, &password, NULL);
- if (ret) {
- /* password caching failures are not fatal errors */
- DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password\n");
- goto done;
- }
-
- ret = sysdb_cache_password(be_ctx->domain, pd->user, password);
-
- /* password caching failures are not fatal errors */
- /* so we just log it any return */
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password (%d)[%s]!?\n",
- ret, strerror(ret));
- }
- }
-
-done:
- be_req_terminate(client_ctx->be_req, DP_ERR_OK, EOK, NULL);
-}
-
static void run_proxy_child_queue(struct tevent_context *ev,
struct tevent_immediate *imm,
void *pvt)
@@ -840,3 +707,144 @@ static void run_proxy_child_queue(struct tevent_context *ev,
state->running = true;
}
}
+
+struct proxy_pam_handler_state {
+ struct pam_data *pd;
+ struct proxy_auth_ctx *auth_ctx;
+ struct be_ctx *be_ctx;
+};
+
+static void proxy_pam_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+proxy_pam_handler_send(TALLOC_CTX *mem_ctx,
+ struct proxy_auth_ctx *proxy_auth_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
+{
+ struct proxy_pam_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state, struct proxy_pam_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->pd = pd;
+ state->auth_ctx = proxy_auth_ctx;
+ state->be_ctx = params->be_ctx;
+
+ switch (pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ case SSS_PAM_CHAUTHTOK:
+ case SSS_PAM_CHAUTHTOK_PRELIM:
+ case SSS_PAM_ACCT_MGMT:
+ /* Queue the request and spawn a child if there is an available slot. */
+ subreq = proxy_child_send(state, proxy_auth_ctx, state->pd);
+ if (subreq == NULL) {
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
+ }
+ tevent_req_set_callback(subreq, proxy_pam_handler_done, req);
+ break;
+ case SSS_PAM_SETCRED:
+ case SSS_PAM_OPEN_SESSION:
+ case SSS_PAM_CLOSE_SESSION:
+ pd->pam_status = PAM_SUCCESS;
+ goto immediately;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
+ 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 proxy_pam_handler_done(struct tevent_req *subreq)
+{
+ struct proxy_pam_handler_state *state;
+ struct tevent_immediate *imm;
+ struct tevent_req *req;
+ const char *password;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct proxy_pam_handler_state);
+
+ ret = proxy_child_recv(subreq, state, &state->pd);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ /* Start the next auth in the queue, if any */
+ state->auth_ctx->running--;
+ imm = tevent_create_immediate(state->be_ctx->ev);
+ if (imm == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
+ /* We'll still finish the current request, but we're
+ * likely to have problems if there are queued events
+ * if we've gotten into this state.
+ * Hopefully this is impossible, since freeing req
+ * above should guarantee that we have enough memory
+ * to create this immediate event.
+ */
+ } else {
+ tevent_schedule_immediate(imm, state->be_ctx->ev,
+ run_proxy_child_queue,
+ state->auth_ctx);
+ }
+
+ /* Check if we need to save the cached credentials */
+ if ((state->pd->cmd == SSS_PAM_AUTHENTICATE || state->pd->cmd == SSS_PAM_CHAUTHTOK)
+ && (state->pd->pam_status == PAM_SUCCESS) && state->be_ctx->domain->cache_credentials) {
+
+ ret = sss_authtok_get_password(state->pd->authtok, &password, NULL);
+ if (ret) {
+ /* password caching failures are not fatal errors */
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password\n");
+ goto done;
+ }
+
+ ret = sysdb_cache_password(state->be_ctx->domain, state->pd->user, password);
+
+ /* password caching failures are not fatal errors */
+ /* so we just log it any return */
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password (%d)[%s]!?\n",
+ ret, sss_strerror(ret));
+ }
+ }
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+proxy_pam_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct proxy_pam_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct proxy_pam_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
+}
+
diff --git a/src/providers/proxy/proxy_client.c b/src/providers/proxy/proxy_client.c
new file mode 100644
index 000000000..fc1735f2a
--- /dev/null
+++ b/src/providers/proxy/proxy_client.c
@@ -0,0 +1,192 @@
+/*
+ SSSD
+
+ proxy_init.c
+
+ Authors:
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2010 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 "config.h"
+
+#include "util/sss_format.h"
+#include "providers/proxy/proxy.h"
+
+static int client_registration(struct sbus_request *dbus_req, void *data);
+
+static struct data_provider_iface proxy_methods = {
+ { &data_provider_iface_meta, 0 },
+ .RegisterService = client_registration,
+ .pamHandler = NULL,
+ .sudoHandler = NULL,
+ .autofsHandler = NULL,
+ .hostHandler = NULL,
+ .getDomains = NULL,
+ .getAccountInfo = NULL,
+};
+
+struct proxy_client {
+ struct proxy_auth_ctx *proxy_auth_ctx;
+ struct sbus_connection *conn;
+ struct tevent_timer *timeout;
+ bool initialized;
+};
+
+static int client_registration(struct sbus_request *dbus_req, void *data)
+{
+ dbus_uint16_t version = DATA_PROVIDER_VERSION;
+ struct sbus_connection *conn;
+ struct proxy_client *proxy_cli;
+ dbus_uint16_t cli_ver;
+ uint32_t cli_id;
+ int hret;
+ hash_key_t key;
+ hash_value_t value;
+ struct tevent_req *req;
+ struct proxy_child_ctx *child_ctx;
+ struct pc_init_ctx *init_ctx;
+ int ret;
+
+ conn = dbus_req->conn;
+ proxy_cli = talloc_get_type(data, struct proxy_client);
+ if (!proxy_cli) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
+ return EINVAL;
+ }
+
+ /* First thing, cancel the timeout */
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout);
+ talloc_zfree(proxy_cli->timeout);
+
+ if (!sbus_request_parse_or_finish(dbus_req,
+ DBUS_TYPE_UINT16, &cli_ver,
+ DBUS_TYPE_UINT32, &cli_id,
+ DBUS_TYPE_INVALID)) {
+ sbus_disconnect(conn);
+ return EOK; /* handled */
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id);
+
+ /* Check the hash table */
+ key.type = HASH_KEY_ULONG;
+ key.ul = cli_id;
+ if (!hash_has_key(proxy_cli->proxy_auth_ctx->request_table, &key)) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unknown child ID. Killing the connection\n");
+ sbus_disconnect(proxy_cli->conn);
+ return EIO;
+ }
+
+ /* reply that all is ok */
+ ret = sbus_request_return_and_finish(dbus_req,
+ DBUS_TYPE_UINT16, &version,
+ DBUS_TYPE_INVALID);
+ if (ret != EOK) {
+ sbus_disconnect(conn);
+ return ret;
+ }
+
+ hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
+ if (hret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Hash error [%d][%s]\n", hret, hash_error_string(hret));
+ sbus_disconnect(conn);
+ }
+
+ /* Signal that the child is up and ready to receive the request */
+ req = talloc_get_type(value.ptr, struct tevent_req);
+ child_ctx = tevent_req_data(req, struct proxy_child_ctx);
+
+ if (!child_ctx->running) {
+ /* This should hopefully be impossible, but protect
+ * against it anyway. If we're not marked running, then
+ * the init_req will be NULL below and things will
+ * break.
+ */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Client connection from a request "
+ "that's not marked as running\n");
+ return EIO;
+ }
+
+ init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);
+ init_ctx->conn = conn;
+ tevent_req_done(child_ctx->init_req);
+ child_ctx->init_req = NULL;
+
+ return EOK;
+}
+
+static void init_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *ptr)
+{
+ struct proxy_client *proxy_cli;
+
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Client timed out before Identification [%p]!\n", te);
+
+ proxy_cli = talloc_get_type(ptr, struct proxy_client);
+
+ sbus_disconnect(proxy_cli->conn);
+ talloc_zfree(proxy_cli);
+
+ /* If we time out here, we will also time out to
+ * pc_init_timeout(), so we'll finish the request
+ * there.
+ */
+}
+
+int proxy_client_init(struct sbus_connection *conn, void *data)
+{
+ struct proxy_auth_ctx *proxy_auth_ctx;
+ struct proxy_client *proxy_cli;
+ struct timeval tv;
+
+ proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
+
+ /* hang off this memory to the connection so that when the connection
+ * is freed we can potentially call a destructor */
+
+ proxy_cli = talloc_zero(conn, struct proxy_client);
+ if (!proxy_cli) {
+ DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
+ talloc_zfree(conn);
+ return ENOMEM;
+ }
+ proxy_cli->proxy_auth_ctx = proxy_auth_ctx;
+ proxy_cli->conn = conn;
+ proxy_cli->initialized = false;
+
+ /* 5 seconds should be plenty */
+ tv = tevent_timeval_current_ofs(5, 0);
+
+ proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,
+ tv, init_timeout, proxy_cli);
+ if (!proxy_cli->timeout) {
+ DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
+ talloc_zfree(conn);
+ return ENOMEM;
+ }
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout);
+
+ return sbus_conn_register_iface(conn, &proxy_methods.vtable,
+ DP_PATH, proxy_cli);
+}
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index f8b8cbdf2..c2150924b 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -1362,150 +1362,159 @@ static int get_initgr_groups_process(TALLOC_CTX *memctx,
/* =Proxy_Id-Functions====================================================*/
-void proxy_get_account_info(struct be_req *breq)
+static struct dp_reply_std
+proxy_account_info(TALLOC_CTX *mem_ctx,
+ struct proxy_id_ctx *ctx,
+ struct be_acct_req *data,
+ struct be_ctx *be_ctx,
+ struct sss_domain_info *domain)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
- struct be_acct_req *ar;
- struct proxy_id_ctx *ctx;
+ struct dp_reply_std reply;
struct sysdb_ctx *sysdb;
- struct sss_domain_info *domain;
uid_t uid;
gid_t gid;
- int ret;
+ errno_t ret;
char *endptr;
- ar = talloc_get_type(be_req_get_data(breq), struct be_acct_req);
- ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct proxy_id_ctx);
- sysdb = be_ctx->domain->sysdb;
- domain = be_ctx->domain;
-
- if (be_is_offline(be_ctx)) {
- return be_req_terminate(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
- }
+ sysdb = domain->sysdb;
- /* for now we support only core attrs */
- if (ar->attr_type != BE_ATTR_CORE) {
- return be_req_terminate(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
+ /* For now we support only core attrs. */
+ if (data->attr_type != BE_ATTR_CORE) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL, "Invalid attr type");
+ return reply;
}
- /* proxy provider does not support security ID lookups */
- if (ar->filter_type == BE_FILTER_SECID) {
- return be_req_terminate(breq, DP_ERR_FATAL, ENOSYS,
- "Invalid filter type");
+ /* Proxy provider does not support security ID lookups. */
+ if (data->filter_type == BE_FILTER_SECID) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENOSYS,
+ "Security lookups are not supported");
+ return reply;
}
- switch (ar->entry_type & BE_REQ_TYPE_MASK) {
+ switch (data->entry_type & BE_REQ_TYPE_MASK) {
case BE_REQ_USER: /* user */
- switch (ar->filter_type) {
+ switch (data->filter_type) {
case BE_FILTER_ENUM:
- ret = enum_users(breq, ctx, sysdb, domain);
+ ret = enum_users(mem_ctx, ctx, sysdb, domain);
break;
case BE_FILTER_NAME:
- ret = get_pw_name(ctx, domain, ar->filter_value);
+ ret = get_pw_name(ctx, domain, data->filter_value);
break;
case BE_FILTER_IDNUM:
- uid = (uid_t) strtouint32(ar->filter_value, &endptr, 10);
- if (errno || *endptr || (ar->filter_value == endptr)) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid attr type");
+ uid = (uid_t) strtouint32(data->filter_value, &endptr, 10);
+ if (errno || *endptr || (data->filter_value == endptr)) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid attr type");
+ return reply;
}
ret = get_pw_uid(ctx, domain, uid);
break;
default:
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
break;
case BE_REQ_GROUP: /* group */
- switch (ar->filter_type) {
+ switch (data->filter_type) {
case BE_FILTER_ENUM:
- ret = enum_groups(breq, ctx, sysdb, domain);
+ ret = enum_groups(mem_ctx, ctx, sysdb, domain);
break;
case BE_FILTER_NAME:
- ret = get_gr_name(ctx, sysdb, domain, ar->filter_value);
+ ret = get_gr_name(ctx, sysdb, domain, data->filter_value);
break;
case BE_FILTER_IDNUM:
- gid = (gid_t) strtouint32(ar->filter_value, &endptr, 10);
- if (errno || *endptr || (ar->filter_value == endptr)) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid attr type");
+ gid = (gid_t) strtouint32(data->filter_value, &endptr, 10);
+ if (errno || *endptr || (data->filter_value == endptr)) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid attr type");
+ return reply;
}
- ret = get_gr_gid(breq, ctx, sysdb, domain, gid, 0);
+ ret = get_gr_gid(mem_ctx, ctx, sysdb, domain, gid, 0);
break;
default:
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
break;
case BE_REQ_INITGROUPS: /* init groups for user */
- if (ar->filter_type != BE_FILTER_NAME) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
+ if (data->filter_type != BE_FILTER_NAME) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
if (ctx->ops.initgroups_dyn == NULL) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- ENODEV, "Initgroups call not supported");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
+ "Initgroups call not supported");
+ return reply;
}
- ret = get_initgr(breq, ctx, sysdb, domain, ar->filter_value);
+ ret = get_initgr(mem_ctx, ctx, sysdb, domain, data->filter_value);
break;
case BE_REQ_NETGROUP:
- if (ar->filter_type != BE_FILTER_NAME) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
+ if (data->filter_type != BE_FILTER_NAME) {
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
if (ctx->ops.setnetgrent == NULL || ctx->ops.getnetgrent_r == NULL ||
ctx->ops.endnetgrent == NULL) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- ENODEV, "Netgroups are not supported");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
+ "Netgroups are not supported");
+ return reply;
}
- ret = get_netgroup(ctx, domain, ar->filter_value);
+ ret = get_netgroup(ctx, domain, data->filter_value);
break;
case BE_REQ_SERVICES:
- switch (ar->filter_type) {
+ switch (data->filter_type) {
case BE_FILTER_NAME:
if (ctx->ops.getservbyname_r == NULL) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- ENODEV, "Services are not supported");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
+ "Services are not supported");
+ return reply;
}
ret = get_serv_byname(ctx, domain,
- ar->filter_value,
- ar->extra_value);
+ data->filter_value,
+ data->extra_value);
break;
case BE_FILTER_IDNUM:
if (ctx->ops.getservbyport_r == NULL) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- ENODEV, "Services are not supported");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
+ "Services are not supported");
+ return reply;
}
ret = get_serv_byport(ctx, domain,
- ar->filter_value,
- ar->extra_value);
+ data->filter_value,
+ data->extra_value);
break;
case BE_FILTER_ENUM:
if (!ctx->ops.setservent
|| !ctx->ops.getservent_r
|| !ctx->ops.endservent) {
- return be_req_terminate(breq, DP_ERR_FATAL,
- ENODEV, "Services are not supported");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ENODEV,
+ "Services are not supported");
+ return reply;
}
ret = enum_services(ctx, sysdb, domain);
break;
default:
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid filter type");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
break;
default: /*fail*/
- return be_req_terminate(breq, DP_ERR_FATAL,
- EINVAL, "Invalid request type");
+ dp_reply_std_set(&reply, DP_ERR_FATAL, EINVAL,
+ "Invalid filter type");
+ return reply;
}
if (ret) {
@@ -1514,8 +1523,56 @@ void proxy_get_account_info(struct be_req *breq)
"proxy returned UNAVAIL error, going offline!\n");
be_mark_offline(be_ctx);
}
- be_req_terminate(breq, DP_ERR_FATAL, ret, NULL);
- return;
+
+ dp_reply_std_set(&reply, DP_ERR_FATAL, ret, NULL);
+ return reply;
+ }
+
+ dp_reply_std_set(&reply, DP_ERR_OK, EOK, NULL);
+ return reply;
+}
+
+struct proxy_account_info_handler_state {
+ struct dp_reply_std reply;
+};
+
+struct tevent_req *
+proxy_account_info_handler_send(TALLOC_CTX *mem_ctx,
+ struct proxy_id_ctx *id_ctx,
+ struct be_acct_req *data,
+ struct dp_req_params *params)
+{
+ struct proxy_account_info_handler_state *state;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct proxy_account_info_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- be_req_terminate(breq, DP_ERR_OK, EOK, NULL);
+
+ state->reply = proxy_account_info(state, id_ctx, data, params->be_ctx,
+ params->be_ctx->domain);
+
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+ tevent_req_post(req, params->ev);
+
+ return req;
+}
+
+errno_t proxy_account_info_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
+{
+ struct proxy_account_info_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct proxy_account_info_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
+
+ return EOK;
}
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 0a6b11d4a..3a4cee91e 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -27,60 +27,26 @@
#include "util/sss_format.h"
#include "providers/proxy/proxy.h"
-static int client_registration(struct sbus_request *dbus_req, void *data);
-
-static struct data_provider_iface proxy_methods = {
- { &data_provider_iface_meta, 0 },
- .RegisterService = client_registration,
- .pamHandler = NULL,
- .sudoHandler = NULL,
- .autofsHandler = NULL,
- .hostHandler = NULL,
- .getDomains = NULL,
- .getAccountInfo = NULL,
-};
-
-static void proxy_shutdown(struct be_req *req)
-{
- /* TODO: Clean up any internal data */
- be_req_terminate(req, DP_ERR_OK, EOK, NULL);
-}
-
-static void proxy_auth_shutdown(struct be_req *req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(req);
- talloc_free(be_ctx->bet_info[BET_AUTH].pvt_bet_data);
- be_req_terminate(req, DP_ERR_OK, EOK, NULL);
-}
-
-struct bet_ops proxy_id_ops = {
- .handler = proxy_get_account_info,
- .finalize = proxy_shutdown,
- .check_online = NULL
-};
-
-struct bet_ops proxy_auth_ops = {
- .handler = proxy_pam_handler,
- .finalize = proxy_auth_shutdown
-};
-
-struct bet_ops proxy_access_ops = {
- .handler = proxy_pam_handler,
- .finalize = proxy_auth_shutdown
-};
-
-struct bet_ops proxy_chpass_ops = {
- .handler = proxy_pam_handler,
- .finalize = proxy_auth_shutdown
-};
-
-static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
+#define NSS_FN_NAME "_nss_%s_%s"
+
+#define ERROR_INITGR "The '%s' library does not provides the " \
+ "_nss_XXX_initgroups_dyn function!\n" \
+ "initgroups will be slow as it will require " \
+ "full groups enumeration!\n"
+#define ERROR_NETGR "The '%s' library does not support netgroups.\n"
+#define ERROR_SERV "The '%s' library does not support services.\n"
+
+static void *proxy_dlsym(void *handle,
+ const char *name,
+ const char *libname)
{
char *funcname;
void *funcptr;
- funcname = talloc_asprintf(NULL, functemp, libname);
- if (funcname == NULL) return NULL;
+ funcname = talloc_asprintf(NULL, NSS_FN_NAME, libname, name);
+ if (funcname == NULL) {
+ return NULL;
+ }
funcptr = dlsym(handle, funcname);
talloc_free(funcname);
@@ -88,476 +54,331 @@ static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
return funcptr;
}
-int sssm_proxy_id_init(struct be_ctx *bectx,
- struct bet_ops **ops, void **pvt_data)
+static errno_t proxy_id_conf(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ char **_libname,
+ char **_libpath,
+ bool *_fast_alias)
{
- struct proxy_id_ctx *ctx;
+ TALLOC_CTX *tmp_ctx;
char *libname;
char *libpath;
- int ret;
+ bool fast_alias;
+ errno_t ret;
- ctx = talloc_zero(bectx, struct proxy_id_ctx);
- if (!ctx) {
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
return ENOMEM;
}
- ctx->be = bectx;
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
+ ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
CONFDB_PROXY_LIBNAME, NULL, &libname);
- if (ret != EOK) goto done;
- if (libname == NULL) {
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ } else if (libname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No library name given\n");
ret = ENOENT;
goto done;
}
- ret = confdb_get_bool(bectx->cdb, bectx->conf_path,
- CONFDB_PROXY_FAST_ALIAS, false, &ctx->fast_alias);
- if (ret != EOK) goto done;
-
- libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname);
- if (!libpath) {
- ret = ENOMEM;
+ ret = confdb_get_bool(be_ctx->cdb, be_ctx->conf_path,
+ CONFDB_PROXY_FAST_ALIAS, false, &fast_alias);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- ctx->handle = dlopen(libpath, RTLD_NOW);
- if (!ctx->handle) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Unable to load %s module with path, error: %s\n",
- libpath, dlerror());
- ret = ELIBACC;
+ libpath = talloc_asprintf(tmp_ctx, "libnss_%s.so.2", libname);
+ if (libpath == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+ ret = ENOMEM;
goto done;
}
- ctx->ops.getpwnam_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwnam_r",
- libname);
- if (!ctx->ops.getpwnam_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+ *_libname = talloc_steal(mem_ctx, libname);
+ *_libpath = talloc_steal(mem_ctx, libpath);
+ *_fast_alias = fast_alias;
- ctx->ops.getpwuid_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwuid_r",
- libname);
- if (!ctx->ops.getpwuid_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+ ret = EOK;
- ctx->ops.setpwent = proxy_dlsym(ctx->handle, "_nss_%s_setpwent", libname);
- if (!ctx->ops.setpwent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+done:
+ talloc_free(tmp_ctx);
- ctx->ops.getpwent_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwent_r",
- libname);
- if (!ctx->ops.getpwent_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+ return ret;
+}
- ctx->ops.endpwent = proxy_dlsym(ctx->handle, "_nss_%s_endpwent", libname);
- if (!ctx->ops.endpwent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
+static errno_t proxy_id_load_symbols(struct proxy_nss_ops *ops,
+ const char *libname,
+ void *handle)
+{
+ int i;
+ struct {void **dest;
+ const char *name;
+ const char *custom_error;
+ bool is_fatal;
+ } symbols[] = {
+ {(void**)&ops->getpwnam_r, "getpwnam_r", NULL, true},
+ {(void**)&ops->getpwuid_r, "getpwuid_r", NULL, true},
+ {(void**)&ops->setpwent, "setpwent", NULL, true},
+ {(void**)&ops->getpwent_r, "getpwent_r", NULL, true},
+ {(void**)&ops->endpwent, "endpwent", NULL, true},
+ {(void**)&ops->getgrnam_r, "getgrnam_r", NULL, true},
+ {(void**)&ops->getgrgid_r, "getgrgid_r", NULL, true},
+ {(void**)&ops->setgrent, "setgrent", NULL, true},
+ {(void**)&ops->getgrent_r, "getgrent_r", NULL, true},
+ {(void**)&ops->endgrent, "endgrent", NULL, true},
+ {(void**)&ops->initgroups_dyn, "initgroups_dyn", ERROR_INITGR, false},
+ {(void**)&ops->setnetgrent, "setnetgrent", ERROR_NETGR, false},
+ {(void**)&ops->getnetgrent_r, "getnetgrent_r", ERROR_NETGR, false},
+ {(void**)&ops->endnetgrent, "endnetgrent", ERROR_NETGR, false},
+ {(void**)&ops->getservbyname_r, "getservbyname_r", ERROR_SERV, false},
+ {(void**)&ops->getservbyport_r, "getservbyport_r", ERROR_SERV, false},
+ {(void**)&ops->setservent, "setservent", ERROR_SERV, false},
+ {(void**)&ops->getservent_r, "getservent_r", ERROR_SERV, false},
+ {(void**)&ops->endservent, "endservent", ERROR_SERV, false},
+ {NULL, NULL, NULL, false}
+ };
+
+ for (i = 0; symbols[i].dest != NULL; i++) {
+ *symbols[i].dest = proxy_dlsym(handle, symbols[i].name, libname);
+ if (*symbols[i].dest == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load _nss_%s_%s, "
+ "error: %s.\n", libname, symbols[i].name, dlerror());
+
+ if (symbols[i].custom_error != NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, symbols[i].custom_error, libname);
+ }
+
+ if (symbols[i].is_fatal) {
+ return ELIBBAD;
+ }
+ }
}
- ctx->ops.getgrnam_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrnam_r",
- libname);
- if (!ctx->ops.getgrnam_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+ return EOK;
+}
- ctx->ops.getgrgid_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrgid_r",
- libname);
- if (!ctx->ops.getgrgid_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+static errno_t proxy_setup_sbus(TALLOC_CTX *mem_ctx,
+ struct proxy_auth_ctx *ctx,
+ struct be_ctx *be_ctx)
+{
+ char *sbus_address;
+ errno_t ret;
- ctx->ops.setgrent = proxy_dlsym(ctx->handle, "_nss_%s_setgrent", libname);
- if (!ctx->ops.setgrent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
+ sbus_address = talloc_asprintf(mem_ctx, "unix:path=%s/%s_%s", PIPE_PATH,
+ PROXY_CHILD_PIPE, be_ctx->domain->name);
+ if (sbus_address == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed.\n");
+ return ENOMEM;
}
- ctx->ops.getgrent_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrent_r",
- libname);
- if (!ctx->ops.getgrent_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
+ ret = sbus_new_server(mem_ctx, be_ctx->ev, sbus_address, 0, be_ctx->gid,
+ false, &ctx->sbus_srv, proxy_client_init, ctx);
+ talloc_free(sbus_address);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
+ return ret;
}
- ctx->ops.endgrent = proxy_dlsym(ctx->handle, "_nss_%s_endgrent", libname);
- if (!ctx->ops.endgrent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load NSS fns, error: %s\n", dlerror());
- ret = ELIBBAD;
- goto done;
- }
+ return EOK;
+}
- ctx->ops.initgroups_dyn = proxy_dlsym(ctx->handle, "_nss_%s_initgroups_dyn",
- libname);
- if (!ctx->ops.initgroups_dyn) {
- DEBUG(SSSDBG_CRIT_FAILURE, "The '%s' library does not provides the "
- "_nss_XXX_initgroups_dyn function!\n"
- "initgroups will be slow as it will require "
- "full groups enumeration!\n", libname);
- }
+static errno_t proxy_auth_conf(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ char **_pam_target)
+{
+ char *pam_target;
+ errno_t ret;
- ctx->ops.setnetgrent = proxy_dlsym(ctx->handle, "_nss_%s_setnetgrent",
- libname);
- if (!ctx->ops.setnetgrent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load _nss_%s_setnetgrent, error: %s. "
- "The library does not support netgroups.\n", libname,
- dlerror());
+ ret = confdb_get_string(be_ctx->cdb, mem_ctx, be_ctx->conf_path,
+ CONFDB_PROXY_PAM_TARGET, NULL, &pam_target);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read confdb [%d]: %s\n",
+ ret, sss_strerror(ret));
+ return ret;
}
- ctx->ops.getnetgrent_r = proxy_dlsym(ctx->handle, "_nss_%s_getnetgrent_r",
- libname);
- if (!ctx->ops.getgrent_r) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load _nss_%s_getnetgrent_r, error: %s. "
- "The library does not support netgroups.\n", libname,
- dlerror());
+ if (pam_target == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing option %s.\n",
+ CONFDB_PROXY_PAM_TARGET);
+ return EINVAL;
}
- ctx->ops.endnetgrent = proxy_dlsym(ctx->handle, "_nss_%s_endnetgrent",
- libname);
- if (!ctx->ops.endnetgrent) {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Failed to load _nss_%s_endnetgrent, error: %s. "
- "The library does not support netgroups.\n", libname,
- dlerror());
- }
+ *_pam_target = pam_target;
- ctx->ops.getservbyname_r = proxy_dlsym(ctx->handle,
- "_nss_%s_getservbyname_r",
- libname);
- if (!ctx->ops.getservbyname_r) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to load _nss_%s_getservbyname_r, error: %s. "
- "The library does not support services.\n",
- libname,
- dlerror());
- }
+ return EOK;
+}
- ctx->ops.getservbyport_r = proxy_dlsym(ctx->handle,
- "_nss_%s_getservbyport_r",
- libname);
- if (!ctx->ops.getservbyport_r) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to load _nss_%s_getservbyport_r, error: %s. "
- "The library does not support services.\n",
- libname,
- dlerror());
- }
+static errno_t proxy_init_auth_ctx(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct proxy_auth_ctx **_auth_ctx)
+{
+ struct proxy_auth_ctx *auth_ctx;
+ errno_t ret;
+ int hret;
- ctx->ops.setservent = proxy_dlsym(ctx->handle,
- "_nss_%s_setservent",
- libname);
- if (!ctx->ops.setservent) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to load _nss_%s_setservent, error: %s. "
- "The library does not support services.\n",
- libname,
- dlerror());
+ auth_ctx = talloc_zero(mem_ctx, struct proxy_auth_ctx);
+ if (auth_ctx == NULL) {
+ return ENOMEM;
}
- ctx->ops.getservent_r = proxy_dlsym(ctx->handle,
- "_nss_%s_getservent_r",
- libname);
- if (!ctx->ops.getservent_r) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to load _nss_%s_getservent_r, error: %s. "
- "The library does not support services.\n",
- libname,
- dlerror());
- }
+ auth_ctx->be = be_ctx;
+ auth_ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT / 4;
+ auth_ctx->next_id = 1;
- ctx->ops.endservent = proxy_dlsym(ctx->handle,
- "_nss_%s_endservent",
- libname);
- if (!ctx->ops.endservent) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Failed to load _nss_%s_endservent, error: %s. "
- "The library does not support services.\n",
- libname,
- dlerror());
+ ret = proxy_auth_conf(auth_ctx, be_ctx, &auth_ctx->pam_target);
+ if (ret != EOK) {
+ goto done;
}
- *ops = &proxy_id_ops;
- *pvt_data = ctx;
- ret = EOK;
-
-done:
+ ret = proxy_setup_sbus(auth_ctx, auth_ctx, be_ctx);
if (ret != EOK) {
- talloc_free(ctx);
+ goto done;
}
- return ret;
-}
-
-struct proxy_client {
- struct proxy_auth_ctx *proxy_auth_ctx;
- struct sbus_connection *conn;
- struct tevent_timer *timeout;
- bool initialized;
-};
-
-static void init_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *ptr);
-static int proxy_client_init(struct sbus_connection *conn, void *data)
-{
- struct proxy_auth_ctx *proxy_auth_ctx;
- struct proxy_client *proxy_cli;
- struct timeval tv;
- proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
-
- /* hang off this memory to the connection so that when the connection
- * is freed we can potentially call a destructor */
+ /* Set up request hash table */
+ /* FIXME: get max_children from configuration file */
+ auth_ctx->max_children = 10;
- proxy_cli = talloc_zero(conn, struct proxy_client);
- if (!proxy_cli) {
- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
- talloc_zfree(conn);
- return ENOMEM;
- }
- proxy_cli->proxy_auth_ctx = proxy_auth_ctx;
- proxy_cli->conn = conn;
- proxy_cli->initialized = false;
-
- /* 5 seconds should be plenty */
- tv = tevent_timeval_current_ofs(5, 0);
-
- proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,
- tv, init_timeout, proxy_cli);
- if (!proxy_cli->timeout) {
- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
- talloc_zfree(conn);
- return ENOMEM;
+ hret = hash_create(auth_ctx->max_children * 2, &auth_ctx->request_table,
+ NULL, NULL);
+ if (hret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize request table\n");
+ ret = EIO;
+ goto done;
}
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout);
- return sbus_conn_register_iface(conn, &proxy_methods.vtable,
- DP_PATH, proxy_cli);
-}
+ *_auth_ctx = auth_ctx;
-static void init_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *ptr)
-{
- struct proxy_client *proxy_cli;
-
- DEBUG(SSSDBG_OP_FAILURE,
- "Client timed out before Identification [%p]!\n", te);
-
- proxy_cli = talloc_get_type(ptr, struct proxy_client);
+ ret = EOK;
- sbus_disconnect(proxy_cli->conn);
- talloc_zfree(proxy_cli);
+done:
+ if (ret != EOK) {
+ talloc_free(auth_ctx);
+ }
- /* If we time out here, we will also time out to
- * pc_init_timeout(), so we'll finish the request
- * there.
- */
+ return ret;
}
-static int client_registration(struct sbus_request *dbus_req, void *data)
+errno_t sssm_proxy_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct data_provider *provider,
+ const char *module_name,
+ void **_module_data)
{
- dbus_uint16_t version = DATA_PROVIDER_VERSION;
- struct sbus_connection *conn;
- struct proxy_client *proxy_cli;
- dbus_uint16_t cli_ver;
- uint32_t cli_id;
- int hret;
- hash_key_t key;
- hash_value_t value;
- struct tevent_req *req;
- struct proxy_child_ctx *child_ctx;
- struct pc_init_ctx *init_ctx;
- int ret;
-
- conn = dbus_req->conn;
- proxy_cli = talloc_get_type(data, struct proxy_client);
- if (!proxy_cli) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
- return EINVAL;
- }
+ struct proxy_auth_ctx *auth_ctx;
+ errno_t ret;
- /* First thing, cancel the timeout */
- DEBUG(SSSDBG_CONF_SETTINGS,
- "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout);
- talloc_zfree(proxy_cli->timeout);
-
- if (!sbus_request_parse_or_finish(dbus_req,
- DBUS_TYPE_UINT16, &cli_ver,
- DBUS_TYPE_UINT32, &cli_id,
- DBUS_TYPE_INVALID)) {
- sbus_disconnect(conn);
- return EOK; /* handled */
+ if (!dp_target_enabled(provider, module_name,
+ DPT_ACCESS, DPT_AUTH, DPT_CHPASS)) {
+ return EOK;
}
- DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id);
-
- /* Check the hash table */
- key.type = HASH_KEY_ULONG;
- key.ul = cli_id;
- if (!hash_has_key(proxy_cli->proxy_auth_ctx->request_table, &key)) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Unknown child ID. Killing the connection\n");
- sbus_disconnect(proxy_cli->conn);
- return EIO;
- }
+ /* Initialize auth_ctx since one of the access, auth or chpass is set. */
- /* reply that all is ok */
- ret = sbus_request_return_and_finish(dbus_req,
- DBUS_TYPE_UINT16, &version,
- DBUS_TYPE_INVALID);
+ ret = proxy_init_auth_ctx(mem_ctx, be_ctx, &auth_ctx);
if (ret != EOK) {
- sbus_disconnect(conn);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create auth context [%d]: %s\n",
+ ret, sss_strerror(ret));
return ret;
}
- hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
- if (hret != HASH_SUCCESS) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Hash error [%d][%s]\n", hret, hash_error_string(hret));
- sbus_disconnect(conn);
- }
-
- /* Signal that the child is up and ready to receive the request */
- req = talloc_get_type(value.ptr, struct tevent_req);
- child_ctx = tevent_req_data(req, struct proxy_child_ctx);
-
- if (!child_ctx->running) {
- /* This should hopefully be impossible, but protect
- * against it anyway. If we're not marked running, then
- * the init_req will be NULL below and things will
- * break.
- */
- DEBUG(SSSDBG_CRIT_FAILURE, "Client connection from a request "
- "that's not marked as running\n");
- return EIO;
- }
-
- init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);
- init_ctx->conn = conn;
- tevent_req_done(child_ctx->init_req);
- child_ctx->init_req = NULL;
+ *_module_data = auth_ctx;
return EOK;
}
-int sssm_proxy_auth_init(struct be_ctx *bectx,
- struct bet_ops **ops, void **pvt_data)
+errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- struct proxy_auth_ctx *ctx;
- int ret;
- int hret;
- char *sbus_address;
-
- /* If we're already set up, just return that */
- if(bectx->bet_info[BET_AUTH].mod_name &&
- strcmp("proxy", bectx->bet_info[BET_AUTH].mod_name) == 0) {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "Re-using proxy_auth_ctx for this provider\n");
- *ops = bectx->bet_info[BET_AUTH].bet_ops;
- *pvt_data = bectx->bet_info[BET_AUTH].pvt_bet_data;
- return EOK;
- }
+ struct proxy_id_ctx *ctx;
+ char *libname;
+ char *libpath;
+ errno_t ret;
- ctx = talloc_zero(bectx, struct proxy_auth_ctx);
- if (!ctx) {
+ ctx = talloc_zero(mem_ctx, struct proxy_id_ctx);
+ if (ctx == NULL) {
return ENOMEM;
}
- ctx->be = bectx;
- ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT/4;
- ctx->next_id = 1;
-
- ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
- CONFDB_PROXY_PAM_TARGET, NULL,
- &ctx->pam_target);
- if (ret != EOK) goto done;
- if (!ctx->pam_target) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Missing option proxy_pam_target.\n");
- ret = EINVAL;
+
+ ctx->be = be_ctx;
+
+ ret = proxy_id_conf(ctx, be_ctx, &libname, &libpath, &ctx->fast_alias);
+ if (ret != EOK) {
goto done;
}
- sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s", PIPE_PATH,
- PROXY_CHILD_PIPE, bectx->domain->name);
- if (sbus_address == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
- ret = ENOMEM;
+ ctx->handle = dlopen(libpath, RTLD_NOW);
+ if (ctx->handle == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load %s module, "
+ "error: %s\n", libpath, dlerror());
+ ret = ELIBACC;
goto done;
}
- ret = sbus_new_server(ctx, bectx->ev, sbus_address, 0, bectx->gid,
- false, &ctx->sbus_srv, proxy_client_init, ctx);
+ ret = proxy_id_load_symbols(&ctx->ops, libname, ctx->handle);
if (ret != EOK) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load NSS symbols [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- /* Set up request hash table */
- /* FIXME: get max_children from configuration file */
- ctx->max_children = 10;
+ dp_set_method(dp_methods, DPM_ACCOUNT_HANDLER,
+ proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx,
+ struct proxy_id_ctx, struct be_acct_req, struct dp_reply_std);
- hret = hash_create(ctx->max_children * 2, &ctx->request_table,
- NULL, NULL);
- if (hret != HASH_SUCCESS) {
- DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize request table\n");
- ret = EIO;
- goto done;
- }
-
- *ops = &proxy_auth_ops;
- *pvt_data = ctx;
+ ret = EOK;
done:
if (ret != EOK) {
talloc_free(ctx);
}
+
return ret;
}
-int sssm_proxy_access_init(struct be_ctx *bectx,
- struct bet_ops **ops, void **pvt_data)
+errno_t sssm_proxy_auth_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
- *ops = &proxy_access_ops;
- return ret;
+ struct proxy_auth_ctx *auth_ctx;
+
+ auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx);
+
+ dp_set_method(dp_methods, DPM_AUTH_HANDLER,
+ proxy_pam_handler_send, proxy_pam_handler_recv, auth_ctx,
+ struct proxy_auth_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
}
-int sssm_proxy_chpass_init(struct be_ctx *bectx,
- struct bet_ops **ops, void **pvt_data)
+errno_t sssm_proxy_chpass_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret;
- ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
- *ops = &proxy_chpass_ops;
- return ret;
+ return sssm_proxy_auth_init(mem_ctx, be_ctx, module_data, dp_methods);
+}
+
+errno_t sssm_proxy_access_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
+{
+ struct proxy_auth_ctx *auth_ctx;
+
+ auth_ctx = talloc_get_type(module_data, struct proxy_auth_ctx);
+
+ dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+ proxy_pam_handler_send, proxy_pam_handler_recv, auth_ctx,
+ struct proxy_auth_ctx, struct pam_data, struct pam_data *);
+
+ return EOK;
}
diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
index d4fa615f2..ca6d49db4 100644
--- a/src/providers/simple/simple_access.c
+++ b/src/providers/simple/simple_access.c
@@ -34,13 +34,80 @@
#define TIMEOUT_OF_REFRESH_FILTER_LISTS 5
-static void simple_access_check(struct tevent_req *req);
static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx,
struct be_ctx *be_ctx,
char **list,
- char ***_out);
+ char ***_out)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char **out = NULL;
+ char *domain = NULL;
+ char *name = NULL;
+ size_t size;
+ size_t i;
+ errno_t ret;
+
+ if (list == NULL) {
+ *_out = NULL;
+ return EOK;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (size = 0; list[size] != NULL; size++) {
+ /* count size */
+ }
+
+ out = talloc_zero_array(tmp_ctx, char*, size + 1);
+ if (out == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Since this is access provider, we should fail on any error so we don't
+ * allow unauthorized access. */
+ for (i = 0; i < size; i++) {
+ ret = sss_parse_name(tmp_ctx, be_ctx->domain->names, list[i],
+ &domain, &name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
+ list[i], ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0 ||
+ (be_ctx->domain->flat_name != NULL &&
+ strcasecmp(domain, be_ctx->domain->flat_name) == 0)) {
+ /* This object belongs to main SSSD domain. Those users and groups
+ * are stored without domain part, so we will strip it off.
+ * */
+ out[i] = talloc_move(out, &name);
+ } else {
+ /* Subdomain users and groups are stored as fully qualified names,
+ * thus we will remember the domain part.
+ *
+ * Since subdomains may come and go, we will look for their
+ * existence later, during each access check.
+ */
+ out[i] = talloc_move(out, &list[i]);
+ }
+ }
+
+ *_out = talloc_steal(mem_ctx, out);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
-static int simple_access_obtain_filter_lists(struct simple_ctx *ctx)
+int simple_access_obtain_filter_lists(struct simple_ctx *ctx)
{
struct be_ctx *bectx = ctx->be_ctx;
int ret;
@@ -103,185 +170,141 @@ failed:
return ret;
}
-void simple_access_handler(struct be_req *be_req)
-{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
+struct simple_access_handler_state {
struct pam_data *pd;
+};
+
+static void simple_access_handler_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+simple_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct simple_ctx *simple_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
+{
+ struct simple_access_handler_state *state;
+ struct tevent_req *subreq;
struct tevent_req *req;
- struct simple_ctx *ctx;
- int ret;
+ errno_t ret;
time_t now;
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
+ req = tevent_req_create(mem_ctx, &state,
+ struct simple_access_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
- pd->pam_status = PAM_SYSTEM_ERR;
+ state->pd = pd;
+ pd->pam_status = PAM_SYSTEM_ERR;
if (pd->cmd != SSS_PAM_ACCT_MGMT) {
DEBUG(SSSDBG_CONF_SETTINGS,
"simple access does not handle pam task %d.\n", pd->cmd);
pd->pam_status = PAM_MODULE_UNKNOWN;
- goto done;
+ goto immediately;
}
- ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
- struct simple_ctx);
-
-
now = time(NULL);
- if ((now - ctx->last_refresh_of_filter_lists)
+ if ((now - simple_ctx->last_refresh_of_filter_lists)
> TIMEOUT_OF_REFRESH_FILTER_LISTS) {
- ret = simple_access_obtain_filter_lists(ctx);
+ ret = simple_access_obtain_filter_lists(simple_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Failed to refresh filter lists\n");
}
- ctx->last_refresh_of_filter_lists = now;
+ simple_ctx->last_refresh_of_filter_lists = now;
}
- req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user);
- if (!req) {
+ subreq = simple_access_check_send(state, params->ev, simple_ctx, pd->user);
+ if (subreq == NULL) {
pd->pam_status = PAM_SYSTEM_ERR;
- goto done;
+ goto immediately;
}
- tevent_req_set_callback(req, simple_access_check, be_req);
- return;
-done:
- be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
+ tevent_req_set_callback(subreq, simple_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);
+
+ return req;
}
-static void simple_access_check(struct tevent_req *req)
+static void simple_access_handler_done(struct tevent_req *subreq)
{
- bool access_granted = false;
+ struct simple_access_handler_state *state;
+ struct tevent_req *req;
+ bool access_granted;
errno_t ret;
- struct pam_data *pd;
- struct be_req *be_req;
- be_req = tevent_req_callback_data(req, struct be_req);
- pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct simple_access_handler_state);
- ret = simple_access_check_recv(req, &access_granted);
- talloc_free(req);
+ ret = simple_access_check_recv(subreq, &access_granted);
+ talloc_free(subreq);
if (ret != EOK) {
- pd->pam_status = PAM_SYSTEM_ERR;
+ state->pd->pam_status = PAM_SYSTEM_ERR;
goto done;
}
if (access_granted) {
- pd->pam_status = PAM_SUCCESS;
+ state->pd->pam_status = PAM_SUCCESS;
} else {
- pd->pam_status = PAM_PERM_DENIED;
+ state->pd->pam_status = PAM_PERM_DENIED;
}
done:
- be_req_terminate(be_req, DP_ERR_OK, pd->pam_status, NULL);
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
}
-static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx,
- struct be_ctx *be_ctx,
- char **list,
- char ***_out)
+static errno_t
+simple_access_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
{
- TALLOC_CTX *tmp_ctx = NULL;
- char **out = NULL;
- char *domain = NULL;
- char *name = NULL;
- size_t size;
- size_t i;
- errno_t ret;
-
- if (list == NULL) {
- *_out = NULL;
- return EOK;
- }
+ struct simple_access_handler_state *state = NULL;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
- ret = ENOMEM;
- goto done;
- }
+ state = tevent_req_data(req, struct simple_access_handler_state);
- for (size = 0; list[size] != NULL; size++) {
- /* count size */
- }
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- out = talloc_zero_array(tmp_ctx, char*, size + 1);
- if (out == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
- ret = ENOMEM;
- goto done;
- }
+ *_data = talloc_steal(mem_ctx, state->pd);
- /* Since this is access provider, we should fail on any error so we don't
- * allow unauthorized access. */
- for (i = 0; i < size; i++) {
- ret = sss_parse_name(tmp_ctx, be_ctx->domain->names, list[i],
- &domain, &name);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
- list[i], ret, sss_strerror(ret));
- goto done;
- }
-
- if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0 ||
- (be_ctx->domain->flat_name != NULL &&
- strcasecmp(domain, be_ctx->domain->flat_name) == 0)) {
- /* This object belongs to main SSSD domain. Those users and groups
- * are stored without domain part, so we will strip it off.
- * */
- out[i] = talloc_move(out, &name);
- } else {
- /* Subdomain users and groups are stored as fully qualified names,
- * thus we will remember the domain part.
- *
- * Since subdomains may come and go, we will look for their
- * existence later, during each access check.
- */
- out[i] = talloc_move(out, &list[i]);
- }
- }
-
- *_out = talloc_steal(mem_ctx, out);
- ret = EOK;
-
-done:
- talloc_free(tmp_ctx);
- return ret;
+ return EOK;
}
-struct bet_ops simple_access_ops = {
- .handler = simple_access_handler,
- .finalize = NULL
-};
-
-int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
- void **pvt_data)
+errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ void *module_data,
+ struct dp_method *dp_methods)
{
- int ret = EINVAL;
struct simple_ctx *ctx;
- ctx = talloc_zero(bectx, struct simple_ctx);
+ errno_t ret;
+
+ ctx = talloc_zero(mem_ctx, struct simple_ctx);
if (ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed.\n");
return ENOMEM;
}
- ctx->domain = bectx->domain;
- ctx->be_ctx = bectx;
+ ctx->domain = be_ctx->domain;
+ ctx->be_ctx = be_ctx;
ctx->last_refresh_of_filter_lists = 0;
ret = simple_access_obtain_filter_lists(ctx);
if (ret != EOK) {
- goto failed;
+ talloc_free(ctx);
+ return ret;
}
- *ops = &simple_access_ops;
- *pvt_data = ctx;
+ dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
+ simple_access_handler_send, simple_access_handler_recv, ctx,
+ struct simple_ctx, struct pam_data, struct pam_data *);
return EOK;
-
-failed:
- talloc_free(ctx);
- return ret;
}
-
diff --git a/src/providers/simple/simple_access_check.c b/src/providers/simple/simple_access_check.c
index 3b7c2fe93..094ed364a 100644
--- a/src/providers/simple/simple_access_check.c
+++ b/src/providers/simple/simple_access_check.c
@@ -268,7 +268,9 @@ simple_resolve_group_send(TALLOC_CTX *mem_ctx,
goto done;
}
- subreq = be_get_account_info_send(state, ev, NULL, ctx->be_ctx, ar);
+ subreq = dp_req_send(state, ctx->be_ctx->provider, NULL, ar->domain,
+ "Simple Resolve Group", DPT_ID, DPM_ACCOUNT_HANDLER,
+ 0, ar, NULL);
if (!subreq) {
ret = ENOMEM;
goto done;
@@ -328,27 +330,24 @@ static void simple_resolve_group_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct simple_resolve_group_state *state;
- int err_maj;
- int err_min;
+ struct dp_reply_std *reply;
errno_t ret;
- const char *err_msg;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct simple_resolve_group_state);
- ret = be_get_account_info_recv(subreq, state,
- &err_maj, &err_min, &err_msg);
+ ret = dp_req_recv_ptr(state, subreq, struct dp_reply_std, &reply);
talloc_zfree(subreq);
if (ret) {
- DEBUG(SSSDBG_OP_FAILURE, "be_get_account_info_recv failed\n");
+ DEBUG(SSSDBG_OP_FAILURE, "dp_req_recv failed\n");
tevent_req_error(req, ret);
return;
}
- if (err_maj) {
+ if (reply->dp_error != DP_ERR_OK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Cannot refresh data from DP: %u,%u: %s\n",
- err_maj, err_min, err_msg);
+ reply->dp_error, reply->error, reply->message);
tevent_req_error(req, EIO);
return;
}