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.
This commit is contained in:
Dan Williams
2010-02-26 18:01:55 -08:00
parent b9958e6ec5
commit 438a047935
16 changed files with 1219 additions and 22 deletions

View File

@@ -19,7 +19,11 @@ all: $(GENERATED_FILES)
CLEANFILES = $(GENERATED_FILES)
endif
SUBDIRS = marshallers src plugins introspection po policy test
SUBDIRS = marshallers src plugins introspection po test
if WITH_POLKIT
SUBDIRS += policy
endif
dbusservicedir = $(DBUS_SYS_DIR)
dbusservice_DATA = org.freedesktop.ModemManager.conf

View File

@@ -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 >= 0.95 polkit-gobject-1)
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")
@@ -116,4 +132,6 @@ echo Building documentation: ${with_docs}
echo
echo Building PPP-enabled tests: ${have_pppd_headers}
echo
echo Building with PolicyKit support: ${with_polkit}
echo

View File

@@ -5,4 +5,5 @@ VOID:UINT,BOOLEAN
VOID:UINT,UINT
VOID:UINT,UINT,UINT
VOID:STRING,BOXED
VOID:POINTER,UINT

View File

@@ -3,12 +3,137 @@
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy context="default">
<allow send_destination="org.freedesktop.ModemManager"/>
<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.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"/>
</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>

View File

@@ -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=$@ $<

View File

@@ -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;
}

405
src/mm-auth-provider.c Normal file
View File

@@ -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);
}

99
src/mm-auth-provider.h Normal file
View File

@@ -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 */

View File

@@ -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 }
};

View File

@@ -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 ())

View File

@@ -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);

View File

@@ -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

View File

@@ -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_imsi (MMModemGsmCard *modem,
DBusGMethodInvocation *context)
impl_gsm_modem_get_imei (MMModemGsmCard *modem, DBusGMethodInvocation *context)
{
mm_modem_gsm_card_get_imsi (modem, str_call_done, 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_send_puk (MMModemGsmCard *modem,
const char *puk,
const char *pin,
DBusGMethodInvocation *context)
impl_gsm_modem_get_imsi (MMModemGsmCard *modem, DBusGMethodInvocation *context)
{
mm_modem_gsm_card_send_puk (modem, puk, pin, async_call_done, 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)
{
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
send_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 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);
}

View File

@@ -397,11 +397,40 @@ impl_gsm_modem_register (MMModemGsmNetwork *modem,
mm_modem_gsm_network_register (modem, id, async_call_done, context);
}
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);
}

View File

@@ -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)
{

View File

@@ -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 */