[gupnp] Implement a simple ACL infrastructure
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp] Implement a simple ACL infrastructure
- Date: Sun, 4 May 2014 12:59:55 +0000 (UTC)
commit 036f9d8b3df1fee296f04c553aee59234f967eae
Author: Jens Georg <mail jensge org>
Date: Sun Nov 24 01:25:05 2013 +0100
Implement a simple ACL infrastructure
Signed-off-by: Jens Georg <mail jensge org>
configure.ac | 2 +-
libgupnp/Makefile.am | 5 +-
libgupnp/gupnp-acl-private.h | 85 +++++++++++++
libgupnp/gupnp-acl.c | 258 ++++++++++++++++++++++++++++++++++++++
libgupnp/gupnp-acl.h | 118 +++++++++++++++++
libgupnp/gupnp-context-private.h | 7 +
libgupnp/gupnp-context.c | 221 ++++++++++++++++++++++++++++++++-
libgupnp/gupnp-context.h | 16 +++
libgupnp/gupnp-service.c | 31 +++--
9 files changed, 729 insertions(+), 14 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bd03565..6b073de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -137,7 +137,7 @@ AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug], [enable debugging]),,
enable_debug=no)
if test "x$enable_debug" = "xyes"; then
- CFLAGS="$CFLAGS -g -Wall -Werror"
+ CFLAGS="$CFLAGS -g -Wall -Wextra -Werror"
fi
GOBJECT_INTROSPECTION_CHECK([0.6.4])
diff --git a/libgupnp/Makefile.am b/libgupnp/Makefile.am
index 5f65373..771434d 100644
--- a/libgupnp/Makefile.am
+++ b/libgupnp/Makefile.am
@@ -48,7 +48,8 @@ libgupnpincdir = $(includedir)/gupnp-1.0/libgupnp
lib_LTLIBRARIES = libgupnp-1.0.la
-libgupnpinc_HEADERS = gupnp-context.h \
+libgupnpinc_HEADERS = gupnp-acl.h \
+ gupnp-context.h \
gupnp-context-manager.h \
gupnp-control-point.h \
gupnp-device.h \
@@ -67,6 +68,7 @@ libgupnpinc_HEADERS = gupnp-context.h \
gupnp.h
introspection_sources = $(libgupnpinc_HEADERS) \
+ gupnp-acl.c \
gupnp-context.c \
gupnp-context-manager.c \
gupnp-control-point.c \
@@ -106,6 +108,7 @@ libgupnp_1_0_la_SOURCES = $(introspection_sources) \
gupnp-error-private.h \
gupnp-resource-factory-private.h \
gupnp-service-introspection-private.h \
+ gupnp-acl-private.h \
gupnp-types-private.h \
gvalue-util.c \
gvalue-util.h \
diff --git a/libgupnp/gupnp-acl-private.h b/libgupnp/gupnp-acl-private.h
new file mode 100644
index 0000000..ec28ef7
--- /dev/null
+++ b/libgupnp/gupnp-acl-private.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013,2014 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_ACL_PRIVATE_H__
+#define __GUPNP_ACL_PRIVATE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libsoup/soup-session.h>
+
+#include "gupnp-acl.h"
+#include "gupnp-context.h"
+
+G_BEGIN_DECLS
+
+/**
+ * Closure for the ACL server handler that adds
+ * a) Some data from the original server handler such as user_data and callback
+ * b) Saves information for later use to pass on to ACL such as the service and context
+ */
+typedef struct _AclServerHandler
+{
+ GUPnPService *service;
+ GUPnPContext *context;
+ SoupServerCallback callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+} AclServerHandler;
+
+/**
+ * Closure when doing an async ACL request. Stores everything passed into the server handler
+ */
+typedef struct _AclAsyncHandler
+{
+ SoupServer *server;
+ SoupMessage *message;
+ char *path;
+ GHashTable *query;
+ SoupClientContext *client;
+ AclServerHandler *handler;
+} AclAsyncHandler;
+
+G_GNUC_INTERNAL AclServerHandler *
+acl_server_handler_new (GUPnPService *service,
+ GUPnPContext *context,
+ SoupServerCallback callback,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+G_GNUC_INTERNAL void
+acl_server_handler_free (AclServerHandler *handler);
+
+G_GNUC_INTERNAL AclAsyncHandler *
+acl_async_handler_new (SoupServer *server,
+ SoupMessage *message,
+ const char *path,
+ GHashTable *query,
+ SoupClientContext *client,
+ AclServerHandler *handler);
+
+G_GNUC_INTERNAL void
+acl_async_handler_free (AclAsyncHandler *handler);
+
+
+G_END_DECLS
+
+#endif
diff --git a/libgupnp/gupnp-acl.c b/libgupnp/gupnp-acl.c
new file mode 100644
index 0000000..d9accc8
--- /dev/null
+++ b/libgupnp/gupnp-acl.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2013,2014 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gupnp-acl.h"
+#include "gupnp-acl-private.h"
+
+G_DEFINE_INTERFACE(GUPnPAcl, gupnp_acl, G_TYPE_OBJECT)
+
+static void
+gupnp_acl_default_init (GUPnPAclInterface *klass)
+{
+}
+
+/**
+ * gupnp_acl_is_allowed:
+ * @self: an instance of #GUPnPAcl
+ * @device: (allow-none): The #GUPnPDevice associated with @path or %NULL if
+ * unknown.
+ * @service: (allow-none): The #GUPnPService associated with @path or %NULL if
+ * unknown.
+ * @path: The path being served.
+ * @address: IP address of the peer.
+ * @agent: (allow-none): The User-Agent header of the peer or %NULL if not
+ * unknown.
+ * @returns: %TRUE if the peer is allowed, %FALSE otherwise
+ *
+ * Check whether an IP address is allowed to access this resource.
+ *
+ * Since: 0.20.11
+ */
+gboolean
+gupnp_acl_is_allowed (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent)
+{
+ g_return_val_if_fail (GUPNP_IS_ACL (self), FALSE);
+
+ return GUPNP_ACL_GET_INTERFACE (self)->is_allowed (self,
+ device,
+ service,
+ path,
+ address,
+ agent);
+}
+
+/**
+ * gupnp_acl_is_allowed_async:
+ * @self: a #GUPnPAcl
+ * @device: (allow-none): The #GUPnPDevice associated with @path or %NULL if
+ * unknown.
+ * @service: (allow-none): The #GUPnPService associated with @path or %NULL if
+ * unknown.
+ * @path: The path being served.
+ * @address: IP address of the peer
+ * @agent: (allow-none): The User-Agent header of the peer or %NULL if not
+ * unknown.
+ * @cancellable: (allow-none): A #GCancellable which can be used to cancel the
+ * operation.
+ * @callback: Callback to call after the function is done.
+ * @user_data: Some user data.
+ *
+ * Optional. Check asynchronously whether an IP address is allowed to access
+ * this resource. Use this function if the process of verifying the access right
+ * is expected to take some time, for example when using D-Bus etc.
+ *
+ * If this function is supported, gupnp_acl_can_sync() should return %TRUE.
+ *
+ * Use gupnp_acl_is_allowed_finish() to retrieve the result.
+ *
+* Since: 0.20.11
+ */
+void
+gupnp_acl_is_allowed_async (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GUPNP_IS_ACL (self));
+
+ GUPNP_ACL_GET_INTERFACE (self)->is_allowed_async (self,
+ device,
+ service,
+ path,
+ address,
+ agent,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * gupnp_acl_is_allowed_finish:
+ * @self: An instance of #GUPnPAcl
+ * @res: %GAsyncResult obtained from the callback in gupnp_acl_is_allowed_async()
+ * @error: (allow-none): A return location for a #GError describing the failure
+ * @returns %TRUE if the authentication was successful, %FALSE otherwise and on
+ * error. Check @error for details.
+ *
+ * Since: 0.20.11
+ */
+gboolean
+gupnp_acl_is_allowed_finish (GUPnPAcl *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_return_if_fail (GUPNP_IS_ACL (self));
+
+ return GUPNP_ACL_GET_INTERFACE (self)->is_allowed_finish (self,
+ res,
+ error);
+}
+
+/**
+ * gupnp_acl_can_sync:
+ * @self: A #GUPnPAcl
+ * @returns: %TRUE, if gupnp_acl_is_allowed_async() is supported, %FALSE
+ * otherwise.
+ *
+ * Check whether gupnp_acl_is_allowed_async() is supported.
+ *
+ * Since: 0.20.11
+ */
+gboolean
+gupnp_acl_can_sync (GUPnPAcl *self)
+{
+ g_return_if_fail (GUPNP_IS_ACL (self));
+
+ return GUPNP_ACL_GET_INTERFACE (self)->can_sync (self);
+}
+
+/**
+ * acl_server_handler_new:
+ *
+ * Allocate a new #AclServerHandler.
+ *
+ * @service: (allow-none): A #GUPnPContext or %NULL if unknown
+ * @context: The #GUPnPContext the server handler is run on.
+ * @callback: The #SoupServerCallback we're wrapping.
+ * @user_data: The user_data for @callback
+ * @notify: (allow-none): The #GDestroyNotify for @user_data or %NULL if none.
+ * @returns: A newly allocated #AclServerHandler
+ */
+AclServerHandler *
+acl_server_handler_new (GUPnPService *service,
+ GUPnPContext *context,
+ SoupServerCallback callback,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ AclServerHandler *handler = g_new0 (AclServerHandler, 1);
+
+ handler->service = service ? g_object_ref (service) : NULL;
+ handler->context = g_object_ref (context);
+ handler->callback = callback;
+ handler->user_data = user_data;
+ handler->notify = notify;
+
+ return handler;
+}
+
+/**
+ * acl_server_handler_free:
+ *
+ * Free an #AclServerHandler previously allocated with acl_server_handler_new().
+ *
+ * @handler: An #AclServerHandler instance.
+ */
+void
+acl_server_handler_free (AclServerHandler *handler)
+{
+ g_clear_object (&handler->service);
+ g_clear_object (&handler->context);
+
+ if (handler->notify != NULL)
+ handler->notify (handler->user_data);
+
+ g_free (handler);
+}
+
+/**
+ * acl_async_handler_new:
+ *
+ * Create a new async closure.
+ *
+ * @server: A #SoupServer instance.
+ * @message: The #SoupMessage we want to handle.
+ * @path: The path we're trying to serve.
+ * @query: (allow-none): The query parameters of the request.
+ * @client: The #SoupClientContext for this request.
+ * @handler: The #AclServerHandler used with this request.
+ * @returns: A new instance of #AclAsyncHandler.
+ */
+AclAsyncHandler *
+acl_async_handler_new (SoupServer *server,
+ SoupMessage *message,
+ const char *path,
+ GHashTable *query,
+ SoupClientContext *client,
+ AclServerHandler *handler)
+{
+ AclAsyncHandler *data = g_slice_new0 (AclAsyncHandler);
+
+ data->server = g_object_ref (server);
+ data->message = g_object_ref (message);
+ data->path = g_strdup (path);
+ if (query != NULL)
+ data->query = g_hash_table_ref (query);
+ data->client = g_boxed_copy (SOUP_TYPE_CLIENT_CONTEXT, client);
+ data->handler = handler;
+
+ return data;
+}
+
+/**
+ * acl_async_handler_free:
+ *
+ * Free an #AclAsyncHandler allocated with acl_async_handler_new().
+ *
+ * @handler: An instance allocated with acl_async_handler_new()
+ */
+void
+acl_async_handler_free (AclAsyncHandler *handler)
+{
+ g_object_unref (handler->server);
+ g_object_unref (handler->message);
+ g_free (handler->path);
+ if (handler->query != NULL)
+ g_hash_table_unref (handler->query);
+ g_boxed_free (SOUP_TYPE_CLIENT_CONTEXT, handler->client);
+
+ g_slice_free (AclAsyncHandler, handler);
+}
diff --git a/libgupnp/gupnp-acl.h b/libgupnp/gupnp-acl.h
new file mode 100644
index 0000000..a1ba497
--- /dev/null
+++ b/libgupnp/gupnp-acl.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013,2014 Jens Georg <mail jensge org>
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_ACL_H__
+#define __GUPNP_ACL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libsoup/soup-session.h>
+
+G_BEGIN_DECLS
+
+GType
+gupnp_acl_get_type (void) G_GNUC_CONST;
+
+#define GUPNP_TYPE_ACL (gupnp_acl_get_type())
+
+#define GUPNP_ACL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GUPNP_TYPE_ACL, \
+ GUPnPAcl))
+
+#define GUPNP_IS_ACL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GUPNP_TYPE_ACL))
+
+#define GUPNP_ACL_GET_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+ GUPNP_TYPE_ACL, GUPnPAclInterface))
+
+typedef struct _GUPnPAcl GUPnPAcl;
+typedef struct _GUPnPAclInterface GUPnPAclInterface;
+
+/* Forward declarations to avoid recursive includes */
+typedef struct _GUPnPDevice GUPnPDevice;
+typedef struct _GUPnPService GUPnPService;
+
+struct _GUPnPAclInterface {
+ GTypeInterface parent;
+
+ gboolean (*is_allowed) (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent);
+
+ void (*is_allowed_async) (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ gboolean (*is_allowed_finish) (GUPnPAcl *self,
+ GAsyncResult *res,
+ GError **error);
+
+ gboolean (*can_sync) (GUPnPAcl *self);
+
+ /* future padding */
+ void (* _gupnp_reserved1) (void);
+ void (* _gupnp_reserved2) (void);
+ void (* _gupnp_reserved3) (void);
+ void (* _gupnp_reserved4) (void);
+};
+
+gboolean
+gupnp_acl_is_allowed (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent);
+
+void
+gupnp_acl_is_allowed_async (GUPnPAcl *self,
+ GUPnPDevice *device,
+ GUPnPService *service,
+ const char *path,
+ const char *address,
+ const char *agent,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean
+gupnp_acl_is_allowed_finish (GUPnPAcl *self,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean
+gupnp_acl_can_sync (GUPnPAcl *self);
+
+G_END_DECLS
+
+#endif
diff --git a/libgupnp/gupnp-context-private.h b/libgupnp/gupnp-context-private.h
index 18c4813..212d5e0 100644
--- a/libgupnp/gupnp-context-private.h
+++ b/libgupnp/gupnp-context-private.h
@@ -24,11 +24,18 @@
#include <libsoup/soup.h>
+#include "gupnp-acl-private.h"
+
G_BEGIN_DECLS
G_GNUC_INTERNAL const char *
_gupnp_context_get_server_url (GUPnPContext *context);
+G_GNUC_INTERNAL void
+_gupnp_context_add_server_handler_with_data (GUPnPContext *context,
+ const char *path,
+ AclServerHandler *data);
+
G_END_DECLS
#endif /* __GUPNP_CONTEXT_PRIVATE_H__ */
diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c
index 07ded6d..f8855d4 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -51,6 +51,8 @@
#include <libsoup/soup-address.h>
#include <glib/gstdio.h>
+#include "gupnp-acl.h"
+#include "gupnp-acl-private.h"
#include "gupnp-context.h"
#include "gupnp-context-private.h"
#include "gupnp-error.h"
@@ -61,6 +63,14 @@
#define GUPNP_CONTEXT_DEFAULT_LANGUAGE "en"
static void
+gupnp_acl_server_handler (SoupServer *server,
+ SoupMessage *msg,
+ const char *path,
+ GHashTable *query,
+ SoupClientContext *client,
+ gpointer user_data);
+
+static void
gupnp_context_initable_iface_init (gpointer g_iface,
gpointer iface_data);
@@ -85,6 +95,8 @@ struct _GUPnPContextPrivate {
char *default_language;
GList *host_path_datas;
+
+ GUPnPAcl *acl;
};
enum {
@@ -93,7 +105,8 @@ enum {
PROP_SERVER,
PROP_SESSION,
PROP_SUBSCRIPTION_TIMEOUT,
- PROP_DEFAULT_LANGUAGE
+ PROP_DEFAULT_LANGUAGE,
+ PROP_ACL
};
typedef struct {
@@ -253,6 +266,10 @@ gupnp_context_set_property (GObject *object,
gupnp_context_set_default_language (context,
g_value_get_string (value));
break;
+ case PROP_ACL:
+ gupnp_context_set_acl (context, g_value_get_object (value));
+
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -292,6 +309,11 @@ gupnp_context_get_property (GObject *object,
gupnp_context_get_default_language
(context));
break;
+ case PROP_ACL:
+ g_value_set_object (value,
+ gupnp_context_get_acl (context));
+
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -493,6 +515,17 @@ gupnp_context_class_init (GUPnPContextClass *klass)
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ACL,
+ g_param_spec_object ("acl",
+ "Access control list",
+ "Access control list",
+ GUPNP_TYPE_ACL,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
}
/**
@@ -1281,3 +1314,189 @@ gupnp_context_unhost_path (GUPnPContext *context,
soup_server_remove_handler (server, server_path);
host_path_data_free (path_data);
}
+
+/**
+ * gupnp_context_get_acl:
+ * @context: A #GUPnPContext
+ *
+ * Returns:(transfer none): The access control list associated with this context or %NULL
+ * if no acl is set.
+ **/
+GUPnPAcl *
+gupnp_context_get_acl (GUPnPContext *context)
+{
+ g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
+
+ return context->priv->acl;
+}
+
+/**
+ * gupnp_context_set_acl:
+ * @context: A #GUPnPContext
+ * @acl:(allow-none): The new access control list or %NULL to remove the
+ * current list.
+ **/
+void
+gupnp_context_set_acl (GUPnPContext *context, GUPnPAcl *acl)
+{
+ g_return_if_fail (GUPNP_IS_CONTEXT (context));
+
+ if (context->priv->acl != NULL) {
+ g_object_unref (context->priv->acl);
+ context->priv->acl = NULL;
+ }
+
+ if (acl != NULL)
+ context->priv->acl = g_object_ref (acl);
+
+ g_object_notify (G_OBJECT (context), "acl");
+}
+
+static void
+gupnp_acl_async_callback (GUPnPAcl *acl,
+ GAsyncResult *res,
+ AclAsyncHandler *data)
+{
+ gboolean allowed;
+ GError *error = NULL;
+
+ allowed = gupnp_acl_is_allowed_finish (acl, res, &error);
+ soup_server_unpause_message (data->server, data->message);
+ if (!allowed)
+ soup_message_set_status (data->message, SOUP_STATUS_FORBIDDEN);
+ else
+ data->handler->callback (data->server,
+ data->message,
+ data->path,
+ data->query,
+ data->client,
+ data->handler->user_data);
+
+ acl_async_handler_free (data);
+}
+
+static void
+gupnp_acl_server_handler (SoupServer *server,
+ SoupMessage *msg,
+ const char *path,
+ GHashTable *query,
+ SoupClientContext *client,
+ gpointer user_data)
+{
+ AclServerHandler *handler = (AclServerHandler *) user_data;
+ const char *agent;
+ GUPnPDevice *device = NULL;
+
+ if (handler->service) {
+ g_object_get (handler->service,
+ "root-device", &device,
+ NULL);
+ }
+
+ agent = soup_message_headers_get_one (msg->request_headers,
+ "User-Agent");
+
+ if (gupnp_acl_can_sync (handler->context->priv->acl)) {
+ if (!gupnp_acl_is_allowed (handler->context->priv->acl,
+ device,
+ handler->service,
+ path,
+ soup_client_context_get_host (client),
+ agent)) {
+ soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
+
+ return;
+ }
+ } else {
+ AclAsyncHandler *data;
+
+ data = acl_async_handler_new (server, msg, path, query, client, handler);
+
+ soup_server_pause_message (server, msg);
+ gupnp_acl_is_allowed_async (handler->context->priv->acl,
+ device,
+ handler->service,
+ path,
+ soup_client_context_get_host (client),
+ agent,
+ NULL,
+ (GAsyncReadyCallback) gupnp_acl_async_callback,
+ data);
+
+ return;
+ }
+
+ /* Delegate to orignal callback */
+ handler->callback (server, msg, path, query, client, handler->user_data);
+}
+
+/**
+ * gupnp_context_add_server_handler:
+ * @context: a #GUPnPContext
+ * @use_acl: %TRUE, if the path should query the GUPnPContext::acl before
+ * serving the resource, %FALSE otherwise.
+ * @path: the toplevel path for the handler.
+ * @callback: callback to invoke for requests under @path
+ * @user_data:
+ * @destroy:
+ *
+ * Add a #SoupServerCallback to the #GUPnPContext<!-- -->'s #SoupServer.
+ *
+ */
+void
+gupnp_context_add_server_handler (GUPnPContext *context,
+ gboolean use_acl,
+ const char *path,
+ SoupServerCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (GUPNP_IS_CONTEXT (context));
+
+ if (use_acl) {
+ AclServerHandler *handler;
+ handler = acl_server_handler_new (NULL, context, callback, user_data, destroy);
+ soup_server_add_handler (context->priv->server,
+ path,
+ gupnp_acl_server_handler,
+ handler,
+ (GDestroyNotify) acl_server_handler_free);
+ } else
+ soup_server_add_handler (context->priv->server,
+ path,
+ callback,
+ user_data,
+ destroy);
+}
+
+void
+_gupnp_context_add_server_handler_with_data (GUPnPContext *context,
+ const char *path,
+ AclServerHandler *handler)
+{
+ g_return_if_fail (GUPNP_IS_CONTEXT (context));
+
+ soup_server_add_handler (context->priv->server,
+ path,
+ gupnp_acl_server_handler,
+ handler,
+ (GDestroyNotify) acl_server_handler_free);
+}
+
+/**
+ * gupnp_context_remove_server_handler:
+ * @context: a #GUPnPContext
+ * @use_acl: %TRUE, if the path should query the GUPnPContext::acl before
+ * serving the resource, %FALSE otherwise.
+ * @path: the toplevel path for the handler.
+ *
+ * Add a #SoupServerCallback to the #GUPnPContext<!-- -->'s #SoupServer.
+ *
+ */
+void
+gupnp_context_remove_server_handler (GUPnPContext *context, const char *path)
+{
+ g_return_if_fail (GUPNP_IS_CONTEXT (context));
+
+ soup_server_remove_handler (context->priv->server, path);
+}
diff --git a/libgupnp/gupnp-context.h b/libgupnp/gupnp-context.h
index a2e2f9e..233d2fa 100644
--- a/libgupnp/gupnp-context.h
+++ b/libgupnp/gupnp-context.h
@@ -26,6 +26,8 @@
#include <libsoup/soup-server.h>
#include <libsoup/soup-session.h>
+#include "gupnp-acl.h"
+
G_BEGIN_DECLS
GType
@@ -129,6 +131,20 @@ void
gupnp_context_unhost_path (GUPnPContext *context,
const char *server_path);
+GUPnPAcl *
+gupnp_context_get_acl (GUPnPContext *context);
+
+void
+gupnp_context_set_acl (GUPnPContext *context,
+ GUPnPAcl *acl);
+
+void
+gupnp_context_add_server_handler (GUPnPContext *context,
+ gboolean use_acl,
+ const char *path,
+ SoupServerCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
G_END_DECLS
#endif /* __GUPNP_CONTEXT_H__ */
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index 684dbd1..f545dd4 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -31,11 +31,13 @@
#include <gmodule.h>
#include <libsoup/soup-date.h>
#include <string.h>
+
#include "gupnp-service.h"
#include "gupnp-root-device.h"
#include "gupnp-context-private.h"
#include "gupnp-marshal.h"
#include "gupnp-error.h"
+#include "gupnp-acl.h"
#include "http-headers.h"
#include "gena-protocol.h"
#include "xml-util.h"
@@ -1302,6 +1304,8 @@ subscription_server_handler (G_GNUC_UNUSED SoupServer *server,
gpointer user_data)
{
GUPnPService *service;
+ GUPnPContext *context;
+ GUPnPAcl *acl;
const char *callback, *nt, *sid;
service = GUPNP_SERVICE (user_data);
@@ -1432,7 +1436,7 @@ gupnp_service_constructor (GType type,
GObject *object;
GUPnPServiceInfo *info;
GUPnPContext *context;
- SoupServer *server;
+ AclServerHandler *handler;
char *url;
char *path;
@@ -1443,7 +1447,7 @@ gupnp_service_constructor (GType type,
n_construct_params,
construct_params);
- info = GUPNP_SERVICE_INFO (object);
+ info = GUPNP_SERVICE_INFO (object);
/* Get introspection and save state variable names */
gupnp_service_info_get_introspection_async (info,
@@ -1452,21 +1456,28 @@ gupnp_service_constructor (GType type,
/* Get server */
context = gupnp_service_info_get_context (info);
- server = gupnp_context_get_server (context);
/* Run listener on controlURL */
url = gupnp_service_info_get_control_url (info);
path = path_from_url (url);
- soup_server_add_handler (server, path,
- control_server_handler, object, NULL);
+ handler = acl_server_handler_new (GUPNP_SERVICE (object),
+ context,
+ control_server_handler,
+ g_object_ref (object),
+ g_object_unref);
+ _gupnp_context_add_server_handler_with_data (context, path, handler);
g_free (path);
g_free (url);
/* Run listener on eventSubscriptionURL */
url = gupnp_service_info_get_event_subscription_url (info);
path = path_from_url (url);
- soup_server_add_handler (server, path,
- subscription_server_handler, object, NULL);
+ handler = acl_server_handler_new (GUPNP_SERVICE (object),
+ context,
+ subscription_server_handler,
+ g_object_ref (object),
+ g_object_unref);
+ _gupnp_context_add_server_handler_with_data (context, path, handler);
g_free (path);
g_free (url);
@@ -1553,7 +1564,6 @@ gupnp_service_dispose (GObject *object)
GObjectClass *object_class;
GUPnPServiceInfo *info;
GUPnPContext *context;
- SoupServer *server;
char *url;
char *path;
@@ -1562,19 +1572,18 @@ gupnp_service_dispose (GObject *object)
/* Get server */
info = GUPNP_SERVICE_INFO (service);
context = gupnp_service_info_get_context (info);
- server = gupnp_context_get_server (context);
/* Remove listener on controlURL */
url = gupnp_service_info_get_control_url (info);
path = path_from_url (url);
- soup_server_remove_handler (server, path);
+ gupnp_context_remove_server_handler (context, path);
g_free (path);
g_free (url);
/* Remove listener on eventSubscriptionURL */
url = gupnp_service_info_get_event_subscription_url (info);
path = path_from_url (url);
- soup_server_remove_handler (server, path);
+ gupnp_context_remove_server_handler (context, path);
g_free (path);
g_free (url);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]