diff options
author | Dan Williams <dcbw@redhat.com> | 2010-02-26 18:01:55 -0800 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-02-26 18:01:55 -0800 |
commit | 438a047935f941e8f7d8df27a0069c70e4b4ea05 (patch) | |
tree | 8933f938d30e44ec4acb8f4a1c775789de90e9ae /src | |
parent | b9958e6ec5115822b1c2112da5ef2652aa847a51 (diff) |
core: add authorization providers and optional PolicyKit support
When the support is complete, use --with-polkit to enable
PolicyKit support. It's not there yet, but this commit adds an
authorization provider framework which will be extended to allow
hooking into PolicyKit.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 19 | ||||
-rw-r--r-- | src/mm-auth-provider-factory.c | 45 | ||||
-rw-r--r-- | src/mm-auth-provider.c | 405 | ||||
-rw-r--r-- | src/mm-auth-provider.h | 99 | ||||
-rw-r--r-- | src/mm-errors.c | 1 | ||||
-rw-r--r-- | src/mm-errors.h | 3 | ||||
-rw-r--r-- | src/mm-modem-base.c | 108 | ||||
-rw-r--r-- | src/mm-modem-cdma.c | 35 | ||||
-rw-r--r-- | src/mm-modem-gsm-card.c | 262 | ||||
-rw-r--r-- | src/mm-modem-gsm-network.c | 32 | ||||
-rw-r--r-- | src/mm-modem.c | 46 | ||||
-rw-r--r-- | src/mm-modem.h | 32 |
12 files changed, 1068 insertions, 19 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 9209b55f..2ed7e603 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,12 +19,20 @@ 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) \ $(top_builddir)/marshallers/libmarshallers.la \ $(builddir)/libmodem-helpers.la +if WITH_POLKIT +modem_manager_LDADD += $(POLKIT_LIBS) +endif + modem_manager_SOURCES = \ main.c \ mm-callback-info.c \ @@ -63,7 +71,16 @@ modem_manager_SOURCES = \ mm-plugin-base.c \ mm-plugin-base.h \ mm-properties-changed-signal.c \ - mm-properties-changed-signal.h + mm-properties-changed-signal.h \ + mm-auth-provider.h \ + mm-auth-provider.c \ + mm-auth-provider-factory.c + +if WITH_POLKIT +modem_manager_SOURCES += \ + mm-auth-provider-polkit.c \ + mm-auth-provider-polkit.h +endif mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $< 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.c b/src/mm-auth-provider.c new file mode 100644 index 00000000..0ff4baff --- /dev/null +++ b/src/mm-auth-provider.c @@ -0,0 +1,405 @@ +/* -*- 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 +}; + +enum { + REQUEST_ADDED, + REQUEST_REMOVED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + +/*****************************************************************************/ + +GObject * +mm_auth_provider_new (void) +{ + return g_object_new (MM_TYPE_AUTH_PROVIDER, NULL); +} + +/*****************************************************************************/ + +struct MMAuthRequest { + guint32 refcount; + guint32 id; + char *auth; + GObject *instance; + + MMAuthResult result; + + MMAuthRequestCb callback; + gpointer callback_data; + GDestroyNotify notify; +}; + +static MMAuthRequest * +mm_auth_request_new (const char *authorization, + GObject *instance, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify) +{ + static guint32 id = 1; + MMAuthRequest *req; + + g_return_val_if_fail (authorization != NULL, NULL); + g_return_val_if_fail (callback != NULL, NULL); + + req = g_malloc0 (sizeof (MMAuthRequest)); + req->id = id++; + req->refcount = 1; + req->auth = g_strdup (authorization); + req->instance = instance; + req->callback = callback; + req->callback_data = callback_data; + req->notify = notify; + + return req; +} + +MMAuthRequest * +mm_auth_request_ref (MMAuthRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + g_return_val_if_fail (req->refcount > 0, NULL); + + req->refcount++; + return req; +} + +void +mm_auth_request_unref (MMAuthRequest *req) +{ + g_return_if_fail (req != NULL); + g_return_if_fail (req->refcount > 0); + + req->refcount--; + if (req->refcount == 0) { + g_free (req->auth); + memset (req, 0, sizeof (MMAuthRequest)); + g_free (req); + } +} + +guint32 +mm_auth_request_get_id (MMAuthRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + g_return_val_if_fail (req->refcount > 0, 0); + + return req->id; +} + +const char * +mm_auth_request_get_authorization (MMAuthRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + g_return_val_if_fail (req->refcount > 0, 0); + + return req->auth; +} + +/*****************************************************************************/ + +MMAuthRequest * +mm_auth_provider_get_request (MMAuthProvider *provider, guint32 reqid) +{ + MMAuthProviderPrivate *priv; + + g_return_val_if_fail (provider != NULL, NULL); + g_return_val_if_fail (MM_IS_AUTH_PROVIDER (provider), NULL); + g_return_val_if_fail (reqid > 0, NULL); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + return (MMAuthRequest *) g_hash_table_lookup (priv->requests, GUINT_TO_POINTER (reqid)); +} + +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 = (MMAuthRequest *) value; + if (req->result != MM_AUTH_RESULT_UNKNOWN) { + req->callback (req->instance, req->id, req->result, req->callback_data); + + /* Let the caller clean up the request's callback data */ + if (req->notify) + req->notify (req->callback_data); + + remove = g_slist_prepend (remove, req); + } + } + + /* And remove those requests from our pending request list */ + while (remove) { + req = (MMAuthRequest *) remove->data; + g_signal_emit (self, signals[REQUEST_REMOVED], 0, req->instance, req->id); + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->id)); + remove = g_slist_remove (remove, req); + } + + return FALSE; +} + +void +mm_auth_provider_finish_request (MMAuthProvider *provider, + guint32 reqid, + MMAuthResult result) +{ + MMAuthProviderPrivate *priv; + MMAuthRequest *req; + + g_return_if_fail (provider != NULL); + g_return_if_fail (MM_IS_AUTH_PROVIDER (provider)); + g_return_if_fail (reqid > 0); + g_return_if_fail (result != MM_AUTH_RESULT_UNKNOWN); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + req = (MMAuthRequest *) g_hash_table_lookup (priv->requests, GUINT_TO_POINTER (reqid)); + g_return_if_fail (req != NULL); + + req->result = result; + + if (priv->process_id == 0) + priv->process_id = g_idle_add (process_complete_requests, provider); +} + +void +mm_auth_provider_cancel_request (MMAuthProvider *provider, guint32 reqid) +{ + MMAuthProviderPrivate *priv; + MMAuthRequest *req; + + g_return_if_fail (provider != NULL); + g_return_if_fail (MM_IS_AUTH_PROVIDER (provider)); + g_return_if_fail (reqid > 0); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + + req = (MMAuthRequest *) g_hash_table_lookup (priv->requests, GUINT_TO_POINTER (reqid)); + g_return_if_fail (req != NULL); + + /* Let the caller clean up the request's callback data */ + if (req->notify) + req->notify (req->callback_data); + + /* We don't signal removal here as it's assumed the caller + * handles that itself instead of by the signal. + */ + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (reqid)); +} + +const char * +mm_auth_provider_get_authorization_for_id (MMAuthProvider *provider, guint32 reqid) +{ + MMAuthProviderPrivate *priv; + MMAuthRequest *req; + + g_return_val_if_fail (provider != NULL, NULL); + g_return_val_if_fail (MM_IS_AUTH_PROVIDER (provider), NULL); + g_return_val_if_fail (reqid > 0, NULL); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + req = (MMAuthRequest *) g_hash_table_lookup (priv->requests, GUINT_TO_POINTER (reqid)); + g_return_val_if_fail (req != NULL, NULL); + + return mm_auth_request_get_authorization (req); +} + +/*****************************************************************************/ + +static gboolean +real_request_auth (MMAuthProvider *provider, + MMAuthRequest *req, + GError **error) +{ + /* This class provides null authentication; all requests pass */ + mm_auth_provider_finish_request (provider, + mm_auth_request_get_id (req), + MM_AUTH_RESULT_AUTHORIZED); + return TRUE; +} + +guint32 +mm_auth_provider_request_auth (MMAuthProvider *provider, + const char *authorization, + GObject *instance, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error) +{ + MMAuthProviderPrivate *priv; + MMAuthRequest *req; + + g_return_val_if_fail (provider != NULL, 0); + g_return_val_if_fail (MM_IS_AUTH_PROVIDER (provider), 0); + g_return_val_if_fail (authorization != NULL, 0); + g_return_val_if_fail (callback != NULL, 0); + + priv = MM_AUTH_PROVIDER_GET_PRIVATE (provider); + + req = mm_auth_request_new (authorization, instance, callback, callback_data, notify); + g_assert (req); + + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->id), req); + g_signal_emit (provider, signals[REQUEST_ADDED], 0, instance, req->id); + + if (!MM_AUTH_PROVIDER_GET_CLASS (provider)->request_auth (provider, req, error)) { + /* Error */ + g_signal_emit (provider, signals[REQUEST_REMOVED], 0, instance, req->id); + + /* Let the caller clean up the request's callback data */ + if (req->notify) + req->notify (req->callback_data); + + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->id)); + return 0; + } + + return req->id; +} + +/*****************************************************************************/ + +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, + (GDestroyNotify) mm_auth_request_unref); +} + +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 +finalize (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)->finalize (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->finalize = finalize; + class->request_auth = real_request_auth; + + /* 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)); + + /* Signals */ + signals[REQUEST_ADDED] = + g_signal_new ("request-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + mm_marshal_VOID__POINTER_UINT, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + + signals[REQUEST_REMOVED] = + g_signal_new ("request-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + mm_marshal_VOID__POINTER_UINT, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); +} + diff --git a/src/mm-auth-provider.h b/src/mm-auth-provider.h new file mode 100644 index 00000000..8d693f3e --- /dev/null +++ b/src/mm-auth-provider.h @@ -0,0 +1,99 @@ +/* -*- 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> + +/* 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 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 MMAuthRequest MMAuthRequest; +typedef struct _MMAuthProvider MMAuthProvider; +typedef struct _MMAuthProviderClass MMAuthProviderClass; + +typedef void (*MMAuthRequestCb) (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data); + +struct _MMAuthProvider { + GObject parent; +}; + +struct _MMAuthProviderClass { + GObjectClass parent; + + gboolean (*request_auth) (MMAuthProvider *provider, + MMAuthRequest *req, + GError **error); +}; + +GType mm_auth_provider_get_type (void); + +guint32 mm_auth_provider_request_auth (MMAuthProvider *provider, + const char *authorization, + GObject *instance, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + +/* To get an auth provider instance, implemented in mm-auth-provider-factory.c */ +MMAuthProvider *mm_auth_provider_get (void); + +/* For subclasses only */ +MMAuthRequest *mm_auth_provider_get_request (MMAuthProvider *provider, guint32 reqid); +MMAuthRequest *mm_auth_request_ref (MMAuthRequest *req); +void mm_auth_request_unref (MMAuthRequest *req); +guint32 mm_auth_request_get_id (MMAuthRequest *req); +const char * mm_auth_request_get_authorization (MMAuthRequest *req); + +/* Normal API */ + +/* schedules the request's completion */ +void mm_auth_provider_finish_request (MMAuthProvider *provider, + guint32 reqid, + MMAuthResult result); + +void mm_auth_provider_cancel_request (MMAuthProvider *provider, guint32 reqid); + +const char *mm_auth_provider_get_authorization_for_id (MMAuthProvider *provider, + guint32 reqid); + +#endif /* MM_AUTH_PROVIDER_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-modem-base.c b/src/mm-modem-base.c index 43ec6f84..83178874 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -44,6 +44,11 @@ typedef struct { gboolean valid; MMModemState state; + MMAuthProvider *authp; + guint authp_added_id; + guint authp_removed_id; + GSList *auth_reqs; + GHashTable *ports; } MMModemBasePrivate; @@ -213,11 +218,104 @@ mm_modem_base_set_unlock_required (MMModemBase *self, const char *unlock_require /*****************************************************************************/ +static gboolean +modem_auth_request (MMModem *modem, + const char *authorization, + 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), + callback, + callback_data, + notify, + error); +} + +static gboolean +modem_auth_finish (MMModem *modem, + guint32 reqid, + MMAuthResult result, + GError **error) +{ + MMModemBase *self = MM_MODEM_BASE (modem); + MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + + if (result != MM_AUTH_RESULT_AUTHORIZED) { + const char *auth; + + auth = mm_auth_provider_get_authorization_for_id (priv->authp, reqid); + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_AUTHORIZATION_REQUIRED, + "This request requires the '%s' authorization", + auth ? auth : "(unknown)"); + return FALSE; + } + + return TRUE; +} + +static void +authp_request_added (MMAuthProvider *provider, + gpointer parent, + guint32 reqid, + gpointer user_data) +{ + MMModemBase *self; + MMModemBasePrivate *priv; + + /* Make sure it's our auth request */ + if (parent != user_data) + return; + + self = MM_MODEM_BASE (user_data); + priv = MM_MODEM_BASE_GET_PRIVATE (self); + + /* Add this request to our table so we can cancel it when we die */ + priv->auth_reqs = g_slist_prepend (priv->auth_reqs, GUINT_TO_POINTER (reqid)); +} + +static void +authp_request_removed (MMAuthProvider *provider, + gpointer parent, + guint32 reqid, + gpointer user_data) +{ + MMModemBase *self; + MMModemBasePrivate *priv; + + /* Make sure it's our auth request */ + if (parent != user_data) + return; + + self = MM_MODEM_BASE (user_data); + priv = MM_MODEM_BASE_GET_PRIVATE (self); + + /* Request finished; remove cleanly */ + priv->auth_reqs = g_slist_remove (priv->auth_reqs, GUINT_TO_POINTER (reqid)); +} + +/*****************************************************************************/ + static void mm_modem_base_init (MMModemBase *self) { MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + priv->authp = mm_auth_provider_get (); + priv->authp_added_id = g_signal_connect (priv->authp, "request-added", + (GCallback) authp_request_added, + self); + priv->authp_removed_id = g_signal_connect (priv->authp, "request-removed", + (GCallback) authp_request_removed, + self); + 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 +326,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 @@ -325,6 +425,14 @@ finalize (GObject *object) { MMModemBase *self = MM_MODEM_BASE (object); MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); + GSList *iter; + + g_signal_handler_disconnect (priv->authp, priv->authp_added_id); + g_signal_handler_disconnect (priv->authp, priv->authp_removed_id); + + for (iter = priv->auth_reqs; iter; iter = g_slist_next (iter)) + mm_auth_provider_cancel_request (priv->authp, GPOINTER_TO_UINT (iter->data)); + g_slist_free (priv->auth_reqs); g_hash_table_destroy (priv->ports); g_free (priv->driver); diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c index 112b93fa..0ba9f792 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 (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) { - mm_modem_cdma_get_esn (modem, str_call_done, context); + MMModemCdma *self = MM_MODEM_CDMA (instance); + DBusGMethodInvocation *context = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise get the ESN */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &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, + esn_auth_cb, + context, + 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..0e62779a 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,178 @@ mm_modem_gsm_card_change_pin (MMModemGsmCard *self, /*****************************************************************************/ static void -impl_gsm_modem_get_imei (MMModemGsmCard *modem, - DBusGMethodInvocation *context) +imei_auth_cb (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) { - mm_modem_gsm_card_get_imei (modem, str_call_done, context); + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + DBusGMethodInvocation *context = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMEI */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &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_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, + imei_auth_cb, + context, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +static void +imsi_auth_cb (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + DBusGMethodInvocation *context = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMSI */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &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, +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, + imsi_auth_cb, + context, + NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +/*****************************************************************************/ + +typedef struct { + char *puk; + char *pin; + char *pin2; + gboolean enabled; + DBusGMethodInvocation *context; +} 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, + DBusGMethodInvocation *context) +{ + 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; + info->context = context; + return info; +} + +/*****************************************************************************/ + +static void +send_puk_auth_cb (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise send the PUK */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &error)) { + dbus_g_method_return_error (info->context, error); + g_error_free (error); + } else + mm_modem_gsm_card_send_puk (self, info->puk, info->pin, async_call_done, info->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, context); + + /* Make sure the caller is authorized to send the PUK */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + 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 (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) { - mm_modem_gsm_card_send_puk (modem, puk, pin, async_call_done, context); + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise unlock the modem */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &error)) { + dbus_g_method_return_error (info->context, error); + g_error_free (error); + } else + mm_modem_gsm_card_send_pin (self, info->pin, async_call_done, info->context); } static void @@ -228,7 +381,41 @@ 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, context); + + /* Make sure the caller is authorized to unlock the modem */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + 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 (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise enable the PIN */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &error)) { + dbus_g_method_return_error (info->context, error); + g_error_free (error); + } else + mm_modem_gsm_card_enable_pin (self, info->pin, info->enabled, async_call_done, info->context); } static void @@ -237,7 +424,41 @@ 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, context); + + /* Make sure the caller is authorized to enable a PIN */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + 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 (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) +{ + MMModemGsmCard *self = MM_MODEM_GSM_CARD (instance); + SendPinPukInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise change the PIN */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &error)) { + dbus_g_method_return_error (info->context, error); + g_error_free (error); + } else + mm_modem_gsm_card_change_pin (self, info->pin, info->pin2, async_call_done, info->context); } static void @@ -246,7 +467,21 @@ 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, context); + + /* Make sure the caller is authorized to change the PIN */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE, + change_pin_auth_cb, + info, + send_pin_puk_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } } /*****************************************************************************/ @@ -305,6 +540,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..bb84da12 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 (GObject *instance, + guint32 reqid, + MMAuthResult result, + gpointer user_data) +{ + MMModemGsmNetwork *self = MM_MODEM_GSM_NETWORK (instance); + DBusGMethodInvocation *context = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise get the IMEI */ + if (!mm_modem_auth_finish (MM_MODEM (self), reqid, result, &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, + scan_auth_cb, + context, + 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.c b/src/mm-modem.c index 5bb2ef6b..0c8e6b25 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -608,6 +608,52 @@ mm_modem_set_state (MMModem *self, /*****************************************************************************/ +gboolean +mm_modem_auth_request (MMModem *self, + const char *authorization, + 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 (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, + callback, + callback_data, + notify, + error); +} + +gboolean +mm_modem_auth_finish (MMModem *self, + guint32 reqid, + MMAuthResult result, + 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 (reqid > 0, FALSE); + + g_return_val_if_fail (MM_MODEM_GET_INTERFACE (self)->auth_finish, FALSE); + success = MM_MODEM_GET_INTERFACE (self)->auth_finish (self, reqid, result, 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..531ca785 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -20,6 +20,7 @@ #include <glib-object.h> #include "mm-port.h" +#include "mm-auth-provider.h" typedef enum { MM_MODEM_STATE_UNKNOWN = 0, @@ -156,6 +157,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, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + + gboolean (*auth_finish) (MMModem *self, + guint32 reqid, + MMAuthResult result, + GError **error); + /* Signals */ void (*state_changed) (MMModem *self, MMModemState new_state, @@ -217,5 +233,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, + MMAuthRequestCb callback, + gpointer callback_data, + GDestroyNotify notify, + GError **error); + +gboolean mm_modem_auth_finish (MMModem *self, + guint32 reqid, + MMAuthResult result, + GError **error); + #endif /* MM_MODEM_H */ |