[gupnp/wip/acl: 14/15] WIP: Initial ACL implementation
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp/wip/acl: 14/15] WIP: Initial ACL implementation
- Date: Sun, 19 Jan 2014 12:44:50 +0000 (UTC)
commit b5a64094db8a5aa98ebe15e197ba60dc1cd9677a
Author: Jens Georg <mail jensge org>
Date: Sun Nov 24 01:25:05 2013 +0100
WIP: Initial ACL implementation
libgupnp/Makefile.am | 4 +-
libgupnp/gupnp-acl.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
libgupnp/gupnp-acl.h | 98 ++++++++++++++++++++++++++++++++++++
libgupnp/gupnp-context.c | 59 +++++++++++++++++++++-
libgupnp/gupnp-context.h | 8 +++
libgupnp/gupnp-service.c | 32 ++++++++++++
6 files changed, 323 insertions(+), 2 deletions(-)
---
diff --git a/libgupnp/Makefile.am b/libgupnp/Makefile.am
index 6d30acb..9a16668 100644
--- a/libgupnp/Makefile.am
+++ b/libgupnp/Makefile.am
@@ -44,7 +44,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 \
@@ -63,6 +64,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 \
diff --git a/libgupnp/gupnp-acl.c b/libgupnp/gupnp-acl.c
new file mode 100644
index 0000000..57433fc
--- /dev/null
+++ b/libgupnp/gupnp-acl.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 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"
+
+G_DEFINE_INTERFACE(GUPnPAcl, gupnp_acl, 0)
+
+static void
+gupnp_acl_default_init (GUPnPAclInterface *klass)
+{
+}
+
+/**
+ * gupnp_acl_is_allowed:
+ *
+ * Check whether an IP address is allowed to access this resource.
+ *
+ * @self: an instance of #GUPnPAcl
+ * @address: IP address of the peer.
+ * @returns: %TRUE if the peer is allowed, %FALSE otherwise
+ *
+ * Since: 0.21.0
+ */
+gboolean
+gupnp_acl_is_allowed (GUPnPAcl *self, const char *address)
+{
+ g_return_val_if_fail (GUPNP_IS_ACL (self), FALSE);
+
+ return GUPNP_ACL_GET_INTERFACE (self)->is_allowed (self, address);
+}
+
+/**
+ * gupnp_acl_is_allowed_async:
+ *
+ * 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.
+ *
+ * @self: a #GUPnPAcl
+ * @address: IP address of the peer
+ * @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.
+ *
+ * Since: 0.21.0
+ */
+void
+gupnp_acl_is_allowed_async (GUPnPAcl *self,
+ const char *address,
+ GCancellable *cancellable,
+ GAsyncReadyCallback *callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GUPNP_IS_ACL (self));
+
+ GUPNP_ACL_GET_INTERFACE (self)->is_allowed_async (self,
+ address,
+ 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.21.0
+ */
+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:
+ * Check whether gupnp_acl_is_allowed_async() is supported.
+ *
+ * @self: A #GUPnPAcl
+ * @returns: %TRUE, if gupnp_acl_is_allowed_async() is supported, %FALSE
+ * otherwise.
+ *
+ * Since: 0.21.0
+ */
+gboolean
+gupnp_acl_can_sync (GUPnPAcl *self)
+{
+ g_return_if_fail (GUPNP_IS_ACL (self));
+
+ return GUPNP_ACL_GET_INTERFACE (self)->can_sync (self);
+}
diff --git a/libgupnp/gupnp-acl.h b/libgupnp/gupnp-acl.h
new file mode 100644
index 0000000..42bfc05
--- /dev/null
+++ b/libgupnp/gupnp-acl.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 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;
+
+struct _GUPnPAclInterface {
+ GTypeInterface parent;
+
+ gboolean (*is_allowed) (GUPnPAcl *self,
+ const char *address);
+
+ void (*is_allowed_async) (GUPnPAcl *self,
+ const char *address,
+ 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,
+ const char *address);
+
+void
+gupnp_acl_is_allowed_async (GUPnPAcl *self,
+ const char *address,
+ 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.c b/libgupnp/gupnp-context.c
index 7949880..3046c84 100644
--- a/libgupnp/gupnp-context.c
+++ b/libgupnp/gupnp-context.c
@@ -49,6 +49,7 @@
#include <libsoup/soup-address.h>
#include <glib/gstdio.h>
+#include "gupnp-acl.h"
#include "gupnp-context.h"
#include "gupnp-context-private.h"
#include "gupnp-error.h"
@@ -83,6 +84,8 @@ struct _GUPnPContextPrivate {
char *default_language;
GList *host_path_datas;
+
+ GUPnPAcl *acl;
};
enum {
@@ -91,7 +94,8 @@ enum {
PROP_SERVER,
PROP_SESSION,
PROP_SUBSCRIPTION_TIMEOUT,
- PROP_DEFAULT_LANGUAGE
+ PROP_DEFAULT_LANGUAGE,
+ PROP_ACL
};
typedef struct {
@@ -251,6 +255,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;
@@ -290,6 +298,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;
@@ -491,6 +504,16 @@ 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_STATIC_STRINGS));
}
/**
@@ -1279,3 +1302,37 @@ 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 = g_object_ref (acl);
+
+ g_object_notify (G_OBJECT (context), "acl");
+}
diff --git a/libgupnp/gupnp-context.h b/libgupnp/gupnp-context.h
index a2e2f9e..d0556e9 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,12 @@ 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);
G_END_DECLS
#endif /* __GUPNP_CONTEXT_H__ */
diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c
index 684dbd1..faacc37 100644
--- a/libgupnp/gupnp-service.c
+++ b/libgupnp/gupnp-service.c
@@ -36,6 +36,7 @@
#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"
@@ -914,6 +915,7 @@ control_server_handler (SoupServer *server,
char *action_name;
char *end;
GUPnPServiceAction *action;
+ GUPnPAcl *acl;
service = GUPNP_SERVICE (user_data);
@@ -939,6 +941,20 @@ control_server_handler (SoupServer *server,
context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));
+ acl = gupnp_context_get_acl (context);
+
+ if (acl) {
+ if (gupnp_acl_can_sync (acl)) {
+ if (!gupnp_acl_is_allowed (acl, "127.0.0.1")) {
+ soup_message_set_status (msg, SOUP_STATUS_PROXY_UNAUTHORIZED);
+
+ return;
+ } else {
+ g_warning ("TBD: Handle async ACL");
+ }
+ }
+ }
+
/* Get action name */
soap_action = soup_message_headers_get_one (msg->request_headers,
"SOAPAction");
@@ -1302,10 +1318,26 @@ 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);
+ context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));
+ acl = gupnp_context_get_acl (context);
+ if (acl) {
+ if (gupnp_acl_can_sync (acl)) {
+ if (!gupnp_acl_is_allowed (acl, "127.0.0.1")) {
+ soup_message_set_status (msg, SOUP_STATUS_PROXY_UNAUTHORIZED);
+
+ return;
+ } else {
+ g_warning ("TBD: Handle async ACL");
+ }
+ }
+ }
+
callback = soup_message_headers_get_one (msg->request_headers,
"Callback");
nt = soup_message_headers_get_one (msg->request_headers, "NT");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]