diff options
Diffstat (limited to 'src/providers/data_provider_be.c')
-rw-r--r-- | src/providers/data_provider_be.c | 2464 |
1 files changed, 110 insertions, 2354 deletions
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; } |