From 5f8c3c8f58c4e754f719a6d8258dc77b269ab066 Mon Sep 17 00:00:00 2001 From: Sergio Costas Date: Fri, 30 Dec 2022 23:47:45 +0100 Subject: [PATCH] Add support for getting UID and PID This patch allows to get the UID and the PID of a DBus client. --- .../docs/libgsystemservice-sections.txt | 4 +- libgsystemservice/peer-manager-dbus.c | 72 +++++++++++++++++-- libgsystemservice/peer-manager.c | 48 +++++++++++++ libgsystemservice/peer-manager.h | 15 ++++ 4 files changed, 133 insertions(+), 6 deletions(-) diff --git a/libgsystemservice/docs/libgsystemservice-sections.txt b/libgsystemservice/docs/libgsystemservice-sections.txt index 1645277..476e6a6 100644 --- a/libgsystemservice/docs/libgsystemservice-sections.txt +++ b/libgsystemservice/docs/libgsystemservice-sections.txt @@ -26,6 +26,8 @@ GssPeerManagerError gss_peer_manager_ensure_peer_credentials_async gss_peer_manager_ensure_peer_credentials_finish gss_peer_manager_get_peer_credentials +gss_peer_manager_get_peer_uid +gss_peer_manager_get_peer_pid GSS_TYPE_PEER_MANAGER @@ -69,4 +71,4 @@ gss_service_release GSS_TYPE_SERVICE GSS_SERVICE_ERROR gss_service_error_quark - \ No newline at end of file + diff --git a/libgsystemservice/peer-manager-dbus.c b/libgsystemservice/peer-manager-dbus.c index c37b61e..ad13f16 100644 --- a/libgsystemservice/peer-manager-dbus.c +++ b/libgsystemservice/peer-manager-dbus.c @@ -78,6 +78,10 @@ static gchar *gss_peer_manager_dbus_ensure_peer_credentials_finish (GssPee GError **error); static const gchar *gss_peer_manager_dbus_get_peer_credentials (GssPeerManager *manager, const gchar *sender); +static guint32 gss_peer_manager_dbus_get_peer_uid (GssPeerManager *manager, + const gchar *sender); +static guint32 gss_peer_manager_dbus_get_peer_pid (GssPeerManager *manager, + const gchar *sender); /** * GssPeerManagerDBus: @@ -133,12 +137,30 @@ gss_peer_manager_dbus_class_init (GssPeerManagerDBusClass *klass) g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props); } +typedef struct { + gchar *path; + guint32 uid; + guint32 pid; +} credentials_t; + +static void +free_credentials_t (gpointer element) +{ + if (element == NULL) + return; + + g_free (((credentials_t *)element)->path); + g_free (element); +} + static void gss_peer_manager_dbus_peer_manager_init (GssPeerManagerInterface *iface) { iface->ensure_peer_credentials_async = gss_peer_manager_dbus_ensure_peer_credentials_async; iface->ensure_peer_credentials_finish = gss_peer_manager_dbus_ensure_peer_credentials_finish; iface->get_peer_credentials = gss_peer_manager_dbus_get_peer_credentials; + iface->get_peer_uid = gss_peer_manager_dbus_get_peer_uid; + iface->get_peer_pid = gss_peer_manager_dbus_get_peer_pid; } static void @@ -152,7 +174,7 @@ gss_peer_manager_dbus_init (GssPeerManagerDBus *self) { self->peer_watch_ids = g_ptr_array_new_with_free_func (watcher_id_free); self->peer_credentials = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); + g_free, free_credentials_t); } static void @@ -303,7 +325,7 @@ ensure_peer_credentials_cb (GObject *obj, * (CAP_SYS_PTRACE, but I can’t get that working; so it would require root * privileges). Instead, we look at /proc/$pid/cmdline, which is accessible * by all. Unfortunately, it is also forgeable. */ - guint process_id; + guint process_id, user_id; g_autoptr(GVariant) credentials = g_variant_get_child_value (retval, 0); @@ -315,7 +337,14 @@ ensure_peer_credentials_cb (GObject *obj, sender); return; } - + if (!g_variant_lookup (credentials, "UnixUserID", "u", &user_id)) + { + g_task_return_new_error (task, GSS_PEER_MANAGER_ERROR, + GSS_PEER_MANAGER_ERROR_IDENTIFYING_PEER, + _("Process ID for peer ‘%s’ could not be determined"), + sender); + return; + } g_autofree gchar *pid_str = g_strdup_printf ("%u", process_id); g_autofree gchar *proc_pid_cmdline = g_build_filename ("/proc", pid_str, "cmdline", NULL); g_autofree gchar *cmdline = NULL; @@ -351,8 +380,12 @@ ensure_peer_credentials_cb (GObject *obj, g_debug ("%s: Got credentials from D-Bus daemon; path is ‘%s’ (resolved from ‘%s’)", G_STRFUNC, sender_path, cmdline); + credentials_t *element = g_new (credentials_t, 1); + element->path = g_strdup (sender_path); + element->pid = process_id; + element->uid = user_id; g_hash_table_replace (self->peer_credentials, - g_strdup (sender), g_strdup (sender_path)); + g_strdup (sender), element); g_task_return_pointer (task, g_steal_pointer (&sender_path), g_free); } @@ -375,7 +408,36 @@ gss_peer_manager_dbus_get_peer_credentials (GssPeerManager *manager, GssPeerManagerDBus *self = GSS_PEER_MANAGER_DBUS (manager); g_debug ("%s: Querying credentials for peer ‘%s’", G_STRFUNC, sender); - return g_hash_table_lookup (self->peer_credentials, sender); + credentials_t *credentials = g_hash_table_lookup (self->peer_credentials, sender); + if (credentials == NULL) + return NULL; + return credentials->path; +} + +static guint32 +gss_peer_manager_dbus_get_peer_uid (GssPeerManager *manager, + const gchar *sender) +{ + GssPeerManagerDBus *self = GSS_PEER_MANAGER_DBUS (manager); + + g_debug ("%s: Querying uid for peer ‘%s’", G_STRFUNC, sender); + credentials_t *credentials = g_hash_table_lookup (self->peer_credentials, sender); + if (credentials == NULL) + return -1; + return credentials->uid; +} + +static guint32 +gss_peer_manager_dbus_get_peer_pid (GssPeerManager *manager, + const gchar *sender) +{ + GssPeerManagerDBus *self = GSS_PEER_MANAGER_DBUS (manager); + + g_debug ("%s: Querying pid for peer ‘%s’", G_STRFUNC, sender); + credentials_t *credentials = g_hash_table_lookup (self->peer_credentials, sender); + if (credentials == NULL) + return -1; + return credentials->pid; } /** diff --git a/libgsystemservice/peer-manager.c b/libgsystemservice/peer-manager.c index 004795f..5037162 100644 --- a/libgsystemservice/peer-manager.c +++ b/libgsystemservice/peer-manager.c @@ -177,3 +177,51 @@ gss_peer_manager_get_peer_credentials (GssPeerManager *self, return iface->get_peer_credentials (self, sender); } + +/** + * gss_peer_manager_get_peer_uid: + * @self: a #GssPeerManager + * @sender: D-Bus unique name for the peer + * + * Get the UID for the given peer. If no credentials are in the cache + * for @sender, -1 will be returned. + * + * Returns: UID for the peer, or -1 if it’s unknown + * Since: 0.2.0 + */ +guint32 +gss_peer_manager_get_peer_uid (GssPeerManager *self, + const gchar *sender) +{ + g_return_val_if_fail (GSS_IS_PEER_MANAGER (self), -1); + g_return_val_if_fail (g_dbus_is_unique_name (sender), -1); + + GssPeerManagerInterface *iface = GSS_PEER_MANAGER_GET_IFACE (self); + g_assert (iface->get_peer_uid != NULL); + + return iface->get_peer_uid (self, sender); +} + +/** + * gss_peer_manager_get_peer_pid: + * @self: a #GssPeerManager + * @sender: D-Bus unique name for the peer + * + * Get the PID for the given peer. If no credentials are in the cache + * for @sender, -1 will be returned. + * + * Returns: PID for the peer, or -1 if it’s unknown + * Since: 0.2.0 + */ +guint32 +gss_peer_manager_get_peer_pid (GssPeerManager *self, + const gchar *sender) +{ + g_return_val_if_fail (GSS_IS_PEER_MANAGER (self), -1); + g_return_val_if_fail (g_dbus_is_unique_name (sender), -1); + + GssPeerManagerInterface *iface = GSS_PEER_MANAGER_GET_IFACE (self); + g_assert (iface->get_peer_pid != NULL); + + return iface->get_peer_pid (self, sender); +} diff --git a/libgsystemservice/peer-manager.h b/libgsystemservice/peer-manager.h index 158ba52..3174530 100644 --- a/libgsystemservice/peer-manager.h +++ b/libgsystemservice/peer-manager.h @@ -58,6 +58,10 @@ G_DECLARE_INTERFACE (GssPeerManager, gss_peer_manager, GSS, PEER_MANAGER, GObjec * started with @ensure_peer_credentials_async. * @get_peer_credentials: Get credentials for a peer out of the peer manager’s * cache. If the peer is not known to the manager, return %NULL. + * @get_peer_pid: Gets the PID for a peer out of the peer manager's cache. If + * the peer is not known to the manager, return -1. + * @get_peer_uid: Gets the UID for a peer out of the peer manager's cache. If + * the peer is not known to the manager, return -1. * * An interface which exposes peers for the service (typically, D-Bus clients * which are calling its methods) and allows querying of their credentials, and @@ -83,6 +87,12 @@ struct _GssPeerManagerInterface const gchar *(*get_peer_credentials) (GssPeerManager *manager, const gchar *sender); + + guint32 (*get_peer_pid) (GssPeerManager *manager, + const gchar *sender); + + guint32 (*get_peer_uid) (GssPeerManager *manager, + const gchar *sender); }; void gss_peer_manager_ensure_peer_credentials_async (GssPeerManager *self, @@ -97,4 +107,9 @@ gchar *gss_peer_manager_ensure_peer_credentials_finish (GssPeerManager const gchar *gss_peer_manager_get_peer_credentials (GssPeerManager *self, const gchar *sender); +guint32 gss_peer_manager_get_peer_pid (GssPeerManager *self, + const gchar *sender); + +guint32 gss_peer_manager_get_peer_uid (GssPeerManager *self, + const gchar *sender); G_END_DECLS -- GitLab