[grilo-plugins] upnp: tag sources that belong to the same user
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] upnp: tag sources that belong to the same user
- Date: Thu, 27 Mar 2014 19:21:32 +0000 (UTC)
commit 91c4ee1dfe0bd39155e8a19ca3d7c4d335bb652b
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Wed Mar 5 21:19:45 2014 +0100
upnp: tag sources that belong to the same user
If the source is found to be on the local machine, scan /proc/net/tcp
to find the UID of the process that is listening on the socket,
and tag the source if it's the same user as the one running the
client.
https://bugzilla.gnome.org/show_bug.cgi?id=723780
src/upnp/grl-upnp-utils.c | 300 ++++++++++++++++++++++++++++++++++++++++++---
src/upnp/grl-upnp-utils.h | 4 +-
src/upnp/grl-upnp.c | 27 +++--
3 files changed, 306 insertions(+), 25 deletions(-)
---
diff --git a/src/upnp/grl-upnp-utils.c b/src/upnp/grl-upnp-utils.c
index 0ad0833..6d818bc 100644
--- a/src/upnp/grl-upnp-utils.c
+++ b/src/upnp/grl-upnp-utils.c
@@ -25,6 +25,7 @@
#define _GNU_SOURCE
#include <string.h>
+#include <stdlib.h>
#include <gio/gio.h>
#ifdef G_OS_UNIX
@@ -32,6 +33,10 @@
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
+#ifdef __linux__
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#endif
#endif
#include "grl-upnp-utils.h"
@@ -92,38 +97,303 @@ is_our_ip_address (GInetAddress *address)
return ret;
}
-gboolean
-grl_upnp_util_uri_is_localhost (SoupURI *uri)
+#ifdef __linux__
+static gboolean
+is_our_user_ipv4 (struct sockaddr_in *address)
+{
+ GIOChannel *file;
+ gboolean found;
+ uid_t uid;
+ gboolean ret;
+ GIOStatus status;
+ gchar *line;
+
+ ret = FALSE;
+ file = g_io_channel_new_file ("/proc/net/tcp", "r", NULL);
+ if (file == NULL)
+ return FALSE;
+
+ found = FALSE;
+ /* skip first line, it's the header */
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ g_free (line);
+ if (status != G_IO_STATUS_NORMAL)
+ goto out;
+
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ while (status == G_IO_STATUS_NORMAL) {
+ int j, k, l;
+ /* 8 for IP, 4 for port, 1 for :, 1 for NUL */
+ char buffer[8 + 4 + 1 + 1];
+ guint32 ip;
+ guint16 port;
+
+ j = 0;
+
+ /* skip leading space */
+ while (line[j] == ' ')
+ j++;
+
+ /* skip the first field */
+ while (line[j] != ' ')
+ j++;
+ while (line[j] == ' ')
+ j++;
+
+ strncpy(buffer, line + j, sizeof(buffer));
+ buffer[8+4+1] = 0;
+ buffer[8] = 0;
+ j += 8+4+1;
+
+ /* the IP is in network byte order
+ (so 127.0.0.1 is 0100007F)
+ */
+ ip = strtoul(buffer, NULL, 16);
+ port = htons(strtoul(buffer+8+1, NULL, 16));
+
+ if ((ip == 0 || ip == address->sin_addr.s_addr) &&
+ port == address->sin_port) {
+ /* skip rem_address, st, tx_queue+rx_queue, tr+tm->when, retrnsmt */
+ while (line[j] == ' ')
+ j++;
+ for (k = 0; k < 5; k++) {
+ while (line[j] != ' ')
+ j++;
+ while (line[j] == ' ')
+ j++;
+ }
+
+ strncpy(buffer, line + j, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ l = 0;
+ while (buffer[l] != ' ' && buffer[l] != 0)
+ l++;
+ buffer[l] = 0;
+
+ uid = strtoul(buffer, NULL, 0);
+
+ found = TRUE;
+ break;
+ }
+
+ g_free (line);
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ }
+
+ if (found)
+ ret = uid == getuid();
+
+ out:
+ g_io_channel_unref (file);
+ return ret;
+}
+
+static gboolean
+is_our_user_ipv6 (struct sockaddr_in6 *address)
+{
+ GIOChannel *file;
+ gboolean found;
+ uid_t uid;
+ gboolean ret;
+ GIOStatus status;
+ gchar *line;
+
+ ret = FALSE;
+ file = g_io_channel_new_file ("/proc/net/tcp", "r", NULL);
+ if (file == NULL)
+ return FALSE;
+
+ found = FALSE;
+ /* skip first line, it's the header */
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ g_free (line);
+ if (status != G_IO_STATUS_NORMAL)
+ goto out;
+
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ while (status == G_IO_STATUS_NORMAL) {
+ char *line;
+ int j, k, l;
+ /* 4*8 for IP, 4 for port, 1 for :, 1 for NUL */
+ char buffer[4*8 + 4 + 1 + 1];
+ guint32 ip[4];
+ guint16 port;
+ guint32 all_ipv6[4] = { 0, 0, 0, 0 };
+
+ j = 0;
+
+ /* skip leading space */
+ while (line[j] == ' ')
+ j++;
+
+ /* skip the first field */
+ while (line[j] != ' ')
+ j++;
+ while (line[j] == ' ')
+ j++;
+
+ strncpy(buffer, line + j, sizeof(buffer));
+ buffer[4*8+4+1] = 0;
+ buffer[4*8] = 0;
+ j += 4*8+4+1;
+
+ for (k = 0; k < 4; k++) {
+ /* the IP is written as 4 uint32 units, each in network
+ byte order
+ */
+ char c;
+ c = buffer[8 * k];
+ buffer[8 * k] = 0;
+ ip[k] = strtoul(buffer, NULL, 16);
+ buffer[8 * k] = c;
+ }
+ port = htons(strtoul(buffer+4*8+1, NULL, 16));
+
+ if ((memcmp (ip, all_ipv6, sizeof(ip)) == 0 ||
+ memcmp (ip, address->sin6_addr.s6_addr, sizeof(ip)) == 0) &&
+ port == address->sin6_port) {
+ /* skip remote_address, st, tx_queue+rx_queue, tr+tm->when, retrnsmt */
+ while (line[j] == ' ')
+ j++;
+ for (k = 0; k < 5; k++) {
+ while (line[j] != ' ')
+ j++;
+ while (line[j] == ' ')
+ j++;
+ }
+
+ strncpy(buffer, line + j, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ l = 0;
+ while (buffer[l] != ' ' && buffer[l] != 0)
+ l++;
+ buffer[l] = 0;
+
+ uid = strtoul(buffer, NULL, 0);
+
+ found = TRUE;
+ break;
+ }
+
+ g_free (line);
+ status = g_io_channel_read_line (file, &line, NULL, NULL, NULL);
+ }
+
+ if (found)
+ ret = uid == getuid();
+
+ out:
+ g_io_channel_unref (file);
+ return ret;
+}
+
+static gboolean
+is_our_user (GSocketAddress *sockaddr)
+{
+ struct sockaddr *native_sockaddr;
+ gsize native_len;
+ gboolean ret;
+
+ native_len = g_socket_address_get_native_size (sockaddr);
+ native_sockaddr = g_alloca (native_len);
+ g_socket_address_to_native (sockaddr, native_sockaddr, native_len, NULL);
+
+ if (native_sockaddr->sa_family == AF_INET) {
+ ret = is_our_user_ipv4 ((struct sockaddr_in*) native_sockaddr);
+
+ if (!ret) {
+ /* try also an ipv6 mapped ipv4 */
+ struct sockaddr_in6 ipv6;
+ ipv6.sin6_family = AF_INET6;
+ ipv6.sin6_port = ((struct sockaddr_in*) native_sockaddr)->sin_port;
+ ipv6.sin6_flowinfo = 0;
+
+ memset (ipv6.sin6_addr.s6_addr, 0, 12);
+ memcpy (ipv6.sin6_addr.s6_addr + 12, &((struct sockaddr_in*) native_sockaddr)->sin_port, 4);
+
+ return is_our_user_ipv6 (&ipv6);
+ } else
+ return ret;
+ } else
+ return is_our_user_ipv6 ((struct sockaddr_in6*) native_sockaddr);
+}
+#else
+static gboolean
+is_our_user (GSocketAddress *address)
+{
+ return FALSE;
+}
+#endif
+
+void
+grl_upnp_util_uri_is_localhost (SoupURI *uri,
+ gboolean *localuser,
+ gboolean *localhost)
{
char hostname_buffer[HOSTNAME_LENGTH+1];
const char *host;
GInetAddress *ip_address;
- gboolean ret;
host = soup_uri_get_host (uri);
- if (host == NULL)
- return FALSE;
+ if (host == NULL) {
+ *localhost = FALSE;
+ *localuser = FALSE;
+ return;
+ }
gethostname (hostname_buffer, sizeof(hostname_buffer));
- if (strcmp (hostname_buffer, host) == 0)
- return TRUE;
+ if (strcmp (hostname_buffer, host) == 0) {
+ GList *addresses;
+ GSocketAddress *sockaddr;
+
+ addresses = g_resolver_lookup_by_name (g_resolver_get_default (), host, NULL, NULL);
+ if (addresses == NULL) {
+ *localhost = FALSE;
+ *localuser = FALSE;
+ return;
+ }
+
+ *localhost = TRUE;
+
+ sockaddr = G_SOCKET_ADDRESS (g_inet_socket_address_new (addresses->data, uri->port));
+ *localuser = is_our_user (sockaddr);
+
+ g_object_unref (sockaddr);
+ g_list_free_full (addresses, g_object_unref);
+ return;
+ }
ip_address = g_inet_address_new_from_string (host);
- if (ip_address == NULL)
- return FALSE;
+ if (ip_address == NULL) {
+ *localhost = FALSE;
+ *localuser = FALSE;
+ return;
+ }
- ret = is_our_ip_address (ip_address);
- g_object_unref (ip_address);
+ *localhost = is_our_ip_address (ip_address);
+ if (*localhost) {
+ GSocketAddress *sockaddr;
- return ret;
+ sockaddr = G_SOCKET_ADDRESS (g_inet_socket_address_new (ip_address, uri->port));
+ *localuser = is_our_user (sockaddr);
+
+ g_object_unref (sockaddr);
+ } else {
+ *localuser = FALSE;
+ }
+
+ g_object_unref (ip_address);
}
#else
-gboolean
-grl_upnp_util_uri_is_localhost (SoupURI *uri)
+void
+grl_upnp_util_uri_is_localhost (SoupURI *uri,
+ gboolean *localhost,
+ gboolean *localuser)
{
- return FALSE;
+ *localhost = FALSE;
+ *localuser = FALSE;
}
#endif
diff --git a/src/upnp/grl-upnp-utils.h b/src/upnp/grl-upnp-utils.h
index 52332b6..0f9e23e 100644
--- a/src/upnp/grl-upnp-utils.h
+++ b/src/upnp/grl-upnp-utils.h
@@ -25,7 +25,9 @@
G_BEGIN_DECLS
-gboolean grl_upnp_util_uri_is_localhost (SoupURI *uri);
+void grl_upnp_util_uri_is_localhost (SoupURI *uri,
+ gboolean *localhost,
+ gboolean *localuser);
G_END_DECLS
diff --git a/src/upnp/grl-upnp.c b/src/upnp/grl-upnp.c
index f9a7e39..4288925 100644
--- a/src/upnp/grl-upnp.c
+++ b/src/upnp/grl-upnp.c
@@ -110,7 +110,11 @@ static void setup_key_mappings (void);
static gchar *build_source_id (const gchar *udn);
-static GrlUpnpSource *grl_upnp_source_new (const gchar *id, const gchar *name, const gchar *icon_url,
gboolean localmachine);
+static GrlUpnpSource *grl_upnp_source_new (const gchar *id,
+ const gchar *name,
+ const gchar *icon_url,
+ gboolean localhost,
+ gboolean localuser);
gboolean grl_upnp_plugin_init (GrlRegistry *registry,
GrlPlugin *plugin,
@@ -211,12 +215,14 @@ static GrlUpnpSource *
grl_upnp_source_new (const gchar *source_id,
const gchar *name,
const gchar *icon_url,
- gboolean localhost)
+ gboolean localhost,
+ gboolean localuser)
{
gchar *source_desc;
GrlUpnpSource *source;
GIcon *icon = NULL;
- gchar *tags[2];
+ gchar *tags[3];
+ int i;
GRL_DEBUG ("grl_upnp_source_new");
source_desc = g_strdup_printf (SOURCE_DESC_TEMPLATE, name);
@@ -229,11 +235,12 @@ grl_upnp_source_new (const gchar *source_id,
g_object_unref (file);
}
- if (localhost) {
- tags[0] = "localhost";
- tags[1] = NULL;
- } else
- tags[0] = NULL;
+ i = 0;
+ if (localhost)
+ tags[i++] = "localhost";
+ if (localuser)
+ tags[i++] = "localuser";
+ tags[i++] = NULL;
source = g_object_new (GRL_UPNP_SOURCE_TYPE,
"source-id", source_id,
@@ -476,6 +483,7 @@ device_available_cb (GUPnPControlPoint *cp,
GrlRegistry *registry;
gchar *source_id;
gchar *icon_url;
+ gboolean localhost, localuser;
GRL_DEBUG ("device_available_cb");
@@ -508,8 +516,9 @@ device_available_cb (GUPnPControlPoint *cp,
/* Now let's check if it supports search operations before registering */
icon_url = get_device_icon (device);
url_base = (SoupURI*) gupnp_device_info_get_url_base (GUPNP_DEVICE_INFO (device));
+ grl_upnp_util_uri_is_localhost (url_base, &localhost, &localuser);
GrlUpnpSource *source = grl_upnp_source_new (source_id, name, icon_url,
- grl_upnp_util_uri_is_localhost (url_base));
+ localhost, localuser);
g_free (icon_url);
source->priv->device = g_object_ref (device);
source->priv->service = g_object_ref (service);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]