From 80a0a7569ea86d518bca4c322de15f925ef4e6db Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 6 Oct 2011 18:53:51 +0200 Subject: Append PID to sbus server socket name, let clients use a symlink https://fedorahosted.org/sssd/ticket/1034 --- src/monitor/monitor.c | 2 +- src/providers/data_provider_be.c | 2 +- src/providers/proxy/proxy_init.c | 2 +- src/sbus/sbus_client.c | 2 +- src/sbus/sssd_dbus.h | 1 + src/sbus/sssd_dbus_private.h | 1 + src/sbus/sssd_dbus_server.c | 186 +++++++++++++++++++++++++++++++++++---- 7 files changed, 175 insertions(+), 21 deletions(-) diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 87f7a172..b20bda86 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -462,7 +462,7 @@ static int monitor_dbus_init(struct mt_ctx *ctx) ret = sbus_new_server(ctx, ctx->ev, monitor_address, &monitor_server_interface, - &ctx->sbus_srv, monitor_service_init, ctx); + false, &ctx->sbus_srv, monitor_service_init, ctx); talloc_free(monitor_address); diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index 380e6cdb..42f7515b 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -860,7 +860,7 @@ static int be_srv_init(struct be_ctx *ctx) } ret = sbus_new_server(ctx, ctx->ev, sbus_address, - &be_interface, &ctx->sbus_srv, + &be_interface, true, &ctx->sbus_srv, be_client_init, ctx); if (ret != EOK) { DEBUG(0, ("Could not set up sbus server.\n")); diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c index d281dea2..f53d6de1 100644 --- a/src/providers/proxy/proxy_init.c +++ b/src/providers/proxy/proxy_init.c @@ -465,7 +465,7 @@ int sssm_proxy_auth_init(struct be_ctx *bectx, } ret = sbus_new_server(ctx, bectx->ev, sbus_address, &proxy_interface, - &ctx->sbus_srv, proxy_client_init, ctx); + false, &ctx->sbus_srv, proxy_client_init, ctx); if (ret != EOK) { DEBUG(0, ("Could not set up sbus server.\n")); goto done; diff --git a/src/sbus/sbus_client.c b/src/sbus/sbus_client.c index 5b15ef3e..a06b28d2 100644 --- a/src/sbus/sbus_client.c +++ b/src/sbus/sbus_client.c @@ -46,7 +46,7 @@ int sbus_client_init(TALLOC_CTX *mem_ctx, return EIO; } - ret = check_file(filename, 0, 0, 0600, CHECK_SOCK, NULL, false); + ret = check_file(filename, 0, 0, 0600, CHECK_SOCK, NULL, true); if (ret != EOK) { DEBUG(1, ("check_file failed for [%s].\n", filename)); return EIO; diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h index 2dbf4ab7..98159a7b 100644 --- a/src/sbus/sssd_dbus.h +++ b/src/sbus/sssd_dbus.h @@ -79,6 +79,7 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *address, struct sbus_interface *intf, + bool use_symlink, struct sbus_connection **server, sbus_server_conn_init_fn init_fn, void *init_pvt_data); diff --git a/src/sbus/sssd_dbus_private.h b/src/sbus/sssd_dbus_private.h index 78a2fe5c..c62e0e3f 100644 --- a/src/sbus/sssd_dbus_private.h +++ b/src/sbus/sssd_dbus_private.h @@ -58,6 +58,7 @@ struct sbus_connection { void *reconnect_pvt; /* server related stuff */ + char *symlink; struct sbus_interface *server_intf; sbus_server_conn_init_fn srv_init_fn; void *srv_init_data; diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c index fdcbc4ff..759eb69f 100644 --- a/src/sbus/sssd_dbus_server.c +++ b/src/sbus/sssd_dbus_server.c @@ -81,6 +81,97 @@ static void sbus_server_init_new_connection(DBusServer *dbus_server, } } +const char * +get_socket_address(TALLOC_CTX *mem_ctx, const char *address, bool use_symlink) +{ + if (!use_symlink) { + return talloc_strdup(mem_ctx, address); + } + + return talloc_asprintf(mem_ctx, + "%s.%lu", address, (unsigned long) getpid()); +} + +static errno_t +create_socket_symlink(const char *filename, const char *symlink_filename) +{ + errno_t ret; + + DEBUG(7, ("Symlinking the dbus path %s to a link %s\n", + filename, symlink_filename)); + errno = 0; + ret = symlink(filename, symlink_filename); + if (ret != 0 && errno == EEXIST) { + /* Perhaps cruft after a previous server? */ + ret = unlink(symlink_filename); + if (ret != 0) { + DEBUG(1, ("Cannot remove old symlink: [%d][%s].\n", + ret, strerror(ret))); + return EIO; + } + errno = 0; + ret = symlink(filename, symlink_filename); + } + + if (ret != 0) { + ret = errno; + DEBUG(1, ("symlink() failed on file '%s': [%d][%s].\n", + filename, ret, strerror(ret))); + return EIO; + } + + return EOK; +} + +static errno_t +remove_socket_symlink(const char *symlink_name) +{ + errno_t ret; + char target[PATH_MAX]; + char pidpath[PATH_MAX]; + ssize_t numread = 0; + + errno = 0; + numread = readlink(symlink_name, target, PATH_MAX); + if (numread < 0) { + ret = errno; + DEBUG(2, ("readlink failed [%d]: %s\n", ret, strerror(ret))); + return ret; + } + target[numread] = '\0'; + DEBUG(9, ("The symlink points to [%s]\n", target)); + + /* We can only remove the symlink if it points to a socket with + * the same PID */ + ret = snprintf(pidpath, PATH_MAX, "%s.%lu", + symlink_name, (unsigned long) getpid()); + if (ret < 0) { + DEBUG(2, ("snprintf failed")); + return EIO; + } else if (ret >= PATH_MAX) { + DEBUG(2, ("path too long?!?!\n")); + return EIO; + } + DEBUG(9, ("The path including our pid is [%s]\n", pidpath)); + + if (strcmp(pidpath, target) != 0) { + DEBUG(4, ("Will not remove symlink, seems to be owned by " + "another process\n")); + return EOK; + } + + ret = unlink(symlink_name); + if (ret != 0) { + ret = errno; + DEBUG(2, ("unlink failed to remove [%s] [%d]: %s\n", + symlink, ret, strerror(ret))); + return ret; + } + + DEBUG(9, ("Removed the symlink\n")); + return EOK; +} + /* * dbus_new_server * Set up a D-BUS server, integrate with the event loop @@ -90,8 +181,10 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *address, struct sbus_interface *intf, + bool use_symlink, struct sbus_connection **_server, - sbus_server_conn_init_fn init_fn, void *init_pvt_data) + sbus_server_conn_init_fn init_fn, + void *init_pvt_data) { struct sbus_connection *server; DBusServer *dbus_server; @@ -100,30 +193,64 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, char *tmp; int ret; char *filename; + char *symlink_filename = NULL; + const char *socket_address; struct stat stat_buf; + TALLOC_CTX *tmp_ctx; *_server = NULL; + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + socket_address = get_socket_address(tmp_ctx, address, use_symlink); + if (!socket_address) { + ret = ENOMEM; + goto done; + } + /* Set up D-BUS server */ dbus_error_init(&dbus_error); - dbus_server = dbus_server_listen(address, &dbus_error); + dbus_server = dbus_server_listen(socket_address, &dbus_error); if (!dbus_server) { DEBUG(1,("dbus_server_listen failed! (name=%s, message=%s)\n", dbus_error.name, dbus_error.message)); if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); - return EIO; + ret = EIO; + goto done; } - filename = strchr(address, '/'); + filename = strchr(socket_address, '/'); if (filename == NULL) { - DEBUG(1, ("Unexpected dbus address [%s].\n", address)); - return EIO; + DEBUG(1, ("Unexpected dbus address [%s].\n", socket_address)); + ret = EIO; + goto done; + } + + if (use_symlink) { + symlink_filename = strchr(address, '/'); + if (symlink_filename == NULL) { + DEBUG(1, ("Unexpected dbus address [%s].\n", address)); + ret = EIO; + goto done; + } + + ret = create_socket_symlink(filename, symlink_filename); + if (ret != EOK) { + DEBUG(1, ("Could not create symlink [%d]: %s\n", + ret, strerror(ret))); + ret = EIO; + goto done; + } } - ret = check_file(filename, 0, 0, -1, CHECK_SOCK, &stat_buf, false); + /* Both check_file and chmod can handle both the symlink and + * the socket */ + ret = check_file(filename, 0, 0, -1, CHECK_SOCK, &stat_buf, true); if (ret != EOK) { DEBUG(1, ("check_file failed for [%s].\n", filename)); - return EIO; + ret = EIO; + goto done; } if ((stat_buf.st_mode & ~S_IFMT) != 0600) { @@ -131,7 +258,8 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, if (ret != EOK) { DEBUG(1, ("chmod failed for [%s]: [%d][%s].\n", filename, errno, strerror(errno))); - return EIO; + ret = EIO; + goto done; } } @@ -139,9 +267,10 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, DEBUG(3, ("D-BUS Server listening on %s\n", tmp)); free(tmp); - server = talloc_zero(mem_ctx, struct sbus_connection); + server = talloc_zero(tmp_ctx, struct sbus_connection); if (!server) { - return ENOMEM; + ret = ENOMEM; + goto done; } server->ev = ev; @@ -153,6 +282,14 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, talloc_set_destructor((TALLOC_CTX *)server, sbus_server_destructor); + if (use_symlink) { + server->symlink = talloc_strdup(server, symlink_filename); + if (!server->symlink) { + ret = ENOMEM; + goto done; + } + } + /* Set up D-BUS new connection handler */ dbus_server_set_new_connection_function(server->dbus.server, sbus_server_init_new_connection, @@ -166,8 +303,8 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, server, NULL); if (!dbret) { DEBUG(4, ("Error setting up D-BUS server watch functions\n")); - talloc_free(server); - return EIO; + ret = EIO; + goto done; } /* Set up DBusTimeout functions */ @@ -180,19 +317,34 @@ int sbus_new_server(TALLOC_CTX *mem_ctx, DEBUG(4,("Error setting up D-BUS server timeout functions\n")); dbus_server_set_watch_functions(server->dbus.server, NULL, NULL, NULL, NULL, NULL); - talloc_free(server); - return EIO; + ret = EIO; + goto done; } - *_server = server; - return EOK; + *_server = talloc_steal(mem_ctx, server); + ret = EOK; +done: + if (ret != EOK && symlink_filename) { + unlink(symlink_filename); + } + talloc_free(tmp_ctx); + return ret; } static int sbus_server_destructor(void *ctx) { struct sbus_connection *server; + errno_t ret; server = talloc_get_type(ctx, struct sbus_connection); dbus_server_disconnect(server->dbus.server); + + if (server->symlink) { + ret = remove_socket_symlink(server->symlink); + if (ret != EOK) { + DEBUG(3, ("Could not remove the server symlink\n")); + } + } + return 0; } -- cgit