accounts-service: Add allow-user-installation setting

This controls whether the user can install to their user repository at
all; if it’s true (the default), then installation of apps is still
subject to the OARS filter.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

https://phabricator.endlessm.com/T24457
This commit is contained in:
Philip Withnall 2018-11-29 21:09:57 +00:00
parent 3ec77740c7
commit 222b436a61
5 changed files with 133 additions and 4 deletions

View File

@ -60,6 +60,21 @@
value="('oars-1.1', @a{ss} {})"/> value="('oars-1.1', @a{ss} {})"/>
</property> </property>
<!--
allow-user-installation:
Whether this user is allowed to install to their flatpak user repository.
If this is true, and if the polkit check for allowing app installation
succeeds, and if the oars-filter does not restrict this app, app
installation can proceed.
If this is false, the user is not allowed to install any apps or runtimes
to their flatpak user repository.
-->
<property name="allow-user-installation" type="b" access="readwrite">
<annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
</property>
<!-- <!--
allow-system-installation: allow-system-installation:

View File

@ -138,6 +138,11 @@ def command_get(user, quiet=False, interactive=True):
if not sections: if not sections:
print(' (No OARS values)') print(' (No OARS values)')
if app_filter.is_user_installation_allowed():
print('App installation is allowed to user repository')
else:
print('App installation is disallowed to user repository')
if app_filter.is_system_installation_allowed(): if app_filter.is_system_installation_allowed():
print('App installation is allowed to system repository') print('App installation is allowed to system repository')
else: else:
@ -186,11 +191,13 @@ def command_oars_section(user, section, quiet=False, interactive=True):
section, user_id, __oars_value_to_string(value))) section, user_id, __oars_value_to_string(value)))
def command_set(user, allow_system_installation=False, app_filter_args=None, def command_set(user, allow_user_installation=True,
allow_system_installation=False, app_filter_args=None,
quiet=False, interactive=True): quiet=False, interactive=True):
"""Set the app filter for the given user.""" """Set the app filter for the given user."""
user_id = __lookup_user_id_or_error(user) user_id = __lookup_user_id_or_error(user)
builder = EosParentalControls.AppFilterBuilder.new() builder = EosParentalControls.AppFilterBuilder.new()
builder.set_allow_user_installation(allow_user_installation)
builder.set_allow_system_installation(allow_system_installation) builder.set_allow_system_installation(allow_system_installation)
for arg in app_filter_args: for arg in app_filter_args:
@ -277,6 +284,16 @@ def main():
parser_set.add_argument('user', default='', nargs='?', parser_set.add_argument('user', default='', nargs='?',
help='user ID or username to get the app filter ' help='user ID or username to get the app filter '
'for (default: current user)') 'for (default: current user)')
parser_set.add_argument('--allow-user-installation',
dest='allow_user_installation',
action='store_true',
help='allow installation to the user flatpak '
'repo in general')
parser_set.add_argument('--disallow-user-installation',
dest='allow_user_installation',
action='store_false',
help='unconditionally disallow installation to '
'the user flatpak repo')
parser_set.add_argument('--allow-system-installation', parser_set.add_argument('--allow-system-installation',
dest='allow_system_installation', dest='allow_system_installation',
action='store_true', action='store_true',
@ -290,7 +307,8 @@ def main():
parser_set.add_argument('app_filter_args', nargs='*', parser_set.add_argument('app_filter_args', nargs='*',
help='paths to blacklist and OARS section=value ' help='paths to blacklist and OARS section=value '
'pairs to store') 'pairs to store')
parser_set.set_defaults(allow_system_installation=False) parser_set.set_defaults(allow_user_installation=True,
allow_system_installation=False)
# Parse the command line arguments and run the subcommand. # Parse the command line arguments and run the subcommand.
args = parser.parse_args() args = parser.parse_args()

View File

@ -59,6 +59,7 @@ struct _EpcAppFilter
EpcAppFilterListType app_list_type; EpcAppFilterListType app_list_type;
GVariant *oars_ratings; /* (type a{ss}) (owned non-floating) */ GVariant *oars_ratings; /* (type a{ss}) (owned non-floating) */
gboolean allow_user_installation;
gboolean allow_system_installation; gboolean allow_system_installation;
}; };
@ -408,6 +409,28 @@ epc_app_filter_get_oars_value (EpcAppFilter *filter,
return EPC_APP_FILTER_OARS_VALUE_UNKNOWN; return EPC_APP_FILTER_OARS_VALUE_UNKNOWN;
} }
/**
* epc_app_filter_is_user_installation_allowed:
* @filter: an #EpcAppFilter
*
* Get whether the user is allowed to install to their flatpak user repository.
* This should be queried in addition to the OARS values
* (epc_app_filter_get_oars_value()) if it returns %FALSE, the OARS values
* should be ignored and app installation should be unconditionally disallowed.
*
* Returns: %TRUE if app installation is allowed to the user repository for
* this user; %FALSE if it is unconditionally disallowed for this user
* Since: 0.1.0
*/
gboolean
epc_app_filter_is_user_installation_allowed (EpcAppFilter *filter)
{
g_return_val_if_fail (filter != NULL, FALSE);
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
return filter->allow_user_installation;
}
/** /**
* epc_app_filter_is_system_installation_allowed: * epc_app_filter_is_system_installation_allowed:
* @filter: an #EpcAppFilter * @filter: an #EpcAppFilter
@ -566,6 +589,7 @@ epc_get_app_filter (GDBusConnection *connection,
const gchar *content_rating_kind; const gchar *content_rating_kind;
g_autoptr(GVariant) oars_variant = NULL; g_autoptr(GVariant) oars_variant = NULL;
g_autoptr(GHashTable) oars_map = NULL; g_autoptr(GHashTable) oars_map = NULL;
gboolean allow_user_installation;
gboolean allow_system_installation; gboolean allow_system_installation;
g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), NULL); g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), NULL);
@ -638,6 +662,13 @@ epc_get_app_filter (GDBusConnection *connection,
return NULL; return NULL;
} }
if (!g_variant_lookup (properties, "allow-user-installation", "b",
&allow_user_installation))
{
/* Default value. */
allow_user_installation = TRUE;
}
if (!g_variant_lookup (properties, "allow-system-installation", "b", if (!g_variant_lookup (properties, "allow-system-installation", "b",
&allow_system_installation)) &allow_system_installation))
{ {
@ -653,6 +684,7 @@ epc_get_app_filter (GDBusConnection *connection,
app_filter->app_list_type = app_filter->app_list_type =
is_whitelist ? EPC_APP_FILTER_LIST_WHITELIST : EPC_APP_FILTER_LIST_BLACKLIST; is_whitelist ? EPC_APP_FILTER_LIST_WHITELIST : EPC_APP_FILTER_LIST_BLACKLIST;
app_filter->oars_ratings = g_steal_pointer (&oars_variant); app_filter->oars_ratings = g_steal_pointer (&oars_variant);
app_filter->allow_user_installation = allow_user_installation;
app_filter->allow_system_installation = allow_system_installation; app_filter->allow_system_installation = allow_system_installation;
return g_steal_pointer (&app_filter); return g_steal_pointer (&app_filter);
@ -798,9 +830,11 @@ epc_set_app_filter (GDBusConnection *connection,
g_autofree gchar *object_path = NULL; g_autofree gchar *object_path = NULL;
g_autoptr(GVariant) app_filter_variant = NULL; g_autoptr(GVariant) app_filter_variant = NULL;
g_autoptr(GVariant) oars_filter_variant = NULL; g_autoptr(GVariant) oars_filter_variant = NULL;
g_autoptr(GVariant) allow_user_installation_variant = NULL;
g_autoptr(GVariant) allow_system_installation_variant = NULL; g_autoptr(GVariant) allow_system_installation_variant = NULL;
g_autoptr(GVariant) app_filter_result_variant = NULL; g_autoptr(GVariant) app_filter_result_variant = NULL;
g_autoptr(GVariant) oars_filter_result_variant = NULL; g_autoptr(GVariant) oars_filter_result_variant = NULL;
g_autoptr(GVariant) allow_user_installation_result_variant = NULL;
g_autoptr(GVariant) allow_system_installation_result_variant = NULL; g_autoptr(GVariant) allow_system_installation_result_variant = NULL;
g_autoptr(GError) local_error = NULL; g_autoptr(GError) local_error = NULL;
@ -824,6 +858,7 @@ epc_set_app_filter (GDBusConnection *connection,
app_filter_variant = _epc_app_filter_build_app_filter_variant (app_filter); app_filter_variant = _epc_app_filter_build_app_filter_variant (app_filter);
oars_filter_variant = g_variant_new ("(s@a{ss})", "oars-1.1", oars_filter_variant = g_variant_new ("(s@a{ss})", "oars-1.1",
app_filter->oars_ratings); app_filter->oars_ratings);
allow_user_installation_variant = g_variant_new_boolean (app_filter->allow_user_installation);
allow_system_installation_variant = g_variant_new_boolean (app_filter->allow_system_installation); allow_system_installation_variant = g_variant_new_boolean (app_filter->allow_system_installation);
app_filter_result_variant = app_filter_result_variant =
@ -872,6 +907,29 @@ epc_set_app_filter (GDBusConnection *connection,
return FALSE; return FALSE;
} }
allow_user_installation_result_variant =
g_dbus_connection_call_sync (connection,
"org.freedesktop.Accounts",
object_path,
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new ("(ssv)",
"com.endlessm.ParentalControls.AppFilter",
"allow-user-installation",
g_steal_pointer (&allow_user_installation_variant)),
G_VARIANT_TYPE ("()"),
allow_interactive_authorization
? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION
: G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout, ms */
cancellable,
&local_error);
if (local_error != NULL)
{
g_propagate_error (error, bus_error_to_app_filter_error (local_error, user_id));
return FALSE;
}
allow_system_installation_result_variant = allow_system_installation_result_variant =
g_dbus_connection_call_sync (connection, g_dbus_connection_call_sync (connection,
"org.freedesktop.Accounts", "org.freedesktop.Accounts",
@ -1026,6 +1084,7 @@ typedef struct
{ {
GPtrArray *paths_blacklist; /* (nullable) (owned) (element-type filename) */ GPtrArray *paths_blacklist; /* (nullable) (owned) (element-type filename) */
GHashTable *oars; /* (nullable) (owned) (element-type utf8 EpcAppFilterOarsValue) */ GHashTable *oars; /* (nullable) (owned) (element-type utf8 EpcAppFilterOarsValue) */
gboolean allow_user_installation;
gboolean allow_system_installation; gboolean allow_system_installation;
/*< private >*/ /*< private >*/
@ -1141,6 +1200,7 @@ epc_app_filter_builder_copy (EpcAppFilterBuilder *builder)
_copy->paths_blacklist = g_ptr_array_ref (_builder->paths_blacklist); _copy->paths_blacklist = g_ptr_array_ref (_builder->paths_blacklist);
if (_builder->oars != NULL) if (_builder->oars != NULL)
_copy->oars = g_hash_table_ref (_builder->oars); _copy->oars = g_hash_table_ref (_builder->oars);
_copy->allow_user_installation = _builder->allow_user_installation;
_copy->allow_system_installation = _builder->allow_system_installation; _copy->allow_system_installation = _builder->allow_system_installation;
return g_steal_pointer (&copy); return g_steal_pointer (&copy);
@ -1225,6 +1285,7 @@ epc_app_filter_builder_end (EpcAppFilterBuilder *builder)
app_filter->app_list = (gchar **) g_ptr_array_free (g_steal_pointer (&_builder->paths_blacklist), FALSE); app_filter->app_list = (gchar **) g_ptr_array_free (g_steal_pointer (&_builder->paths_blacklist), FALSE);
app_filter->app_list_type = EPC_APP_FILTER_LIST_BLACKLIST; app_filter->app_list_type = EPC_APP_FILTER_LIST_BLACKLIST;
app_filter->oars_ratings = g_steal_pointer (&oars_variant); app_filter->oars_ratings = g_steal_pointer (&oars_variant);
app_filter->allow_user_installation = _builder->allow_user_installation;
app_filter->allow_system_installation = _builder->allow_system_installation; app_filter->allow_system_installation = _builder->allow_system_installation;
epc_app_filter_builder_clear (builder); epc_app_filter_builder_clear (builder);
@ -1315,6 +1376,30 @@ epc_app_filter_builder_set_oars_value (EpcAppFilterBuilder *builder,
GUINT_TO_POINTER (value)); GUINT_TO_POINTER (value));
} }
/**
* epc_app_filter_builder_set_allow_user_installation:
* @builder: an initialised #EpcAppFilterBuilder
* @allow_user_installation: %TRUE to allow app installation; %FALSE to
* unconditionally disallow it
*
* Set whether the user is allowed to install to their flatpak user repository.
* If this is %TRUE, app installation is still subject to the OARS values
* (epc_app_filter_builder_set_oars_value()). If it is %FALSE, app installation
* is unconditionally disallowed for this user.
*
* Since: 0.1.0
*/
void
epc_app_filter_builder_set_allow_user_installation (EpcAppFilterBuilder *builder,
gboolean allow_user_installation)
{
EpcAppFilterBuilderReal *_builder = (EpcAppFilterBuilderReal *) builder;
g_return_if_fail (_builder != NULL);
_builder->allow_user_installation = allow_user_installation;
}
/** /**
* epc_app_filter_builder_set_allow_system_installation: * epc_app_filter_builder_set_allow_system_installation:
* @builder: an initialised #EpcAppFilterBuilder * @builder: an initialised #EpcAppFilterBuilder

View File

@ -111,6 +111,7 @@ const gchar **epc_app_filter_get_oars_sections (EpcAppFilter *filter);
EpcAppFilterOarsValue epc_app_filter_get_oars_value (EpcAppFilter *filter, EpcAppFilterOarsValue epc_app_filter_get_oars_value (EpcAppFilter *filter,
const gchar *oars_section); const gchar *oars_section);
gboolean epc_app_filter_is_user_installation_allowed (EpcAppFilter *filter);
gboolean epc_app_filter_is_system_installation_allowed (EpcAppFilter *filter); gboolean epc_app_filter_is_system_installation_allowed (EpcAppFilter *filter);
EpcAppFilter *epc_get_app_filter (GDBusConnection *connection, EpcAppFilter *epc_get_app_filter (GDBusConnection *connection,
@ -159,6 +160,7 @@ typedef struct
gpointer p0; gpointer p0;
gpointer p1; gpointer p1;
gboolean b0; gboolean b0;
gboolean b1;
gpointer p2; gpointer p2;
gpointer p3; gpointer p3;
} EpcAppFilterBuilder; } EpcAppFilterBuilder;
@ -182,6 +184,7 @@ GType epc_app_filter_builder_get_type (void);
{ \ { \
g_ptr_array_new_with_free_func (g_free), \ g_ptr_array_new_with_free_func (g_free), \
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL), \ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL), \
TRUE, \
FALSE, \ FALSE, \
} }
@ -207,6 +210,8 @@ void epc_app_filter_builder_set_oars_value (EpcAppFilterBuilder *builde
const gchar *oars_section, const gchar *oars_section,
EpcAppFilterOarsValue value); EpcAppFilterOarsValue value);
void epc_app_filter_builder_set_allow_user_installation (EpcAppFilterBuilder *builder,
gboolean allow_user_installation);
void epc_app_filter_builder_set_allow_system_installation (EpcAppFilterBuilder *builder, void epc_app_filter_builder_set_allow_system_installation (EpcAppFilterBuilder *builder,
gboolean allow_system_installation); gboolean allow_system_installation);

View File

@ -125,6 +125,7 @@ test_app_filter_builder_non_empty (BuilderFixture *fixture,
EPC_APP_FILTER_OARS_VALUE_MILD); EPC_APP_FILTER_OARS_VALUE_MILD);
epc_app_filter_builder_set_oars_value (fixture->builder, "language-humor", epc_app_filter_builder_set_oars_value (fixture->builder, "language-humor",
EPC_APP_FILTER_OARS_VALUE_MODERATE); EPC_APP_FILTER_OARS_VALUE_MODERATE);
epc_app_filter_builder_set_allow_user_installation (fixture->builder, TRUE);
epc_app_filter_builder_set_allow_system_installation (fixture->builder, FALSE); epc_app_filter_builder_set_allow_system_installation (fixture->builder, FALSE);
filter = epc_app_filter_builder_end (fixture->builder); filter = epc_app_filter_builder_end (fixture->builder);
@ -151,6 +152,7 @@ test_app_filter_builder_non_empty (BuilderFixture *fixture,
const gchar * const expected_sections[] = { "drugs-alcohol", "language-humor", NULL }; const gchar * const expected_sections[] = { "drugs-alcohol", "language-humor", NULL };
assert_strv_equal ((const gchar * const *) sections, expected_sections); assert_strv_equal ((const gchar * const *) sections, expected_sections);
g_assert_true (epc_app_filter_is_user_installation_allowed (filter));
g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); g_assert_false (epc_app_filter_is_system_installation_allowed (filter));
} }
@ -186,6 +188,7 @@ test_app_filter_builder_empty (BuilderFixture *fixture,
const gchar * const expected_sections[] = { NULL }; const gchar * const expected_sections[] = { NULL };
assert_strv_equal ((const gchar * const *) sections, expected_sections); assert_strv_equal ((const gchar * const *) sections, expected_sections);
g_assert_true (epc_app_filter_is_user_installation_allowed (filter));
g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); g_assert_false (epc_app_filter_is_system_installation_allowed (filter));
} }
@ -208,6 +211,7 @@ test_app_filter_builder_copy_empty (void)
g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false"));
g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true")); g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true"));
g_assert_true (epc_app_filter_is_user_installation_allowed (filter));
g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); g_assert_false (epc_app_filter_is_system_installation_allowed (filter));
} }
@ -221,13 +225,15 @@ test_app_filter_builder_copy_full (void)
g_autoptr(EpcAppFilter) filter = NULL; g_autoptr(EpcAppFilter) filter = NULL;
epc_app_filter_builder_blacklist_path (builder, "/bin/true"); epc_app_filter_builder_blacklist_path (builder, "/bin/true");
epc_app_filter_builder_set_allow_system_installation (builder, FALSE); epc_app_filter_builder_set_allow_user_installation (builder, FALSE);
epc_app_filter_builder_set_allow_system_installation (builder, TRUE);
builder_copy = epc_app_filter_builder_copy (builder); builder_copy = epc_app_filter_builder_copy (builder);
filter = epc_app_filter_builder_end (builder_copy); filter = epc_app_filter_builder_end (builder_copy);
g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false"));
g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true")); g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true"));
g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); g_assert_false (epc_app_filter_is_user_installation_allowed (filter));
g_assert_true (epc_app_filter_is_system_installation_allowed (filter));
} }
int int