/* Authors: Pavel Březina Stephen Gallagher Simo Sorce Copyright (C) 2017 Red Hat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "util/util.h" #include "sbus/connection/sbus_dbus_private.h" #include "sbus/sbus_private.h" #include "sbus/interface_dbus/sbus_dbus_client_async.h" struct sbus_connect_init_state { struct sbus_connection *conn; const char *name; }; static void sbus_connect_init_hello_done(struct tevent_req *subreq); static void sbus_connect_init_done(struct tevent_req *subreq); struct tevent_req * sbus_connect_init_send(TALLOC_CTX *mem_ctx, struct sbus_connection *conn, const char *name) { struct sbus_connect_init_state *state; struct tevent_req *subreq; struct tevent_req *req; req = tevent_req_create(mem_ctx, &state, struct sbus_connect_init_state); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); return NULL; } state->conn = conn; state->name = name; subreq = sbus_call_DBus_Hello_send(state, conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); tevent_req_error(req, ENOMEM); tevent_req_post(req, conn->ev); return req; } tevent_req_set_callback(subreq, sbus_connect_init_hello_done, req); arm_watchdog(); return req; } static void sbus_connect_init_hello_done(struct tevent_req *subreq) { struct sbus_connect_init_state *state; const char *unique_name; struct tevent_req *req; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sbus_connect_init_state); ret = sbus_call_DBus_Hello_recv(state, subreq, &unique_name); talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); return; } if (state->name == NULL) { tevent_req_done(req); return; } subreq = sbus_call_DBus_RequestName_send(state, state->conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, state->name, DBUS_NAME_FLAG_DO_NOT_QUEUE); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); tevent_req_error(req, ENOMEM); return; } tevent_req_set_callback(subreq, sbus_connect_init_done, req); return; } static void sbus_connect_init_done(struct tevent_req *subreq) { struct tevent_req *req; uint32_t res; errno_t ret; disarm_watchdog(); req = tevent_req_callback_data(subreq, struct tevent_req); ret = sbus_call_DBus_RequestName_recv(subreq, &res); talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); return; } switch (res) { case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: tevent_req_done(req); return; case DBUS_REQUEST_NAME_REPLY_EXISTS: tevent_req_error(req, EEXIST); return; default: tevent_req_error(req, EIO); return; } } errno_t sbus_connect_init_recv(struct tevent_req *req) { TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; } struct sbus_connection * sbus_connect_system(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *dbus_name, time_t *last_activity_time) { struct sbus_connection *sbus_conn; DBusConnection *dbus_conn; errno_t ret; dbus_conn = sbus_dbus_connect_bus(DBUS_BUS_SYSTEM, dbus_name); if (dbus_conn == NULL) { return NULL; } sbus_conn = sbus_connection_init(mem_ctx, ev, dbus_conn, NULL, dbus_name, SBUS_CONNECTION_SYSBUS, last_activity_time); dbus_connection_unref(dbus_conn); if (sbus_conn == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create connection context!\n"); return NULL; } ret = sbus_register_standard_signals(sbus_conn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register signal listeners " "[%d]: %s\n", ret, sss_strerror(ret)); talloc_free(sbus_conn); return NULL; } return sbus_conn; } struct sbus_connection * sbus_connect_private(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *address, const char *dbus_name, time_t *last_activity_time) { struct sbus_connection *sbus_conn; DBusConnection *dbus_conn; errno_t ret; dbus_conn = sbus_dbus_connect_address(address, dbus_name, true); if (dbus_conn == NULL) { return NULL; } sbus_conn = sbus_connection_init(mem_ctx, ev, dbus_conn, address, dbus_name, SBUS_CONNECTION_ADDRESS, last_activity_time); dbus_connection_unref(dbus_conn); if (sbus_conn == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create connection context!\n"); return NULL; } ret = sbus_register_standard_signals(sbus_conn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register signal listeners " "[%d]: %s\n", ret, sss_strerror(ret)); talloc_free(sbus_conn); return NULL; } return sbus_conn; } struct sbus_connect_private_state { struct sbus_connection *conn; }; static void sbus_connect_private_done(struct tevent_req *subreq); struct tevent_req * sbus_connect_private_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *address, const char *dbus_name, time_t *last_activity_time) { struct sbus_connect_private_state *state; DBusConnection *dbus_conn; struct tevent_req *subreq; struct tevent_req *req; errno_t ret; req = tevent_req_create(mem_ctx, &state, struct sbus_connect_private_state); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); return NULL; } dbus_conn = sbus_dbus_connect_address(address, dbus_name, false); if (dbus_conn == NULL) { ret = ENOMEM; goto done; } state->conn = sbus_connection_init(state, ev, dbus_conn, address, dbus_name, SBUS_CONNECTION_ADDRESS, last_activity_time); dbus_connection_unref(dbus_conn); if (state->conn == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create connection context!\n"); ret = ENOMEM; goto done; } subreq = sbus_connect_init_send(state, state->conn, dbus_name); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); ret = ENOMEM; goto done; } tevent_req_set_callback(subreq, sbus_connect_private_done, req); ret = EAGAIN; done: if (ret != EAGAIN) { tevent_req_error(req, ret); tevent_req_post(req, ev); } return req; } static void sbus_connect_private_done(struct tevent_req *subreq) { struct sbus_connect_private_state *state; struct tevent_req *req; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sbus_connect_private_state); ret = sbus_connect_init_recv(subreq); talloc_zfree(subreq); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize connection " "[%d]: %s\n", ret, sss_strerror(ret)); talloc_free(state->conn); tevent_req_error(req, ret); return; } ret = sbus_register_standard_signals(state->conn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register signal listeners " "[%d]: %s\n", ret, sss_strerror(ret)); talloc_zfree(state->conn); tevent_req_error(req, ret); return; } if (state->conn->wellknown_name == NULL) { DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s bus as anonymous\n", state->conn->address); } else { DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s bus as %s\n", state->conn->address, state->conn->wellknown_name); } tevent_req_done(req); return; } errno_t sbus_connect_private_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, struct sbus_connection **_conn) { struct sbus_connect_private_state *state; state = tevent_req_data(req, struct sbus_connect_private_state); TEVENT_REQ_RETURN_ON_ERROR(req); *_conn = talloc_steal(mem_ctx, state->conn); return EOK; } struct sbus_server_create_and_connect_state { struct sbus_server *server; struct sbus_connection *conn; }; static void sbus_server_create_and_connect_done(struct tevent_req *subreq); struct tevent_req * sbus_server_create_and_connect_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *dbus_name, time_t *last_activity_time, const char *address, bool use_symlink, uint32_t max_connections, uid_t uid, gid_t gid, sbus_server_on_connection_cb on_conn_cb, sbus_server_on_connection_data on_conn_data) { struct sbus_server_create_and_connect_state *state; struct tevent_req *subreq; struct tevent_req *req; errno_t ret; req = tevent_req_create(mem_ctx, &state, struct sbus_server_create_and_connect_state); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); return NULL; } state->server = sbus_server_create(state, ev, address, use_symlink, max_connections, uid, gid, on_conn_cb, on_conn_data); if (state->server == NULL) { ret = ENOMEM; goto done; } subreq = sbus_connect_private_send(state, ev, address, dbus_name, last_activity_time); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); ret = ENOMEM; goto done; } tevent_req_set_callback(subreq, sbus_server_create_and_connect_done, req); ret = EAGAIN; done: if (ret != EAGAIN) { tevent_req_error(req, ret); tevent_req_post(req, ev); } return req; } static void sbus_server_create_and_connect_done(struct tevent_req *subreq) { struct sbus_server_create_and_connect_state *state; struct tevent_req *req; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sbus_server_create_and_connect_state); ret = sbus_connect_private_recv(state, subreq, &state->conn); talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); return; } tevent_req_done(req); return; } errno_t sbus_server_create_and_connect_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, struct sbus_server **_server, struct sbus_connection **_conn) { struct sbus_server_create_and_connect_state *state; state = tevent_req_data(req, struct sbus_server_create_and_connect_state); TEVENT_REQ_RETURN_ON_ERROR(req); *_server = talloc_steal(mem_ctx, state->server); *_conn = talloc_steal(mem_ctx, state->conn); return EOK; }