Commit 46a9783b authored by Bastien Nocera's avatar Bastien Nocera Committed by Daniel Drake

Add PolicyKit checking

Add PolicyKit checks to all the public functions, grouped
in 2 main groups: Verify and Enroll
By default, only the user is able to enroll new fingers,
or verify themselves.
You need to be allowed at least one of those 2 actions
to be allowed to claim or release the device.

We also add a new SetUsername function, for administration
functions. Users will need to be authenticate as admins to
be allowed to change the username on which the actions will
be taken. Any prints loaded before the change of username will
be unloaded.
parent 61a2266e
AUTOMAKE_OPTIONS = dist-bzip2 AUTOMAKE_OPTIONS = dist-bzip2
SUBDIRS = src data tests po SUBDIRS = src data tests po
EXTRA_DIST = TODO EXTRA_DIST = TODO intltool-extract.in intltool-merge.in intltool-update.in
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
aclocal || exit 1 aclocal || exit 1
autoheader || exit 1 autoheader || exit 1
glib-gettextize -f -c || exit 1 glib-gettextize -f -c || exit 1
intltoolize -c -f || exit 1
autoconf || exit 1 autoconf || exit 1
automake -a -c || exit 1 automake -a -c || exit 1
./configure $* ./configure $*
...@@ -11,6 +11,7 @@ GETTEXT_PACKAGE=fprintd ...@@ -11,6 +11,7 @@ GETTEXT_PACKAGE=fprintd
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, ["$GETTEXT_PACKAGE"], [Define to the Gettext package name]) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, ["$GETTEXT_PACKAGE"], [Define to the Gettext package name])
AC_SUBST(GETTEXT_PACKAGE) AC_SUBST(GETTEXT_PACKAGE)
AM_GLIB_GNU_GETTEXT AM_GLIB_GNU_GETTEXT
IT_PROG_INTLTOOL([0.35.0])
PKG_CHECK_MODULES(FPRINT, [libfprint > 0.1.0]) PKG_CHECK_MODULES(FPRINT, [libfprint > 0.1.0])
AC_SUBST(FPRINT_LIBS) AC_SUBST(FPRINT_LIBS)
...@@ -24,10 +25,13 @@ PKG_CHECK_MODULES(DBUS_GLIB, "dbus-glib-1") ...@@ -24,10 +25,13 @@ PKG_CHECK_MODULES(DBUS_GLIB, "dbus-glib-1")
AC_SUBST(DBUS_GLIB_LIBS) AC_SUBST(DBUS_GLIB_LIBS)
AC_SUBST(DBUS_GLIB_CFLAGS) AC_SUBST(DBUS_GLIB_CFLAGS)
PKG_CHECK_MODULES(POLKIT, "polkit") PKG_CHECK_MODULES(POLKIT, "polkit polkit-dbus")
AC_SUBST(POLKIT_LIBS) AC_SUBST(POLKIT_LIBS)
AC_SUBST(POLKIT_CFLAGS) AC_SUBST(POLKIT_CFLAGS)
AC_CHECK_PROG([POLKIT_POLICY_FILE_VALIDATE],
[polkit-policy-file-validate], [polkit-policy-file-validate])
AS_AC_EXPAND(DATADIR, $datadir) AS_AC_EXPAND(DATADIR, $datadir)
DBUS_SERVICES_DIR="$DATADIR/dbus-1/services" DBUS_SERVICES_DIR="$DATADIR/dbus-1/services"
......
dbus_servicesdir = $(datadir)/dbus-1/system-services dbus_servicesdir = $(datadir)/dbus-1/system-services
dbus_confdir = $(sysconfdir)/dbus-1/system.d
dbus_services_in_files = net.reactivated.Fprint.service.in dbus_services_in_files = net.reactivated.Fprint.service.in
dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) dbus_services_DATA = $(dbus_services_in_files:.service.in=.service)
$(dbus_services_DATA): $(dbus_services_in_files) $(dbus_services_DATA): $(dbus_services_in_files)
sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@
dbus_confdir = $(sysconfdir)/dbus-1/system.d
dbus_conf_DATA = net.reactivated.Fprint.conf dbus_conf_DATA = net.reactivated.Fprint.conf
polkitdir = $(datadir)/PolicyKit/policy
polkit_in_files = net.reactivated.fprint.device.policy.in
@INTLTOOL_POLICY_RULE@
polkit_DATA = $(polkit_in_files:.policy.in=.policy)
check:
$(POLKIT_POLICY_FILE_VALIDATE) $(polkit_DATA)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
<vendor>The FPrint Project</vendor>
<vendor_url>http://reactivated.net/fprint/</vendor_url>
<icon_name>fprint</icon_name>
<action id="net.reactivated.fprint.device.verify">
<_description>Verify a fingerprint</_description>
<_message>Privileges are required to verify fingerprints.</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="net.reactivated.fprint.device.enroll">
<_description>Enroll new fingerprints</_description>
<_message>Privileges are required to enroll new fingerprints.</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="net.reactivated.fprint.device.setusername">
<_description>Select a user to enroll</_description>
<_message>Privileges are required to enroll new fingerprints for other users.</_message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep_always</allow_active>
</defaults>
</action>
</policyconfig>
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
extern DBusGConnection *fprintd_dbus_conn; extern DBusGConnection *fprintd_dbus_conn;
static void fprint_device_set_username(FprintDevice *rdev,
const char *username,
DBusGMethodInvocation *context);
static void fprint_device_claim(FprintDevice *rdev, static void fprint_device_claim(FprintDevice *rdev,
DBusGMethodInvocation *context); DBusGMethodInvocation *context);
static void fprint_device_release(FprintDevice *rdev, static void fprint_device_release(FprintDevice *rdev,
...@@ -89,9 +92,8 @@ struct FprintDevicePrivate { ...@@ -89,9 +92,8 @@ struct FprintDevicePrivate {
char *sender; char *sender;
/* Either the current user of the device, or if allowed, /* Either the current user of the device, or if allowed,
* what was set using SetCurrentUid */ * what was set using SetUsername */
char *username; char *username;
uid_t uid;
/* type of storage */ /* type of storage */
int storage_type; int storage_type;
...@@ -257,18 +259,15 @@ _fprint_device_check_claimed (FprintDevice *rdev, ...@@ -257,18 +259,15 @@ _fprint_device_check_claimed (FprintDevice *rdev,
} }
static gboolean static gboolean
_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action) _fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
{ {
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
const char *sender; const char *sender;
GError *error;
DBusError dbus_error; DBusError dbus_error;
PolKitCaller *pk_caller; PolKitCaller *pk_caller;
PolKitAction *pk_action; PolKitAction *pk_action;
PolKitResult pk_result; PolKitResult pk_result;
error = NULL;
/* Check that caller is privileged */ /* Check that caller is privileged */
sender = dbus_g_method_get_sender (context); sender = dbus_g_method_get_sender (context);
dbus_error_init (&dbus_error); dbus_error_init (&dbus_error);
...@@ -277,38 +276,103 @@ _check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, co ...@@ -277,38 +276,103 @@ _check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, co
sender, sender,
&dbus_error); &dbus_error);
if (pk_caller == NULL) { if (pk_caller == NULL) {
error = g_error_new (FPRINT_ERROR, g_set_error (error, FPRINT_ERROR,
FPRINT_ERROR_INTERNAL, FPRINT_ERROR_INTERNAL,
"Error getting information about caller: %s: %s", "Error getting information about caller: %s: %s",
dbus_error.name, dbus_error.message); dbus_error.name, dbus_error.message);
dbus_error_free (&dbus_error); dbus_error_free (&dbus_error);
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE; return FALSE;
} }
pk_action = polkit_action_new (); pk_action = polkit_action_new ();
polkit_action_set_action_id (pk_action, action); polkit_action_set_action_id (pk_action, action);
pk_result = polkit_context_is_caller_authorized (priv->pol_ctx, pk_action, pk_caller, pk_result = polkit_context_is_caller_authorized (priv->pol_ctx, pk_action, pk_caller,
FALSE, NULL); TRUE, NULL);
polkit_caller_unref (pk_caller); polkit_caller_unref (pk_caller);
polkit_action_unref (pk_action); polkit_action_unref (pk_action);
if (pk_result != POLKIT_RESULT_YES) { if (pk_result != POLKIT_RESULT_YES) {
error = g_error_new (FPRINT_ERROR, g_set_error (error, FPRINT_ERROR,
FPRINT_ERROR_INTERNAL, FPRINT_ERROR_INTERNAL,
"%s %s <-- (action, result)", "%s %s <-- (action, result)",
action, action,
polkit_result_to_string_representation (pk_result)); polkit_result_to_string_representation (pk_result));
dbus_error_free (&dbus_error); dbus_error_free (&dbus_error);
dbus_g_method_return_error (context, error);
g_error_free (error);
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
static gboolean
_fprint_device_check_polkit_for_actions (FprintDevice *rdev,
DBusGMethodInvocation *context,
const char *action1,
const char *action2,
GError **error)
{
if (_fprint_device_check_polkit_for_action (rdev, context, action1, error) != FALSE)
return TRUE;
g_error_free (*error);
*error = NULL;
return _fprint_device_check_polkit_for_action (rdev, context, action2, error);
}
static void
fprint_device_set_username (FprintDevice *rdev,
const char *username,
DBusGMethodInvocation *context)
{
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
GError *error = NULL;
struct session_data *session = priv->session;
GSList *elem = session->loaded_prints;
if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
if (username == NULL) {
dbus_g_method_return (context);
return;
}
/* We already have a username, check if the one we're
* setting is the same */
if (g_str_equal (username, priv->username) != FALSE) {
dbus_g_method_return (context);
return;
}
g_free (priv->username);
priv->username = g_strdup (username);
/* Any fingerprints to unload? */
if (!elem) {
dbus_g_method_return (context);
return;
}
/* Empty the fingerprints, as we have a different user */
do {
struct loaded_print *print = elem->data;
session->loaded_prints = g_slist_delete_link(session->loaded_prints,
elem);
g_slice_free(struct loaded_print, print);
} while ((elem = g_slist_next(elem)) != NULL);
dbus_g_method_return (context);
}
static void dev_open_cb(struct fp_dev *dev, int status, void *user_data) static void dev_open_cb(struct fp_dev *dev, int status, void *user_data)
{ {
FprintDevice *rdev = user_data; FprintDevice *rdev = user_data;
...@@ -353,6 +417,14 @@ static void fprint_device_claim(FprintDevice *rdev, ...@@ -353,6 +417,14 @@ static void fprint_device_claim(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_actions (rdev, context,
"net.reactivated.fprint.device.verify",
"net.reactivated.fprint.device.enroll",
&error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
/* Get details about the current sender, and username/uid */ /* Get details about the current sender, and username/uid */
conn = dbus_g_connection_get_connection (fprintd_dbus_conn); conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
sender = dbus_g_method_get_sender (context); sender = dbus_g_method_get_sender (context);
...@@ -430,6 +502,15 @@ static void fprint_device_release(FprintDevice *rdev, ...@@ -430,6 +502,15 @@ static void fprint_device_release(FprintDevice *rdev,
return; return;
} }
/* People that can claim can also release */
if (_fprint_device_check_polkit_for_actions (rdev, context,
"net.reactivated.fprint.device.verify",
"net.reactivated.fprint.device.enroll",
&error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
/* Unload any loaded prints */ /* Unload any loaded prints */
if (elem) { if (elem) {
do do
...@@ -455,6 +536,11 @@ static void fprint_device_unload_print_data(FprintDevice *rdev, ...@@ -455,6 +536,11 @@ static void fprint_device_unload_print_data(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
g_message("unload print data %d for device %d", print_id, priv->id); g_message("unload print data %d for device %d", print_id, priv->id);
if (!elem) { if (!elem) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT, g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
...@@ -505,6 +591,11 @@ static void fprint_device_verify_start(FprintDevice *rdev, ...@@ -505,6 +591,11 @@ static void fprint_device_verify_start(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
g_message("start verification device %d print %d", priv->id, print_id); g_message("start verification device %d print %d", priv->id, print_id);
if (!elem) { if (!elem) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT, g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
...@@ -557,6 +648,11 @@ static void fprint_device_verify_stop(FprintDevice *rdev, ...@@ -557,6 +648,11 @@ static void fprint_device_verify_stop(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
r = fp_async_verify_stop(priv->dev, verify_stop_cb, context); r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
if (r < 0) { if (r < 0) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP, g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP,
...@@ -598,6 +694,11 @@ static void fprint_device_enroll_start(FprintDevice *rdev, ...@@ -598,6 +694,11 @@ static void fprint_device_enroll_start(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
g_message("start enrollment device %d finger %d", priv->id, finger_num); g_message("start enrollment device %d finger %d", priv->id, finger_num);
session->enroll_finger = finger_num; session->enroll_finger = finger_num;
...@@ -629,6 +730,11 @@ static void fprint_device_enroll_stop(FprintDevice *rdev, ...@@ -629,6 +730,11 @@ static void fprint_device_enroll_stop(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context); r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
if (r < 0) { if (r < 0) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP, g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP,
...@@ -666,6 +772,11 @@ static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, ...@@ -666,6 +772,11 @@ static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
prints = storages[priv->storage_type].discover_prints(priv->dev, priv->username); prints = storages[priv->storage_type].discover_prints(priv->dev, priv->username);
if (!prints) { if (!prints) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS, g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS,
...@@ -700,6 +811,11 @@ static void fprint_device_load_print_data(FprintDevice *rdev, ...@@ -700,6 +811,11 @@ static void fprint_device_load_print_data(FprintDevice *rdev,
return; return;
} }
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
r = storages[priv->storage_type].print_data_load(priv->dev, (enum fp_finger)finger_num, r = storages[priv->storage_type].print_data_load(priv->dev, (enum fp_finger)finger_num,
&data, priv->username); &data, priv->username);
......
...@@ -60,6 +60,11 @@ ...@@ -60,6 +60,11 @@
<annotation name="org.freedesktop.DBus.GLib.Async" value="" /> <annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method> </method>
<method name="SetUsername">
<arg type="s" name="username" direction="in" />
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
</interface> </interface>
</node> </node>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment