summaryrefslogtreecommitdiffstats
path: root/src/sbus/connection/sbus_connection_connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sbus/connection/sbus_connection_connect.c')
-rw-r--r--src/sbus/connection/sbus_connection_connect.c430
1 files changed, 430 insertions, 0 deletions
diff --git a/src/sbus/connection/sbus_connection_connect.c b/src/sbus/connection/sbus_connection_connect.c
new file mode 100644
index 0000000..edc090e
--- /dev/null
+++ b/src/sbus/connection/sbus_connection_connect.c
@@ -0,0 +1,430 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+ Stephen Gallagher <sgallagh@redhat.com>
+ Simo Sorce <ssorce@redhat.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <tevent.h>
+#include <talloc.h>
+#include <dbus/dbus.h>
+
+#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;
+}