diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.am | 19 | ||||
-rw-r--r-- | configure.ac | 18 | ||||
-rw-r--r-- | marshallers/mm-marshal.list | 1 | ||||
-rw-r--r-- | org.freedesktop.ModemManager.conf.nopolkit (renamed from org.freedesktop.ModemManager.conf) | 3 | ||||
-rw-r--r-- | org.freedesktop.ModemManager.conf.polkit | 154 | ||||
-rw-r--r-- | src/Makefile.am | 24 | ||||
-rw-r--r-- | src/mm-auth-provider-factory.c | 45 | ||||
-rw-r--r-- | src/mm-auth-provider-polkit.c | 153 | ||||
-rw-r--r-- | src/mm-auth-provider-polkit.h | 43 | ||||
-rw-r--r-- | src/mm-auth-provider.c | 300 | ||||
-rw-r--r-- | src/mm-auth-provider.h | 84 | ||||
-rw-r--r-- | src/mm-auth-request-polkit.c | 175 | ||||
-rw-r--r-- | src/mm-auth-request-polkit.h | 53 | ||||
-rw-r--r-- | src/mm-auth-request.c | 182 | ||||
-rw-r--r-- | src/mm-auth-request.h | 72 | ||||
-rw-r--r-- | src/mm-errors.c | 1 | ||||
-rw-r--r-- | src/mm-errors.h | 3 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 125 | ||||
-rw-r--r-- | src/mm-modem-base.c | 46 | ||||
-rw-r--r-- | src/mm-modem-cdma.c | 35 | ||||
-rw-r--r-- | src/mm-modem-gsm-card.c | 263 | ||||
-rw-r--r-- | src/mm-modem-gsm-network.c | 32 | ||||
-rw-r--r-- | src/mm-modem-gsm-sms.c | 383 | ||||
-rw-r--r-- | src/mm-modem.c | 48 | ||||
-rw-r--r-- | src/mm-modem.h | 33 |
26 files changed, 2205 insertions, 92 deletions
@@ -23,6 +23,7 @@ libtool *-glue.h *.tar.bz2 org.freedesktop.ModemManager.service +org.freedesktop.ModemManager.conf ModemManager.pc marshallers/mm-marshal.[ch] src/modem-manager @@ -30,6 +31,7 @@ docs/spec.html callouts/mm-modem-probe test/lsudev src/tests/test-modem-helpers +policy/org.freedesktop.modem-manager.policy libqcdm/tests/test-qcdm diff --git a/Makefile.am b/Makefile.am index 0153b10e..c2639508 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,9 +21,23 @@ endif SUBDIRS = marshallers libqcdm src plugins introspection po policy test +if WITH_POLKIT +SUBDIRS += policy +endif + dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = org.freedesktop.ModemManager.conf +dbusservice_file_polkit = org.freedesktop.ModemManager.conf.polkit +dbusservice_file_nopolkit = org.freedesktop.ModemManager.conf.nopolkit + +org.freedesktop.ModemManager.conf: +if WITH_POLKIT + cp -f $(top_srcdir)/$(dbusservice_file_polkit) $(dbusservice_DATA) +else + cp -f $(top_srcdir)/$(dbusservice_file_nopolkit) $(dbusservice_DATA) +endif + dbusactivationdir = $(datadir)/dbus-1/system-services dbusactivation_in_files = org.freedesktop.ModemManager.service.in dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service) @@ -53,8 +67,9 @@ DISTCLEANFILES = \ EXTRA_DIST = \ doc-generator.xsl \ - $(dbusservice_DATA) \ $(dbusactivation_in_files) \ - $(INTLTOOL_FILES) + $(INTLTOOL_FILES) \ + $(dbusservice_file_polkit) \ + $(dbusservice_file_nopolkit) ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index cc2f2f62..6f6621d7 100644 --- a/configure.ac +++ b/configure.ac @@ -50,6 +50,22 @@ AC_SUBST(UDEV_BASE_DIR) GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` AC_SUBST(GLIB_GENMARSHAL) +# PolicyKit +AC_ARG_WITH(polkit, AS_HELP_STRING([--with-polkit], [Build with PolicyKit support])) +AM_CONDITIONAL(WITH_POLKIT, test "x$with_polkit" = "xyes") +case $with_polkit in + yes) + with_polkit=yes + PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= 0.95) + AC_DEFINE(WITH_POLKIT, 1, [Define if you want to use PolicyKit]) + AC_SUBST(POLKIT_CFLAGS) + AC_SUBST(POLKIT_LIBS) + ;; + *) + with_polkit=no + ;; +esac + # PPPD AC_CHECK_HEADERS(pppd/pppd.h, have_pppd_headers="yes", have_pppd_headers="no") AM_CONDITIONAL(HAVE_PPPD_H, test "x$have_pppd_headers" = "xyes") @@ -119,4 +135,6 @@ echo Building documentation: ${with_docs} echo echo Building PPP-enabled tests: ${have_pppd_headers} echo +echo Building with PolicyKit support: ${with_polkit} +echo diff --git a/marshallers/mm-marshal.list b/marshallers/mm-marshal.list index 474d704d..c209bbbf 100644 --- a/marshallers/mm-marshal.list +++ b/marshallers/mm-marshal.list @@ -5,4 +5,5 @@ VOID:UINT,BOOLEAN VOID:UINT,UINT VOID:UINT,UINT,UINT VOID:STRING,BOXED +VOID:POINTER,UINT diff --git a/org.freedesktop.ModemManager.conf b/org.freedesktop.ModemManager.conf.nopolkit index 5d62d7a9..2f331613 100644 --- a/org.freedesktop.ModemManager.conf +++ b/org.freedesktop.ModemManager.conf.nopolkit @@ -2,6 +2,8 @@ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> + <!-- This config allows anyone to control ModemManager --> + <policy context="default"> <allow send_destination="org.freedesktop.ModemManager"/> </policy> @@ -12,3 +14,4 @@ <limit name="max_replies_per_connection">512</limit> </busconfig> + diff --git a/org.freedesktop.ModemManager.conf.polkit b/org.freedesktop.ModemManager.conf.polkit new file mode 100644 index 00000000..25490e33 --- /dev/null +++ b/org.freedesktop.ModemManager.conf.polkit @@ -0,0 +1,154 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy context="default"> + <deny send_destination="org.freedesktop.ModemManager"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.DBus.Introspectable"/> + + <!-- Methods listed here are explicitly allowed or PolicyKit protected. + The rest are restricted to root for security. + --> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager" + send_member="EnumerateDevices"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.DBus.Properties"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem" + send_member="GetInfo"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Cdma" + send_member="GetSignalQuality"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Cdma" + send_member="GetServingSystem"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Cdma" + send_member="GetRegistrationState"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Cdma" + send_member="GetEsn"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Network" + send_member="GetSignalQuality"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Network" + send_member="GetBand"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Network" + send_member="GetNetworkMode"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Network" + send_member="GetRegistrationInfo"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Network" + send_member="Scan"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="GetImei"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="GetImsi"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="SendPuk"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="SendPin"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="EnablePin"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Card" + send_member="ChangePin"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="Add"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="Delete"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="Get"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="List"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="Find"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.Contacts" + send_member="GetCount"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="Delete"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="Get"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="List"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="Save"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="Send"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="SendFromStorage"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="SetIndication"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="GetSmsc"/> + + <allow send_destination="org.freedesktop.ModemManager" + send_interface="org.freedesktop.ModemManager.Modem.Gsm.SMS" + send_member="SetSmsc"/> + </policy> + + <policy user="root"> + <allow own="org.freedesktop.ModemManager"/> + <allow send_destination="org.freedesktop.ModemManager"/> + </policy> + + <limit name="max_replies_per_connection">512</limit> +</busconfig> + diff --git a/src/Makefile.am b/src/Makefile.am index 15b91bd5..3d938063 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,10 @@ modem_manager_CPPFLAGS = \ -I${top_builddir}/marshallers \ -DPLUGINDIR=\"$(pkglibdir)\" +if WITH_POLKIT +modem_manager_CPPFLAGS += $(POLKIT_CFLAGS) +endif + modem_manager_LDADD = \ $(MM_LIBS) \ $(GUDEV_LIBS) \ @@ -27,10 +31,30 @@ modem_manager_LDADD = \ $(top_builddir)/libqcdm/src/libqcdm.la \ $(builddir)/libmodem-helpers.la +if WITH_POLKIT +modem_manager_LDADD += $(POLKIT_LIBS) +endif + +auth_sources = \ + mm-auth-request.c \ + mm-auth-request.h \ + mm-auth-provider.h \ + mm-auth-provider.c \ + mm-auth-provider-factory.c + +if WITH_POLKIT +auth_sources += \ + mm-auth-request-polkit.c \ + mm-auth-request-polkit.h \ + mm-auth-provider-polkit.c \ + mm-auth-provider-polkit.h +endif + modem_manager_SOURCES = \ main.c \ mm-callback-info.c \ mm-callback-info.h \ + $(auth_sources) \ mm-manager.c \ mm-manager.h \ mm-modem.c \ diff --git a/src/mm-auth-provider-factory.c b/src/mm-auth-provider-factory.c new file mode 100644 index 00000000..356dcf21 --- /dev/null +++ b/src/mm-auth-provider-factory.c @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include <string.h> + +#include "config.h" +#include "mm-auth-provider.h" + +GObject *mm_auth_provider_new (void); + +#ifdef WITH_POLKIT +#define IN_AUTH_PROVIDER_FACTORY_C +#include "mm-auth-provider-polkit.h" +#undef IN_AUTH_PROVIDER_FACTORY_C +#endif + +MMAuthProvider * +mm_auth_provider_get (void) +{ + static MMAuthProvider *singleton; + + if (!singleton) { +#if WITH_POLKIT + singleton = (MMAuthProvider *) mm_auth_provider_polkit_new (); +#else + singleton = (MMAuthProvider *) mm_auth_provider_new (); +#endif + } + + g_assert (singleton); + return singleton; +} + diff --git a/src/mm-auth-provider-polkit.c b/src/mm-auth-provider-polkit.c new file mode 100644 index 00000000..c457eaf4 --- /dev/null +++ b/src/mm-auth-provider-polkit.c @@ -0,0 +1,153 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include <polkit/polkit.h> + +#include "mm-auth-request-polkit.h" +#include "mm-auth-provider-polkit.h" + +G_DEFINE_TYPE (MMAuthProviderPolkit, mm_auth_provider_polkit, MM_TYPE_AUTH_PROVIDER) + +#define MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkitPrivate)) + +typedef struct { + PolkitAuthority *authority; + guint auth_changed_id; +} MMAuthProviderPolkitPrivate; + +enum { + PROP_NAME = 1000, +}; + +/*****************************************************************************/ + +GObject * +mm_auth_provider_polkit_new (void) +{ + return g_object_new (MM_TYPE_AUTH_PROVIDER_POLKIT, NULL); +} + +/*****************************************************************************/ + +static void +pk_authority_changed_cb (GObject *object, gpointer user_data) +{ + /* Let clients know they should re-check their authorization */ +} + +/*****************************************************************************/ + +static MMAuthRequest * +real_create_request (MMAuthProvider *provider, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify) +{ + MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (provider); + + return (MMAuthRequest *) mm_auth_request_polkit_new (priv->authority, + authorization, + owner, + context, + callback, + callback_data, + notify); +} + +/*****************************************************************************/ + +static void +mm_auth_provider_polkit_init (MMAuthProviderPolkit *self) +{ + MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (self); + + priv->authority = polkit_authority_get (); + if (priv->authority) { + priv->auth_changed_id = g_signal_connect (priv->authority, + "changed", + G_CALLBACK (pk_authority_changed_cb), + self); + } else + g_warning ("%s: failed to create PolicyKit authority.", __func__); +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_NAME: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, "polkit"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + MMAuthProviderPolkit *self = MM_AUTH_PROVIDER_POLKIT (object); + MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (self); + + if (priv->auth_changed_id) { + g_signal_handler_disconnect (priv->authority, priv->auth_changed_id); + priv->auth_changed_id = 0; + } + + G_OBJECT_CLASS (mm_auth_provider_polkit_parent_class)->dispose (object); +} + +static void +mm_auth_provider_polkit_class_init (MMAuthProviderPolkitClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + MMAuthProviderClass *ap_class = MM_AUTH_PROVIDER_CLASS (class); + + mm_auth_provider_polkit_parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (MMAuthProviderPolkitPrivate)); + + /* Virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->dispose = dispose; + ap_class->create_request = real_create_request; + + /* Properties */ + g_object_class_override_property (object_class, PROP_NAME, MM_AUTH_PROVIDER_NAME); +} + diff --git a/src/mm-auth-provider-polkit.h b/src/mm-auth-provider-polkit.h new file mode 100644 index 00000000..a52c56df --- /dev/null +++ b/src/mm-auth-provider-polkit.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#ifndef MM_AUTH_PROVIDER_POLKIT_H +#define MM_AUTH_PROVIDER_POLKIT_H + +#include <glib-object.h> + +#include "mm-auth-provider.h" + +#define MM_TYPE_AUTH_PROVIDER_POLKIT (mm_auth_provider_polkit_get_type ()) +#define MM_AUTH_PROVIDER_POLKIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkit)) +#define MM_AUTH_PROVIDER_POLKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkitClass)) +#define MM_IS_AUTH_PROVIDER_POLKIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_AUTH_PROVIDER_POLKIT)) +#define MM_IS_AUTH_PROVIDER_POLKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_AUTH_PROVIDER_POLKIT)) +#define MM_AUTH_PROVIDER_POLKIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkitClass)) + +typedef struct { + MMAuthProvider parent; +} MMAuthProviderPolkit; + +typedef struct { + MMAuthProviderClass parent; +} MMAuthProviderPolkitClass; + +GType mm_auth_provider_polkit_get_type (void); + +GObject *mm_auth_provider_polkit_new (void); + +#endif /* MM_AUTH_PROVIDER_POLKIT_H */ + diff --git a/src/mm-auth-provider.c b/src/mm-auth-provider.c new file mode 100644 index 00000000..ceff9adf --- /dev/null +++ b/src/mm-auth-provider.c @@ -0,0 +1,300 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include <string.h> + +#include "mm-marshal.h" +#include "mm-auth-provider.h" + +GObject *mm_auth_provider_new (void); + +G_DEFINE_TYPE (MMAuthProvider, mm_auth_provider, G_TYPE_OBJECT) + +#define MM_AUTH_PROVIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AUTH_PROVIDER, MMAuthProviderPrivate)) + +typedef struct { + GHashTable *requests; + guint process_id; +} MMAuthProviderPrivate; + +enum { + PROP_0, + PROP_NAME, + LAST_PROP +}; + +/*****************************************************************************/ + +GObject * +mm_auth_provider_new (void) +{ + return g_object_new (MM_TYPE_AUTH_PROVIDER, NULL); +} + +/*****************************************************************************/ + +static void +remove_requests (MMAuthProvider *self, GSList *remove) +{ + MMAuthProviderPrivate *priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + MMAuthRequest *req; + + while (remove) { + req = MM_AUTH_REQUEST (remove->data); + g_hash_table_remove (priv->requests, req); + remove = g_slist_remove (remove, req); + } +} + +void +mm_auth_provider_cancel_request (MMAuthProvider *provider, MMAuthRequest *req) +{ + MMAuthProviderPrivate *priv; + + g_return_if_fail (provider != NULL); + g_return_if_fail (MM_IS_AUTH_PROVIDER (provider)); + g_return_if_fail (req != NULL); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + + g_return_if_fail (g_hash_table_lookup (priv->requests, req) != NULL); + g_hash_table_remove (priv->requests, req); +} + +void +mm_auth_provider_cancel_for_owner (MMAuthProvider *self, GObject *owner) +{ + MMAuthProviderPrivate *priv; + GHashTableIter iter; + MMAuthRequest *req; + gpointer value; + GSList *remove = NULL; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AUTH_PROVIDER (self)); + + /* Find all requests from this owner */ + priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + req = MM_AUTH_REQUEST (value); + if (mm_auth_request_get_owner (req) == owner) + remove = g_slist_prepend (remove, req); + } + + /* And cancel/remove them */ + remove_requests (self, remove); +} + +/*****************************************************************************/ + + +static MMAuthRequest * +real_create_request (MMAuthProvider *provider, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify) +{ + return (MMAuthRequest *) mm_auth_request_new (0, + authorization, + owner, + context, + callback, + callback_data, + notify); +} + +static gboolean +process_complete_requests (gpointer user_data) +{ + MMAuthProvider *self = MM_AUTH_PROVIDER (user_data); + MMAuthProviderPrivate *priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + GHashTableIter iter; + gpointer value; + GSList *remove = NULL; + MMAuthRequest *req; + + priv->process_id = 0; + + /* Call finished request's callbacks */ + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + req = MM_AUTH_REQUEST (value); + + if (mm_auth_request_get_authorization (req) != MM_AUTH_RESULT_UNKNOWN) { + mm_auth_request_callback (req); + remove = g_slist_prepend (remove, req); + } + } + + /* And remove those requests from our pending request list */ + remove_requests (self, remove); + + return FALSE; +} + +static void +auth_result_cb (MMAuthRequest *req, gpointer user_data) +{ + MMAuthProvider *self = MM_AUTH_PROVIDER (user_data); + MMAuthProviderPrivate *priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + + /* Process results from an idle handler */ + if (priv->process_id == 0) + priv->process_id = g_idle_add (process_complete_requests, self); +} + +#define RESULT_SIGID_TAG "result-sigid" + +MMAuthRequest * +mm_auth_provider_request_auth (MMAuthProvider *self, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error) +{ + MMAuthProviderPrivate *priv; + MMAuthRequest *req; + guint32 sigid; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (MM_IS_AUTH_PROVIDER (self), 0); + g_return_val_if_fail (authorization != NULL, 0); + g_return_val_if_fail (callback != NULL, 0); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + + req = MM_AUTH_PROVIDER_GET_CLASS (self)->create_request (self, + authorization, + owner, + context, + callback, + callback_data, + notify); + g_assert (req); + + sigid = g_signal_connect (req, "result", G_CALLBACK (auth_result_cb), self); + g_object_set_data (G_OBJECT (req), RESULT_SIGID_TAG, GUINT_TO_POINTER (sigid)); + + g_hash_table_insert (priv->requests, req, req); + if (!mm_auth_request_authenticate (req, error)) { + /* Error */ + g_hash_table_remove (priv->requests, req); + return NULL; + } + + return req; +} + +/*****************************************************************************/ + +static void +dispose_auth_request (gpointer data) +{ + MMAuthRequest *req = MM_AUTH_REQUEST (data); + guint sigid; + + sigid = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (req), RESULT_SIGID_TAG)); + if (sigid) + g_signal_handler_disconnect (req, sigid); + mm_auth_request_dispose (req); + g_object_unref (req); +} + +static void +mm_auth_provider_init (MMAuthProvider *self) +{ + MMAuthProviderPrivate *priv = MM_AUTH_PROVIDER_GET_PRIVATE (self); + + priv->requests = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + dispose_auth_request); +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_NAME: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#define NULL_PROVIDER "open" + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, NULL_PROVIDER); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + MMAuthProviderPrivate *priv = MM_AUTH_PROVIDER_GET_PRIVATE (object); + + if (priv->process_id) + g_source_remove (priv->process_id); + g_hash_table_destroy (priv->requests); + + G_OBJECT_CLASS (mm_auth_provider_parent_class)->dispose (object); +} + +static void +mm_auth_provider_class_init (MMAuthProviderClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + mm_auth_provider_parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (MMAuthProviderPrivate)); + + /* Virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->dispose = dispose; + class->create_request = real_create_request; + + /* Properties */ + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string (MM_AUTH_PROVIDER_NAME, + "Name", + "Provider name", + NULL_PROVIDER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + diff --git a/src/mm-auth-provider.h b/src/mm-auth-provider.h new file mode 100644 index 00000000..94edc44d --- /dev/null +++ b/src/mm-auth-provider.h @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#ifndef MM_AUTH_PROVIDER_H +#define MM_AUTH_PROVIDER_H + +#include <glib-object.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "mm-auth-request.h" + +/* Authorizations */ +#define MM_AUTHORIZATION_DEVICE "org.freedesktop.ModemManager.Device" +#define MM_AUTHORIZATION_CONTACTS "org.freedesktop.ModemManager.Contacts" +#define MM_AUTHORIZATION_SMS "org.freedesktop.ModemManager.SMS" +/******************/ + + +#define MM_TYPE_AUTH_PROVIDER (mm_auth_provider_get_type ()) +#define MM_AUTH_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_AUTH_PROVIDER, MMAuthProvider)) +#define MM_AUTH_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_AUTH_PROVIDER, MMAuthProviderClass)) +#define MM_IS_AUTH_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_AUTH_PROVIDER)) +#define MM_IS_AUTH_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_AUTH_PROVIDER)) +#define MM_AUTH_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_AUTH_PROVIDER, MMAuthProviderClass)) + +#define MM_AUTH_PROVIDER_NAME "name" + +typedef struct { + GObject parent; +} MMAuthProvider; + +typedef struct { + GObjectClass parent; + + MMAuthRequest * (*create_request) (MMAuthProvider *provider, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify); +} MMAuthProviderClass; + +GType mm_auth_provider_get_type (void); + +/* Don't do anything clever from the notify callback... */ +MMAuthRequest *mm_auth_provider_request_auth (MMAuthProvider *provider, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + +void mm_auth_provider_cancel_for_owner (MMAuthProvider *provider, + GObject *owner); + +/* Subclass API */ + +/* To get an auth provider instance, implemented in mm-auth-provider-factory.c */ +MMAuthProvider *mm_auth_provider_get (void); + +/* schedules the request's completion */ +void mm_auth_provider_finish_request (MMAuthProvider *provider, + MMAuthRequest *req, + MMAuthResult result); + +void mm_auth_provider_cancel_request (MMAuthProvider *provider, MMAuthRequest *req); + +#endif /* MM_AUTH_PROVIDER_H */ + diff --git a/src/mm-auth-request-polkit.c b/src/mm-auth-request-polkit.c new file mode 100644 index 00000000..2a96bfec --- /dev/null +++ b/src/mm-auth-request-polkit.c @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include <glib.h> +#include <gio/gio.h> + +#include "mm-auth-request-polkit.h" + +G_DEFINE_TYPE (MMAuthRequestPolkit, mm_auth_request_polkit, MM_TYPE_AUTH_REQUEST) + +#define MM_AUTH_REQUEST_POLKIT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AUTH_REQUEST_POLKIT, MMAuthRequestPolkitPrivate)) + +typedef struct { + PolkitAuthority *authority; + GCancellable *cancellable; + PolkitSubject *subject; +} MMAuthRequestPolkitPrivate; + +/*****************************************************************************/ + +GObject * +mm_auth_request_polkit_new (PolkitAuthority *authority, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify) +{ + GObject *obj; + MMAuthRequestPolkitPrivate *priv; + char *sender; + + g_return_val_if_fail (authorization != NULL, NULL); + g_return_val_if_fail (owner != NULL, NULL); + g_return_val_if_fail (callback != NULL, NULL); + g_return_val_if_fail (context != NULL, NULL); + + obj = mm_auth_request_new (MM_TYPE_AUTH_REQUEST_POLKIT, + authorization, + owner, + context, + callback, + callback_data, + notify); + if (obj) { + priv = MM_AUTH_REQUEST_POLKIT_GET_PRIVATE (obj); + priv->authority = authority; + priv->cancellable = g_cancellable_new (); + + sender = dbus_g_method_get_sender (context); + priv->subject = polkit_system_bus_name_new (sender); + g_free (sender); + } + + return obj; +} + +/*****************************************************************************/ + +static void +pk_auth_cb (GObject *object, GAsyncResult *result, gpointer user_data) +{ + MMAuthRequestPolkit *self = user_data; + MMAuthRequestPolkitPrivate *priv; + PolkitAuthorizationResult *pk_result; + GError *error = NULL; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AUTH_REQUEST_POLKIT (self)); + + priv = MM_AUTH_REQUEST_POLKIT_GET_PRIVATE (self); + if (!g_cancellable_is_cancelled (priv->cancellable)) { + pk_result = polkit_authority_check_authorization_finish (priv->authority, + result, + &error); + if (error) { + mm_auth_request_set_result (MM_AUTH_REQUEST (self), MM_AUTH_RESULT_INTERNAL_FAILURE); + g_warning ("%s: PolicyKit authentication error: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } else if (polkit_authorization_result_get_is_authorized (pk_result)) + mm_auth_request_set_result (MM_AUTH_REQUEST (self), MM_AUTH_RESULT_AUTHORIZED); + else if (polkit_authorization_result_get_is_challenge (pk_result)) + mm_auth_request_set_result (MM_AUTH_REQUEST (self), MM_AUTH_RESULT_CHALLENGE); + else + mm_auth_request_set_result (MM_AUTH_REQUEST (self), MM_AUTH_RESULT_NOT_AUTHORIZED); + + g_signal_emit_by_name (self, "result"); + } + + g_object_unref (self); +} + +static gboolean +real_authenticate (MMAuthRequest *self, GError **error) +{ + MMAuthRequestPolkitPrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (MM_IS_AUTH_REQUEST_POLKIT (self), FALSE); + + /* We ref ourselves across the polkit call, because we can't get + * disposed of while the call is still in-progress, and even if we + * cancel ourselves we'll still get the callback. + */ + g_object_ref (self); + + priv = MM_AUTH_REQUEST_POLKIT_GET_PRIVATE (self); + polkit_authority_check_authorization (priv->authority, + priv->subject, + mm_auth_request_get_authorization (MM_AUTH_REQUEST (self)), + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + priv->cancellable, + pk_auth_cb, + self); + return TRUE; +} + +static void +real_dispose (MMAuthRequest *req) +{ + g_return_if_fail (req != NULL); + g_return_if_fail (MM_IS_AUTH_REQUEST_POLKIT (req)); + + g_cancellable_cancel (MM_AUTH_REQUEST_POLKIT_GET_PRIVATE (req)->cancellable); +} + +/*****************************************************************************/ + +static void +mm_auth_request_polkit_init (MMAuthRequestPolkit *self) +{ +} + +static void +dispose (GObject *object) +{ + MMAuthRequestPolkitPrivate *priv = MM_AUTH_REQUEST_POLKIT_GET_PRIVATE (object); + + g_object_unref (priv->cancellable); + g_object_unref (priv->subject); + + G_OBJECT_CLASS (mm_auth_request_polkit_parent_class)->dispose (object); +} + +static void +mm_auth_request_polkit_class_init (MMAuthRequestPolkitClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + MMAuthRequestClass *ar_class = MM_AUTH_REQUEST_CLASS (class); + + mm_auth_request_polkit_parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (MMAuthRequestPolkitPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + ar_class->authenticate = real_authenticate; + ar_class->dispose = real_dispose; +} + diff --git a/src/mm-auth-request-polkit.h b/src/mm-auth-request-polkit.h new file mode 100644 index 00000000..384ace85 --- /dev/null +++ b/src/mm-auth-request-polkit.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#ifndef MM_AUTH_REQUEST_POLKIT_H +#define MM_AUTH_REQUEST_POLKIT_H + +#include <glib-object.h> +#include <polkit/polkit.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "mm-auth-request.h" + +#define MM_TYPE_AUTH_REQUEST_POLKIT (mm_auth_request_polkit_get_type ()) +#define MM_AUTH_REQUEST_POLKIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_AUTH_REQUEST_POLKIT, MMAuthRequestPolkit)) +#define MM_AUTH_REQUEST_POLKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_AUTH_REQUEST_POLKIT, MMAuthRequestPolkitClass)) +#define MM_IS_AUTH_REQUEST_POLKIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_AUTH_REQUEST_POLKIT)) +#define MM_IS_AUTH_REQUEST_POLKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_AUTH_REQUEST_POLKIT)) +#define MM_AUTH_REQUEST_POLKIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_AUTH_REQUEST_POLKIT, MMAuthRequestPolkitClass)) + +typedef struct { + MMAuthRequest parent; +} MMAuthRequestPolkit; + +typedef struct { + MMAuthRequestClass parent; +} MMAuthRequestPolkitClass; + +GType mm_auth_request_polkit_get_type (void); + +GObject *mm_auth_request_polkit_new (PolkitAuthority *authority, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify); + +void mm_auth_request_polkit_cancel (MMAuthRequestPolkit *self); + +#endif /* MM_AUTH_REQUEST_POLKIT_H */ + diff --git a/src/mm-auth-request.c b/src/mm-auth-request.c new file mode 100644 index 00000000..79f0d421 --- /dev/null +++ b/src/mm-auth-request.c @@ -0,0 +1,182 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include "mm-auth-request.h" + +G_DEFINE_TYPE (MMAuthRequest, mm_auth_request, G_TYPE_OBJECT) + +#define MM_AUTH_REQUEST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AUTH_REQUEST, MMAuthRequestPrivate)) + +typedef struct { + GObject *owner; + char *auth; + DBusGMethodInvocation *context; + MMAuthRequestCb callback; + gpointer callback_data; + + MMAuthResult result; +} MMAuthRequestPrivate; + +/*****************************************************************************/ + +GObject * +mm_auth_request_new (GType atype, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify) +{ + GObject *obj; + MMAuthRequestPrivate *priv; + + g_return_val_if_fail (authorization != NULL, NULL); + g_return_val_if_fail (owner != NULL, NULL); + g_return_val_if_fail (callback != NULL, NULL); + + obj = g_object_new (atype ? atype : MM_TYPE_AUTH_REQUEST, NULL); + if (obj) { + priv = MM_AUTH_REQUEST_GET_PRIVATE (obj); + priv->owner = owner; /* not reffed */ + priv->context = context; + priv->auth = g_strdup (authorization); + priv->callback = callback; + priv->callback_data = callback_data; + + g_object_set_data_full (obj, "caller-data", callback_data, notify); + } + + return obj; +} + +/*****************************************************************************/ + +const char * +mm_auth_request_get_authorization (MMAuthRequest *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (MM_IS_AUTH_REQUEST (self), NULL); + + return MM_AUTH_REQUEST_GET_PRIVATE (self)->auth; +} + +GObject * +mm_auth_request_get_owner (MMAuthRequest *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (MM_IS_AUTH_REQUEST (self), NULL); + + return MM_AUTH_REQUEST_GET_PRIVATE (self)->owner; +} + +MMAuthResult +mm_auth_request_get_result (MMAuthRequest *self) +{ + g_return_val_if_fail (self != NULL, MM_AUTH_RESULT_UNKNOWN); + g_return_val_if_fail (MM_IS_AUTH_REQUEST (self), MM_AUTH_RESULT_UNKNOWN); + + return MM_AUTH_REQUEST_GET_PRIVATE (self)->result; +} + +void +mm_auth_request_set_result (MMAuthRequest *self, MMAuthResult result) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AUTH_REQUEST (self)); + g_return_if_fail (result != MM_AUTH_RESULT_UNKNOWN); + + MM_AUTH_REQUEST_GET_PRIVATE (self)->result = result; +} + +gboolean +mm_auth_request_authenticate (MMAuthRequest *self, GError **error) +{ + return MM_AUTH_REQUEST_GET_CLASS (self)->authenticate (self, error); +} + +void +mm_auth_request_callback (MMAuthRequest *self) +{ + MMAuthRequestPrivate *priv; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AUTH_REQUEST (self)); + + priv = MM_AUTH_REQUEST_GET_PRIVATE (self); + g_warn_if_fail (priv->result != MM_AUTH_RESULT_UNKNOWN); + + if (priv->callback) + priv->callback (self, priv->owner, priv->context, priv->callback_data); +} + +void +mm_auth_request_dispose (MMAuthRequest *self) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AUTH_REQUEST (self)); + + if (MM_AUTH_REQUEST_GET_CLASS (self)->dispose) + MM_AUTH_REQUEST_GET_CLASS (self)->dispose (self); +} + +/*****************************************************************************/ + +static gboolean +real_authenticate (MMAuthRequest *self, GError **error) +{ + /* Null auth; everything passes */ + mm_auth_request_set_result (self, MM_AUTH_RESULT_AUTHORIZED); + g_signal_emit_by_name (self, "result"); + return TRUE; +} + +/*****************************************************************************/ + +static void +mm_auth_request_init (MMAuthRequest *self) +{ +} + +static void +dispose (GObject *object) +{ + MMAuthRequestPrivate *priv = MM_AUTH_REQUEST_GET_PRIVATE (object); + + g_free (priv->auth); + + G_OBJECT_CLASS (mm_auth_request_parent_class)->dispose (object); +} + +static void +mm_auth_request_class_init (MMAuthRequestClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + mm_auth_request_parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (MMAuthRequestPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + class->authenticate = real_authenticate; + + g_signal_new ("result", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, G_TYPE_NONE); +} + diff --git a/src/mm-auth-request.h b/src/mm-auth-request.h new file mode 100644 index 00000000..e22f0a23 --- /dev/null +++ b/src/mm-auth-request.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#ifndef MM_AUTH_REQUEST_H +#define MM_AUTH_REQUEST_H + +#include <glib-object.h> +#include <dbus/dbus-glib-lowlevel.h> + +#define MM_TYPE_AUTH_REQUEST (mm_auth_request_get_type ()) +#define MM_AUTH_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_AUTH_REQUEST, MMAuthRequest)) +#define MM_AUTH_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_AUTH_REQUEST, MMAuthRequestClass)) +#define MM_IS_AUTH_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_AUTH_REQUEST)) +#define MM_IS_AUTH_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_AUTH_REQUEST)) +#define MM_AUTH_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_AUTH_REQUEST, MMAuthRequestClass)) + +typedef enum MMAuthResult { + MM_AUTH_RESULT_UNKNOWN = 0, + MM_AUTH_RESULT_INTERNAL_FAILURE, + MM_AUTH_RESULT_NOT_AUTHORIZED, + MM_AUTH_RESULT_CHALLENGE, + MM_AUTH_RESULT_AUTHORIZED +} MMAuthResult; + +typedef struct { + GObject parent; +} MMAuthRequest; + +typedef struct { + GObjectClass parent; + + gboolean (*authenticate) (MMAuthRequest *self, GError **error); + void (*dispose) (MMAuthRequest *self); +} MMAuthRequestClass; + +GType mm_auth_request_get_type (void); + +typedef void (*MMAuthRequestCb) (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data); + +GObject *mm_auth_request_new (GType atype, + const char *authorization, + GObject *owner, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify); + +const char * mm_auth_request_get_authorization (MMAuthRequest *req); +GObject * mm_auth_request_get_owner (MMAuthRequest *req); +MMAuthResult mm_auth_request_get_result (MMAuthRequest *req); +void mm_auth_request_set_result (MMAuthRequest *req, MMAuthResult result); +gboolean mm_auth_request_authenticate (MMAuthRequest *req, GError **error); +void mm_auth_request_callback (MMAuthRequest *req); +void mm_auth_request_dispose (MMAuthRequest *req); + +#endif /* MM_AUTH_REQUEST_H */ + diff --git a/src/mm-errors.c b/src/mm-errors.c index 16b591cc..d0a71d65 100644 --- a/src/mm-errors.c +++ b/src/mm-errors.c @@ -76,6 +76,7 @@ mm_modem_error_get_type (void) ENUM_ENTRY (MM_MODEM_ERROR_DISCONNECTED, "Disconnected"), ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_IN_PROGRESS, "OperationInProgress"), ENUM_ENTRY (MM_MODEM_ERROR_REMOVED, "Removed"), + ENUM_ENTRY (MM_MODEM_ERROR_AUTHORIZATION_REQUIRED, "AuthorizationRequired"), { 0, 0, 0 } }; diff --git a/src/mm-errors.h b/src/mm-errors.h index 2a6c565e..1b924d40 100644 --- a/src/mm-errors.h +++ b/src/mm-errors.h @@ -39,7 +39,8 @@ enum { MM_MODEM_ERROR_CONNECTED = 2, MM_MODEM_ERROR_DISCONNECTED = 3, MM_MODEM_ERROR_OPERATION_IN_PROGRESS = 4, - MM_MODEM_ERROR_REMOVED = 5 + MM_MODEM_ERROR_REMOVED = 5, + MM_MODEM_ERROR_AUTHORIZATION_REQUIRED = 6 }; #define MM_MODEM_ERROR (mm_modem_error_quark ()) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 7e121f20..425a92f7 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -136,39 +136,6 @@ got_signal_quality (MMModem *modem, { } -void -mm_generic_gsm_set_reg_status (MMGenericGsm *modem, - MMModemGsmNetworkRegStatus status) -{ - MMGenericGsmPrivate *priv; - - g_return_if_fail (MM_IS_GENERIC_GSM (modem)); - - priv = MM_GENERIC_GSM_GET_PRIVATE (modem); - - if (priv->reg_status != status) { - priv->reg_status = status; - - g_debug ("Registration state changed: %d", status); - - if (status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || - status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) { - mm_at_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem); - mm_at_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem); - mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL); - } else { - g_free (priv->oper_code); - g_free (priv->oper_name); - priv->oper_code = priv->oper_name = NULL; - - mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status, - priv->oper_code, priv->oper_name); - } - - mm_generic_gsm_update_enabled_state (modem, TRUE, MM_MODEM_STATE_REASON_NONE); - } -} - typedef struct { const char *result; const char *normalized; @@ -1130,6 +1097,40 @@ mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem) } } +void +mm_generic_gsm_set_reg_status (MMGenericGsm *modem, + MMModemGsmNetworkRegStatus status) +{ + MMGenericGsmPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + + priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + + if (priv->reg_status != status) { + priv->reg_status = status; + + g_debug ("Registration state changed: %d", status); + + if (status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || + status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) { + mm_at_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem); + mm_at_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem); + mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL); + } else { + g_free (priv->oper_code); + g_free (priv->oper_name); + priv->oper_code = priv->oper_name = NULL; + + mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status, + priv->oper_code, priv->oper_name); + } + + mm_generic_gsm_update_enabled_state (modem, TRUE, MM_MODEM_STATE_REASON_NONE); + } +} + +/* Returns TRUE if the modem is "done", ie has registered or been denied */ static gboolean reg_status_updated (MMGenericGsm *self, int new_value, GError **error) { @@ -1255,8 +1256,7 @@ get_reg_status_done (MMAtSerialPort *port, GMatchInfo *match_info; char *tmp; guint id; - - g_warn_if_fail (info == priv->pending_reg_info); + gboolean status_done; if (error) { info->error = g_error_copy (error); @@ -1290,31 +1290,38 @@ get_reg_status_done (MMAtSerialPort *port, g_regex_unref (r); } - if ( reg_status >= 0 - && !reg_status_updated (self, reg_status, &info->error) - && priv->pending_reg_info) { - g_clear_error (&info->error); + if (reg_status >= 0) { + /* Update cached registration status */ + status_done = reg_status_updated (self, reg_status, &info->error); - /* Not registered yet; poll registration status again */ - id = g_timeout_add_seconds (1, reg_status_again, info); - mm_callback_info_set_data (info, REG_STATUS_AGAIN_TAG, - GUINT_TO_POINTER (id), - reg_status_again_remove); - return; + /* If we're waiting for automatic registration to complete and it's + * not done yet, check again in a few seconds. + */ + if ((info == priv->pending_reg_info) && !status_done) { + g_clear_error (&info->error); + + /* Not registered yet; poll registration status again */ + id = g_timeout_add_seconds (1, reg_status_again, info); + mm_callback_info_set_data (info, REG_STATUS_AGAIN_TAG, + GUINT_TO_POINTER (id), + reg_status_again_remove); + return; + } } reg_done: - /* This will schedule the callback for us */ - mm_generic_gsm_pending_registration_stop (self); + if (info == priv->pending_reg_info) { + /* For pending registration, this will schedule the callback for us */ + mm_generic_gsm_pending_registration_stop (self); + } else { + /* Otherwise for a direct registration request, schedule the callback now */ + mm_callback_info_schedule (info); + } } static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); - - g_warn_if_fail (info == priv->pending_reg_info); - mm_at_serial_port_queue_command (port, "+CREG?", 10, get_reg_status_done, info); } @@ -1423,14 +1430,28 @@ get_registration_info (MMModemGsmNetwork *self, MMModemGsmNetworkRegInfoFn callback, gpointer user_data) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); MMCallbackInfo *info; + MMSerialPort *port = priv->primary; info = mm_callback_info_new_full (MM_MODEM (self), gsm_network_reg_info_invoke, G_CALLBACK (callback), user_data); - mm_callback_info_schedule (info); + if (mm_port_get_connected (MM_PORT (priv->primary))) { + if (!priv->secondary) { + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED, + "Cannot get registration info while connected"); + mm_callback_info_schedule (info); + return; + } + + /* Use secondary port if primary is connected */ + port = priv->secondary; + } + + get_registration_status (port, info); } void diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index b9d07060..20ba2a4c 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -44,6 +44,8 @@ typedef struct { gboolean valid; MMModemState state; + MMAuthProvider *authp; + GHashTable *ports; } MMModemBasePrivate; @@ -213,11 +215,51 @@ mm_modem_base_set_unlock_required (MMModemBase *self, const char *unlock_require /*****************************************************************************/ +static gboolean +modem_auth_request (MMModem *modem, + const char *authorization, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error) +{ + MMModemBase *self = MM_MODEM_BASE (modem); + MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + + g_assert (priv->authp); + return !!mm_auth_provider_request_auth (priv->authp, + authorization, + G_OBJECT (self), + context, + callback, + callback_data, + notify, + error); +} + +static gboolean +modem_auth_finish (MMModem *modem, MMAuthRequest *req, GError **error) +{ + if (mm_auth_request_get_result (req) != MM_AUTH_RESULT_AUTHORIZED) { + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_AUTHORIZATION_REQUIRED, + "This request requires the '%s' authorization", + mm_auth_request_get_authorization (req)); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + static void mm_modem_base_init (MMModemBase *self) { MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + priv->authp = mm_auth_provider_get (); + priv->ports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); mm_properties_changed_signal_register_property (G_OBJECT (self), @@ -228,6 +270,8 @@ mm_modem_base_init (MMModemBase *self) static void modem_init (MMModem *modem_class) { + modem_class->auth_request = modem_auth_request; + modem_class->auth_finish = modem_auth_finish; } static gboolean @@ -326,6 +370,8 @@ finalize (GObject *object) MMModemBase *self = MM_MODEM_BASE (object); MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + mm_auth_provider_cancel_for_owner (priv->authp, object); + g_hash_table_destroy (priv->ports); g_free (priv->driver); g_free (priv->plugin); diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c index 112b93fa..1a4fe6a2 100644 --- a/src/mm-modem-cdma.c +++ b/src/mm-modem-cdma.c @@ -20,6 +20,7 @@ #include "mm-errors.h" #include "mm-callback-info.h" #include "mm-marshal.h" +#include "mm-auth-provider.h" static void impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodInvocation *context); static void impl_modem_cdma_get_esn (MMModemCdma *modem, DBusGMethodInvocation *context); @@ -188,10 +189,38 @@ mm_modem_cdma_get_esn (MMModemCdma *self, } static void -impl_modem_cdma_get_esn (MMModemCdma *modem, - DBusGMethodInvocation *context) +esn_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) { - mm_modem_cdma_get_esn (modem, str_call_done, context); + MMModemCdma *self = MM_MODEM_CDMA (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise get the ESN */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_cdma_get_esn (self, str_call_done, context); +} + +static void +impl_modem_cdma_get_esn (MMModemCdma *self, DBusGMethodInvocation *context) +{ + GError *error = NULL; + + /* Make sure the caller is authorized to get the ESN */ + if (!mm_modem_auth_request (MM_MODEM (self), + MM_AUTHORIZATION_DEVICE, + context, + esn_auth_cb, + NULL, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } void diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c index dea4590e..9881871c 100644 --- a/src/mm-modem-gsm-card.c +++ b/src/mm-modem-gsm-card.c @@ -15,6 +15,7 @@ */ #include <dbus/dbus-glib.h> +#include <string.h> #include "mm-modem-gsm-card.h" #include "mm-errors.h" @@ -201,26 +202,176 @@ mm_modem_gsm_card_change_pin (MMModemGsmCard *self, /*****************************************************************************/ static void -impl_gsm_modem_get_imei (MMModemGsmCard *modem, - DBusGMethodInvocation *context) +imei_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) { - mm_modem_gsm_card_get_imei (modem, str_call_done, context); + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMEI */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_get_imei (self, str_call_done, context); } static void -impl_gsm_modem_get_imsi (MMModemGsmCard *modem, +impl_gsm_modem_get_imei (MMModemGsmCard *modem, DBusGMethodInvocation *context) +{ + GError *error = NULL; + + /* Make sure the caller is authorized to get the IMEI */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + imei_auth_cb, + NULL, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +imsi_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMSI */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_get_imsi (self, str_call_done, context); +} + +static void +impl_gsm_modem_get_imsi (MMModemGsmCard *modem, DBusGMethodInvocation *context) +{ + GError *error = NULL; + + /* Make sure the caller is authorized to get the IMSI */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + imsi_auth_cb, + NULL, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +typedef struct { + char *puk; + char *pin; + char *pin2; + gboolean enabled; +} SendPinPukInfo; + +static void +send_pin_puk_info_destroy (gpointer data) +{ + SendPinPukInfo *info = data; + + g_free (info->puk); + g_free (info->pin); + g_free (info->pin2); + memset (info, 0, sizeof (SendPinPukInfo)); + g_free (info); +} + +static SendPinPukInfo * +send_pin_puk_info_new (const char *puk, + const char *pin, + const char *pin2, + gboolean enabled) +{ + SendPinPukInfo *info; + + info = g_malloc0 (sizeof (SendPinPukInfo)); + info->puk = g_strdup (puk); + info->pin = g_strdup (pin); + info->pin2 = g_strdup (pin2); + info->enabled = enabled; + return info; +} + +/*****************************************************************************/ + +static void +send_puk_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise send the PUK */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_send_puk (self, info->puk, info->pin, async_call_done, context); +} + +static void +impl_gsm_modem_send_puk (MMModemGsmCard *modem, + const char *puk, + const char *pin, DBusGMethodInvocation *context) { - mm_modem_gsm_card_get_imsi (modem, str_call_done, context); + GError *error = NULL; + SendPinPukInfo *info; + + info = send_pin_puk_info_new (puk, pin, NULL, FALSE); + + /* Make sure the caller is authorized to send the PUK */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + send_puk_auth_cb, + info, + send_pin_puk_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } +/*****************************************************************************/ + static void - impl_gsm_modem_send_puk (MMModemGsmCard *modem, - const char *puk, - const char *pin, - DBusGMethodInvocation *context) +send_pin_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) { - mm_modem_gsm_card_send_puk (modem, puk, pin, async_call_done, context); + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise unlock the modem */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_send_pin (self, info->pin, async_call_done, context); } static void @@ -228,7 +379,42 @@ impl_gsm_modem_send_pin (MMModemGsmCard *modem, const char *pin, DBusGMethodInvocation *context) { - mm_modem_gsm_card_send_pin (modem, pin, async_call_done, context); + GError *error = NULL; + SendPinPukInfo *info; + + info = send_pin_puk_info_new (NULL, pin, NULL, FALSE); + + /* Make sure the caller is authorized to unlock the modem */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + send_pin_auth_cb, + info, + send_pin_puk_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +enable_pin_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise enable the PIN */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_enable_pin (self, info->pin, info->enabled, async_call_done, context); } static void @@ -237,7 +423,42 @@ impl_gsm_modem_enable_pin (MMModemGsmCard *modem, gboolean enabled, DBusGMethodInvocation *context) { - mm_modem_gsm_card_enable_pin (modem, pin, enabled, async_call_done, context); + GError *error = NULL; + SendPinPukInfo *info; + + info = send_pin_puk_info_new (NULL, pin, NULL, enabled); + + /* Make sure the caller is authorized to enable a PIN */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + enable_pin_auth_cb, + info, + send_pin_puk_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +change_pin_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (owner); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise change the PIN */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_card_change_pin (self, info->pin, info->pin2, async_call_done, context); } static void @@ -246,7 +467,22 @@ impl_gsm_modem_change_pin (MMModemGsmCard *modem, const char *new_pin, DBusGMethodInvocation *context) { - mm_modem_gsm_card_change_pin (modem, old_pin, new_pin, async_call_done, context); + GError *error = NULL; + SendPinPukInfo *info; + + info = send_pin_puk_info_new (NULL, old_pin, new_pin, FALSE); + + /* Make sure the caller is authorized to change the PIN */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + change_pin_auth_cb, + info, + send_pin_puk_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } /*****************************************************************************/ @@ -305,6 +541,7 @@ mm_modem_gsm_card_get_type (void) &card_info, 0); g_type_interface_add_prerequisite (card_type, G_TYPE_OBJECT); + g_type_interface_add_prerequisite (card_type, MM_TYPE_MODEM); dbus_g_object_type_install_info (card_type, &dbus_glib_mm_modem_gsm_card_object_info); } diff --git a/src/mm-modem-gsm-network.c b/src/mm-modem-gsm-network.c index 26ff4229..bf52b942 100644 --- a/src/mm-modem-gsm-network.c +++ b/src/mm-modem-gsm-network.c @@ -398,10 +398,39 @@ impl_gsm_modem_register (MMModemGsmNetwork *modem, } static void +scan_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmNetwork *self = MM_MODEM_GSM_NETWORK (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMEI */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_gsm_network_scan (self, scan_call_done, context); +} + +static void impl_gsm_modem_scan (MMModemGsmNetwork *modem, DBusGMethodInvocation *context) { - mm_modem_gsm_network_scan (modem, scan_call_done, context); + GError *error = NULL; + + /* Make sure the caller is authorized to request a scan */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + context, + scan_auth_cb, + NULL, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } static void @@ -562,6 +591,7 @@ mm_modem_gsm_network_get_type (void) &network_info, 0); g_type_interface_add_prerequisite (network_type, G_TYPE_OBJECT); + g_type_interface_add_prerequisite (network_type, MM_TYPE_MODEM); dbus_g_object_type_install_info (network_type, &dbus_glib_mm_modem_gsm_network_object_info); } diff --git a/src/mm-modem-gsm-sms.c b/src/mm-modem-gsm-sms.c index e8ec0742..083ce8ae 100644 --- a/src/mm-modem-gsm-sms.c +++ b/src/mm-modem-gsm-sms.c @@ -129,12 +129,137 @@ mm_modem_gsm_sms_send (MMModemGsmSms *self, /*****************************************************************************/ +typedef struct { + guint num1; + guint num2; + guint num3; + guint num4; + guint num5; + char *str; + GHashTable *hash; +} SmsAuthInfo; + +static void +sms_auth_info_destroy (gpointer data) +{ + SmsAuthInfo *info = data; + + g_hash_table_destroy (info->hash); + g_free (info->str); + memset (info, 0, sizeof (SmsAuthInfo)); + g_free (info); +} + +static void +destroy_gvalue (gpointer data) +{ + GValue *value = (GValue *) data; + + g_value_unset (value); + g_slice_free (GValue, value); +} + +static SmsAuthInfo * +sms_auth_info_new (guint num1, + guint num2, + guint num3, + guint num4, + guint num5, + const char *str, + GHashTable *hash) +{ + SmsAuthInfo *info; + + info = g_malloc0 (sizeof (SmsAuthInfo)); + info->num1 = num1; + info->num2 = num2; + info->num3 = num3; + info->num4 = num4; + info->num5 = num5; + info->str = g_strdup (str); + + /* Copy the hash table if we're given one */ + if (hash) { + GHashTableIter iter; + gpointer key, value; + + info->hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, destroy_gvalue); + + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, &key, &value)) { + const char *str_key = (const char *) key; + GValue *src = (GValue *) value; + GValue *dst; + + dst = g_slice_new0 (GValue); + g_value_init (dst, G_VALUE_TYPE (src)); + g_hash_table_insert (info->hash, g_strdup (str_key), dst); + } + } + + return info; +} + +/*****************************************************************************/ + +static void +sms_delete_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise delete the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); +} + static void impl_gsm_modem_sms_delete (MMModemGsmSms *modem, guint idx, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (idx, 0, 0, 0, 0, NULL, NULL); + + /* Make sure the caller is authorized to delete an SMS */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_delete_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +sms_get_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise get the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); } static void @@ -142,9 +267,26 @@ impl_gsm_modem_sms_get (MMModemGsmSms *modem, guint idx, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (idx, 0, 0, 0, 0, NULL, NULL); + + /* Make sure the caller is authorized to get an SMS */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_get_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } +/*****************************************************************************/ + static void impl_gsm_modem_sms_get_format (MMModemGsmSms *modem, DBusGMethodInvocation *context) @@ -167,19 +309,103 @@ impl_gsm_modem_sms_get_smsc (MMModemGsmSms *modem, async_call_not_supported (modem, async_call_done, context); } +/*****************************************************************************/ + +static void +sms_set_smsc_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise set the SMS service center */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); +} + static void impl_gsm_modem_sms_set_smsc (MMModemGsmSms *modem, const char *smsc, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (0, 0, 0, 0, 0, smsc, NULL); + + /* Make sure the caller is authorized to set the SMS service center */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_set_smsc_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +sms_list_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise list SMSs */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); } static void impl_gsm_modem_sms_list (MMModemGsmSms *modem, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + + /* Make sure the caller is authorized to list SMSs */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_list_auth_cb, + NULL, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +sms_save_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise save the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); } static void @@ -187,54 +413,122 @@ impl_gsm_modem_sms_save (MMModemGsmSms *modem, GHashTable *properties, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (0, 0, 0, 0, 0, NULL, properties); + + /* Make sure the caller is authorized to save the SMS */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_save_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } +/*****************************************************************************/ + static void -impl_gsm_modem_sms_send (MMModemGsmSms *modem, - GHashTable *properties, - DBusGMethodInvocation *context) +sms_send_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) { + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + SmsAuthInfo *info = user_data; + GError *error = NULL; GValue *value; const char *number = NULL; const char *text = NULL ; const char *smsc = NULL; - GError *error = NULL; guint validity = 0; guint class = 0; - value = (GValue *) g_hash_table_lookup (properties, "number"); + /* Return any authorization error, otherwise delete the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) + goto done; + + value = (GValue *) g_hash_table_lookup (info->hash, "number"); if (value) number = g_value_get_string (value); - value = (GValue *) g_hash_table_lookup (properties, "text"); + value = (GValue *) g_hash_table_lookup (info->hash, "text"); if (value) text = g_value_get_string (value); - value = (GValue *) g_hash_table_lookup (properties, "smsc"); + value = (GValue *) g_hash_table_lookup (info->hash, "smsc"); if (value) smsc = g_value_get_string (value); - value = (GValue *) g_hash_table_lookup (properties, "validity"); + value = (GValue *) g_hash_table_lookup (info->hash, "validity"); if (value) validity = g_value_get_uint (value); - value = (GValue *) g_hash_table_lookup (properties, "class"); + value = (GValue *) g_hash_table_lookup (info->hash, "class"); if (value) class = g_value_get_uint (value); - if (!number) + if (!number) { error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number"); - else if (!text) + } else if (!text) { error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing message text"); + } +done: if (error) { - async_call_done (MM_MODEM (modem), error, context); + async_call_done (MM_MODEM (self), error, context); g_error_free (error); } else - mm_modem_gsm_sms_send (modem, number, text, smsc, validity, class, async_call_done, context); + mm_modem_gsm_sms_send (self, number, text, smsc, validity, class, async_call_done, context); +} + +static void +impl_gsm_modem_sms_send (MMModemGsmSms *modem, + GHashTable *properties, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (0, 0, 0, 0, 0, NULL, properties); + + /* Make sure the caller is authorized to send the PUK */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_send_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +sms_send_from_storage_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise delete the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); } static void @@ -242,7 +536,41 @@ impl_gsm_modem_sms_send_from_storage (MMModemGsmSms *modem, guint idx, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (idx, 0, 0, 0, 0, NULL, NULL); + + /* Make sure the caller is authorized to send the PUK */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_send_from_storage_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +sms_set_indication_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmSms *self = MM_MODEM_GSM_SMS (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise delete the SMS */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + async_call_not_supported (self, async_call_done, context); } static void @@ -254,7 +582,22 @@ impl_gsm_modem_sms_set_indication (MMModemGsmSms *modem, guint bfr, DBusGMethodInvocation *context) { - async_call_not_supported (modem, async_call_done, context); + GError *error = NULL; + SmsAuthInfo *info; + + info = sms_auth_info_new (mode, mt, bm, ds, bfr, NULL, NULL); + + /* Make sure the caller is authorized to send the PUK */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_SMS, + context, + sms_set_indication_auth_cb, + info, + sms_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } /*****************************************************************************/ diff --git a/src/mm-modem.c b/src/mm-modem.c index 5bb2ef6b..8e2d8a48 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -608,6 +608,54 @@ mm_modem_set_state (MMModem *self, /*****************************************************************************/ +gboolean +mm_modem_auth_request (MMModem *self, + const char *authorization, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (MM_IS_MODEM (self), FALSE); + g_return_val_if_fail (authorization != NULL, FALSE); + g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (callback != NULL, FALSE); + + g_return_val_if_fail (MM_MODEM_GET_INTERFACE (self)->auth_request, FALSE); + return MM_MODEM_GET_INTERFACE (self)->auth_request (self, + authorization, + context, + callback, + callback_data, + notify, + error); +} + +gboolean +mm_modem_auth_finish (MMModem *self, + MMAuthRequest *req, + GError **error) +{ + gboolean success; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (MM_IS_MODEM (self), FALSE); + g_return_val_if_fail (req != NULL, FALSE); + + g_return_val_if_fail (MM_MODEM_GET_INTERFACE (self)->auth_finish, FALSE); + success = MM_MODEM_GET_INTERFACE (self)->auth_finish (self, req, error); + + /* If the request failed, the implementor *should* return an error */ + if (!success && error) + g_warn_if_fail (*error != NULL); + + return success; +} + +/*****************************************************************************/ + static void mm_modem_init (gpointer g_iface) { diff --git a/src/mm-modem.h b/src/mm-modem.h index ead2cca5..93915eb0 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -18,8 +18,10 @@ #define MM_MODEM_H #include <glib-object.h> +#include <dbus/dbus-glib-lowlevel.h> #include "mm-port.h" +#include "mm-auth-provider.h" typedef enum { MM_MODEM_STATE_UNKNOWN = 0, @@ -156,6 +158,21 @@ struct _MMModem { MMModemInfoFn callback, gpointer user_data); + /* Normally implemented by the modem base class; plugins should + * never need to implement this. + */ + gboolean (*auth_request) (MMModem *self, + const char *authorization, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + + gboolean (*auth_finish) (MMModem *self, + MMAuthRequest *req, + GError **error); + /* Signals */ void (*state_changed) (MMModem *self, MMModemState new_state, @@ -217,5 +234,21 @@ void mm_modem_set_state (MMModem *self, GError *mm_modem_check_removed (MMModem *self, const GError *error); +/* Request authorization to perform an action. Used by D-Bus method + * handlers to ensure that the incoming request is authorized to perform + * the action it's requesting. + */ +gboolean mm_modem_auth_request (MMModem *self, + const char *authorization, + DBusGMethodInvocation *context, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + +gboolean mm_modem_auth_finish (MMModem *self, + MMAuthRequest *req, + GError **error); + #endif /* MM_MODEM_H */ |