diff options
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/polkitbackend/Makefile.am | 3 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendauthority.c | 109 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendinteractiveauthority.c | 132 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendjsauthority.c | 831 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendjsauthority.h | 75 | ||||
-rw-r--r-- | src/polkitbackend/polkitbackendtypes.h | 3 | ||||
-rw-r--r-- | test/data/etc/polkit-1/rules.d/10-testing.rules | 32 | ||||
-rw-r--r-- | test/polkitbackend/Makefile.am | 4 | ||||
-rw-r--r-- | test/polkitbackend/test-polkitbackendjsauthority.c | 153 |
10 files changed, 1340 insertions, 6 deletions
diff --git a/configure.ac b/configure.ac index f325922..4f2ac6f 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,10 @@ PKG_CHECK_MODULES(GLIB, [gio-2.0 >= 2.28.0]) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) +PKG_CHECK_MODULES(LIBJS, [libjs >= 1.8.5]) +AC_SUBST(LIBJS_CFLAGS) +AC_SUBST(LIBJS_LIBS) + EXPAT_LIB="" AC_ARG_WITH(expat, [ --with-expat=<dir> Use expat from here], [ diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am index b91cafa..2f6fd05 100644 --- a/src/polkitbackend/Makefile.am +++ b/src/polkitbackend/Makefile.am @@ -37,6 +37,7 @@ libpolkit_backend_1_la_SOURCES = \ polkitbackendauthority.h polkitbackendauthority.c \ polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \ polkitbackendlocalauthority.h polkitbackendlocalauthority.c \ + polkitbackendjsauthority.h polkitbackendjsauthority.c \ polkitbackendactionpool.h polkitbackendactionpool.c \ polkitbackendconfigsource.h polkitbackendconfigsource.c \ polkitbackendactionlookup.h polkitbackendactionlookup.c \ @@ -56,6 +57,7 @@ libpolkit_backend_1_la_CFLAGS = \ -D_POLKIT_BACKEND_COMPILATION \ $(GLIB_CFLAGS) \ $(SYSTEMD_CFLAGS) \ + $(LIBJS_CFLAGS) \ $(NULL) libpolkit_backend_1_la_LIBADD = \ @@ -63,6 +65,7 @@ libpolkit_backend_1_la_LIBADD = \ $(SYSTEMD_LIBS) \ $(top_builddir)/src/polkit/libpolkit-gobject-1.la \ $(EXPAT_LIBS) \ + $(LIBJS_LIBS) \ $(NULL) libpolkit_backend_1_la_LDFLAGS = -export-symbols-regex '(^polkit_.*)' diff --git a/src/polkitbackend/polkitbackendauthority.c b/src/polkitbackend/polkitbackendauthority.c index fd4f161..e127247 100644 --- a/src/polkitbackend/polkitbackendauthority.c +++ b/src/polkitbackend/polkitbackendauthority.c @@ -31,6 +31,7 @@ #include "polkitbackendauthority.h" #include "polkitbackendlocalauthority.h" +#include "polkitbackendjsauthority.h" #include "polkitbackendprivate.h" @@ -1359,6 +1360,7 @@ polkit_backend_authority_get (void) { static GIOExtensionPoint *ep = NULL; static volatile GType local_authority_type = G_TYPE_INVALID; + static volatile GType js_authority_type = G_TYPE_INVALID; GList *modules; GList *authority_implementations; GType authority_type; @@ -1374,9 +1376,9 @@ polkit_backend_authority_get (void) /* make sure local types are registered */ if (local_authority_type == G_TYPE_INVALID) - { - local_authority_type = POLKIT_BACKEND_TYPE_LOCAL_AUTHORITY; - } + local_authority_type = POLKIT_BACKEND_TYPE_LOCAL_AUTHORITY; + if (js_authority_type == G_TYPE_INVALID) + js_authority_type = POLKIT_BACKEND_TYPE_JS_AUTHORITY; /* load all modules */ modules = g_io_modules_load_all_in_directory (PACKAGE_LIB_DIR "/polkit-1/extensions"); @@ -1416,17 +1418,114 @@ polkit_backend_authority_get (void) return authority; } +/* ---------------------------------------------------------------------------------------------------- */ + +typedef enum +{ + _COLOR_RESET, + _COLOR_BOLD_ON, + _COLOR_INVERSE_ON, + _COLOR_BOLD_OFF, + _COLOR_FG_BLACK, + _COLOR_FG_RED, + _COLOR_FG_GREEN, + _COLOR_FG_YELLOW, + _COLOR_FG_BLUE, + _COLOR_FG_MAGENTA, + _COLOR_FG_CYAN, + _COLOR_FG_WHITE, + _COLOR_BG_RED, + _COLOR_BG_GREEN, + _COLOR_BG_YELLOW, + _COLOR_BG_BLUE, + _COLOR_BG_MAGENTA, + _COLOR_BG_CYAN, + _COLOR_BG_WHITE +} _Color; + +static gboolean _color_stdin_is_tty = FALSE; +static gboolean _color_initialized = FALSE; + +static void +_color_init (void) +{ + if (_color_initialized) + return; + _color_initialized = TRUE; + _color_stdin_is_tty = (isatty (STDIN_FILENO) != 0 && isatty (STDOUT_FILENO) != 0); +} + +static const gchar * +_color_get (_Color color) +{ + const gchar *str; + + _color_init (); + + if (!_color_stdin_is_tty) + return ""; + + str = NULL; + switch (color) + { + case _COLOR_RESET: str="\x1b[0m"; break; + case _COLOR_BOLD_ON: str="\x1b[1m"; break; + case _COLOR_INVERSE_ON: str="\x1b[7m"; break; + case _COLOR_BOLD_OFF: str="\x1b[22m"; break; + case _COLOR_FG_BLACK: str="\x1b[30m"; break; + case _COLOR_FG_RED: str="\x1b[31m"; break; + case _COLOR_FG_GREEN: str="\x1b[32m"; break; + case _COLOR_FG_YELLOW: str="\x1b[33m"; break; + case _COLOR_FG_BLUE: str="\x1b[34m"; break; + case _COLOR_FG_MAGENTA: str="\x1b[35m"; break; + case _COLOR_FG_CYAN: str="\x1b[36m"; break; + case _COLOR_FG_WHITE: str="\x1b[37m"; break; + case _COLOR_BG_RED: str="\x1b[41m"; break; + case _COLOR_BG_GREEN: str="\x1b[42m"; break; + case _COLOR_BG_YELLOW: str="\x1b[43m"; break; + case _COLOR_BG_BLUE: str="\x1b[44m"; break; + case _COLOR_BG_MAGENTA: str="\x1b[45m"; break; + case _COLOR_BG_CYAN: str="\x1b[46m"; break; + case _COLOR_BG_WHITE: str="\x1b[47m"; break; + default: + g_assert_not_reached (); + break; + } + return str; +} + +/* ---------------------------------------------------------------------------------------------------- */ + void polkit_backend_authority_log (PolkitBackendAuthority *authority, const gchar *format, ...) { + GTimeVal now; + time_t now_time; + struct tm *now_tm; + gchar time_buf[128]; + gchar *message; va_list var_args; g_return_if_fail (POLKIT_BACKEND_IS_AUTHORITY (authority)); va_start (var_args, format); - vsyslog (LOG_NOTICE, format, var_args); - + message = g_strdup_vprintf (format, var_args); va_end (var_args); + + va_start (var_args, format); + syslog (LOG_NOTICE, "%s", message); + + g_get_current_time (&now); + now_time = (time_t) now.tv_sec; + now_tm = localtime (&now_time); + strftime (time_buf, sizeof time_buf, "%H:%M:%S", now_tm); + g_print ("%s%s%s.%03d%s: %s\n", + _color_get (_COLOR_BOLD_ON), _color_get (_COLOR_FG_YELLOW), + time_buf, (gint) now.tv_usec / 1000, + _color_get (_COLOR_RESET), + message); + + g_free (message); } diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c index b237e9d..5f6eea5 100644 --- a/src/polkitbackend/polkitbackendinteractiveauthority.c +++ b/src/polkitbackend/polkitbackendinteractiveauthority.c @@ -23,6 +23,7 @@ #include <errno.h> #include <pwd.h> #include <grp.h> +#include <netdb.h> #include <string.h> #include <glib/gstdio.h> #include <locale.h> @@ -2059,6 +2060,110 @@ add_pid (PolkitDetails *details, ; } +/* ---------------------------------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------------------------------------- */ + +static GList * +get_users_in_group (PolkitIdentity *group, + gboolean include_root) +{ + gid_t gid; + struct group *grp; + GList *ret; + guint n; + + ret = NULL; + + gid = polkit_unix_group_get_gid (POLKIT_UNIX_GROUP (group)); + grp = getgrgid (gid); + if (grp == NULL) + { + g_warning ("Error looking up group with gid %d: %s", gid, g_strerror (errno)); + goto out; + } + + for (n = 0; grp->gr_mem != NULL && grp->gr_mem[n] != NULL; n++) + { + PolkitIdentity *user; + GError *error; + + if (!include_root && g_strcmp0 (grp->gr_mem[n], "root") == 0) + continue; + + error = NULL; + user = polkit_unix_user_new_for_name (grp->gr_mem[n], &error); + if (user == NULL) + { + g_warning ("Unknown username '%s' in group: %s", grp->gr_mem[n], error->message); + g_error_free (error); + } + else + { + ret = g_list_prepend (ret, user); + } + } + + ret = g_list_reverse (ret); + + out: + return ret; +} + +static GList * +get_users_in_net_group (PolkitIdentity *group, + gboolean include_root) +{ + const gchar *name; + GList *ret; + + ret = NULL; + name = polkit_unix_netgroup_get_name (POLKIT_UNIX_NETGROUP (group)); + + if (setnetgrent (name) == 0) + { + g_warning ("Error looking up net group with name %s: %s", name, g_strerror (errno)); + goto out; + } + + for (;;) + { + char *hostname, *username, *domainname; + PolkitIdentity *user; + GError *error = NULL; + + if (getnetgrent (&hostname, &username, &domainname) == 0) + break; + + /* Skip NULL entries since we never want to make everyone an admin + * Skip "-" entries which mean "no match ever" in netgroup land */ + if (username == NULL || g_strcmp0 (username, "-") == 0) + continue; + + /* TODO: Should we match on hostname? Maybe only allow "-" as a hostname + * for safety. */ + + user = polkit_unix_user_new_for_name (username, &error); + if (user == NULL) + { + g_warning ("Unknown username '%s' in unix-netgroup: %s", username, error->message); + g_error_free (error); + } + else + { + ret = g_list_prepend (ret, user); + } + } + + ret = g_list_reverse (ret); + + out: + endnetgrent (); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + static void authentication_agent_initiate_challenge (AuthenticationAgent *agent, PolkitSubject *subject, @@ -2080,6 +2185,7 @@ authentication_agent_initiate_challenge (AuthenticationAgent *agent, gchar *localized_icon_name; PolkitDetails *localized_details; GVariant *details_gvariant; + GList *user_identities = NULL; GVariantBuilder identities_builder; GVariant *parameters; @@ -2138,10 +2244,33 @@ authentication_agent_initiate_challenge (AuthenticationAgent *agent, details_gvariant = polkit_details_to_gvariant (localized_details); g_variant_ref_sink (details_gvariant); - g_variant_builder_init (&identities_builder, G_VARIANT_TYPE ("a(sa{sv})")); + /* expand groups/netgroups to users */ + user_identities = NULL; for (l = identities; l != NULL; l = l->next) { PolkitIdentity *identity = POLKIT_IDENTITY (l->data); + if (POLKIT_IS_UNIX_USER (identity)) + { + user_identities = g_list_append (user_identities, g_object_ref (identity)); + } + else if (POLKIT_IS_UNIX_GROUP (identity)) + { + user_identities = g_list_concat (user_identities, get_users_in_group (identity, FALSE)); + } + else if (POLKIT_IS_UNIX_NETGROUP (identity)) + { + user_identities = g_list_concat (user_identities, get_users_in_net_group (identity, FALSE)); + } + else + { + g_warning ("Unsupported identity"); + } + } + + g_variant_builder_init (&identities_builder, G_VARIANT_TYPE ("a(sa{sv})")); + for (l = user_identities; l != NULL; l = l->next) + { + PolkitIdentity *identity = POLKIT_IDENTITY (l->data); GVariant *value; value = polkit_identity_to_gvariant (identity); g_variant_ref_sink (value); @@ -2167,6 +2296,7 @@ authentication_agent_initiate_challenge (AuthenticationAgent *agent, (GAsyncReadyCallback) authentication_agent_begin_cb, session); + g_list_free_full (user_identities, g_object_unref); g_list_foreach (identities, (GFunc) g_object_unref, NULL); g_list_free (identities); g_free (cookie); diff --git a/src/polkitbackend/polkitbackendjsauthority.c b/src/polkitbackend/polkitbackendjsauthority.c new file mode 100644 index 0000000..23d2640 --- /dev/null +++ b/src/polkitbackend/polkitbackendjsauthority.c @@ -0,0 +1,831 @@ +/* + * Copyright (C) 2008-2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#include "config.h" +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <netdb.h> +#include <string.h> +#include <glib/gstdio.h> +#include <locale.h> +#include <glib/gi18n-lib.h> + +#include <polkit/polkit.h> +#include "polkitbackendjsauthority.h" + +#include <polkit/polkitprivate.h> + +#include <jsapi.h> + +/** + * SECTION:polkitbackendjsauthority + * @title: PolkitBackendJsAuthority + * @short_description: JS Authority + * @stability: Unstable + * + * An implementation of #PolkitBackendAuthority that reads and + * evalates Javascript files and supports interaction with + * authentication agents (virtue of being based on + * #PolkitBackendInteractiveAuthority). + */ + +/* ---------------------------------------------------------------------------------------------------- */ + +struct _PolkitBackendJsAuthorityPrivate +{ + gchar *rules_dir; + GFileMonitor *dir_monitor; + + JSRuntime *rt; + JSContext *cx; + JSObject *js_global; + JSObject *js_polkit; + + /* A list of JSObject instances */ + GList *scripts; +}; + +static void on_dir_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data); + +/* ---------------------------------------------------------------------------------------------------- */ + +enum +{ + PROP_0, + PROP_RULES_DIR, +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +static GList *polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + PolkitIdentity *user_for_subject, + const gchar *action_id, + PolkitDetails *details); + +static PolkitImplicitAuthorization polkit_backend_js_authority_check_authorization_sync ( + PolkitBackendInteractiveAuthority *authority, + PolkitSubject *caller, + PolkitSubject *subject, + PolkitIdentity *user_for_subject, + gboolean subject_is_local, + gboolean subject_is_active, + const gchar *action_id, + PolkitDetails *details, + PolkitImplicitAuthorization implicit, + PolkitDetails *out_details); + +G_DEFINE_TYPE_WITH_CODE (PolkitBackendJsAuthority, + polkit_backend_js_authority, + POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY, + g_io_extension_point_implement (POLKIT_BACKEND_AUTHORITY_EXTENSION_POINT_NAME, + g_define_type_id, + "js-authority" PACKAGE_VERSION, + 10)); + +/* ---------------------------------------------------------------------------------------------------- */ + +static JSClass js_global_class = { + "global", + JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, + JS_PropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +static JSClass js_polkit_class = { + "Polkit", + 0, + JS_PropertyStub, + JS_PropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub, + JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static JSBool js_polkit_log (JSContext *cx, uintN argc, jsval *vp); + +static JSFunctionSpec js_polkit_functions[] = +{ + JS_FS("log", js_polkit_log, 0, 0), + JS_FS_END +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +static void report_error (JSContext *cx, + const char *message, + JSErrorReport *report) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (JS_GetContextPrivate (cx)); + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "%s:%u: %s", + report->filename ? report->filename : "<no filename>", + (unsigned int) report->lineno, + message); +} + +static void +polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority) +{ + authority->priv = G_TYPE_INSTANCE_GET_PRIVATE (authority, + POLKIT_BACKEND_TYPE_JS_AUTHORITY, + PolkitBackendJsAuthorityPrivate); +} + +static void +load_scripts (PolkitBackendJsAuthority *authority) +{ + GDir *dir = NULL; + GList *files = NULL; + GList *l; + const gchar *name; + guint num_scripts = 0; + GError *error = NULL; + + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Loading scripts from directory %s", + authority->priv->rules_dir); + + dir = g_dir_open (authority->priv->rules_dir, + 0, + &error); + if (dir == NULL) + { + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Error opening rules directory: %s (%s, %d)\n", + error->message, g_quark_to_string (error->domain), error->code); + g_clear_error (&error); + goto out; + } + + files = NULL; + while ((name = g_dir_read_name (dir)) != NULL) + { + if (g_str_has_suffix (name, ".rules")) + files = g_list_prepend (files, g_strdup_printf ("%s/%s", authority->priv->rules_dir, name)); + } + + files = g_list_sort (files, (GCompareFunc) g_strcmp0); + + for (l = files; l != NULL; l = l->next) + { + const gchar *filename = l->data; + JSObject *script; + + script = JS_CompileFile (authority->priv->cx, + authority->priv->js_global, + filename); + if (script == NULL) + { + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Error compiling script %s", + filename); + continue; + } + + /* evaluate the script */ + jsval rval; + if (!JS_ExecuteScript (authority->priv->cx, + authority->priv->js_global, + script, + &rval)) + { + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Error executing script %s", + filename); + continue; + } + + //g_print ("Successfully loaded and evaluated script `%s'\n", filename); + + num_scripts++; + } + + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Finished loading, compiling and executing %d scripts", + num_scripts); + + out: + g_list_free_full (files, g_free); + if (dir != NULL) + g_dir_close (dir); +} + +static void +reload_scripts (PolkitBackendJsAuthority *authority) +{ + jsval argv[1] = {0}; + jsval rval = {0}; + + if (!JS_CallFunctionName(authority->priv->cx, + authority->priv->js_polkit, + "_deleteRules", + 0, + argv, + &rval)) + { + /* TODO: syslog? */ + g_printerr ("boo, faileded clearing rules\n"); + goto out; + } + + load_scripts (authority); + out: + ; +} + +static void +on_dir_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (user_data); + + /* TODO: maybe rate-limit so storms of events are collapsed into one with a 500ms resolution? + * Because when editing a file with emacs we get 4-8 events.. + */ + + if (file != NULL) + { + gchar *name; + + name = g_file_get_basename (file); + + /* g_print ("event_type=%d file=%p name=%s\n", event_type, file, name); */ + if (!g_str_has_prefix (name, ".") && + !g_str_has_prefix (name, "#") && + g_str_has_suffix (name, ".rules") && + (event_type == G_FILE_MONITOR_EVENT_CREATED || + event_type == G_FILE_MONITOR_EVENT_DELETED || + event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)) + { + polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority), + "Reloading scripts"); + reload_scripts (authority); + } + g_free (name); + } +} + +static const gchar js_polkit_init[] = + "polkit._administratorRuleFuncs = [];\n" + "polkit.addAdministratorRule = function(callback) {this._administratorRuleFuncs.push(callback);};\n" + "polkit._runAdministratorRules = function(action, pid, user, groups, is_local, is_active) {\n" + " var ret = null;\n" + " var subject = {};\n" + " subject.pid = pid;\n" + " subject.user = user;\n" + " subject.local = is_local;\n" + " subject.active = is_active;\n" + " subject.groups = groups.split(',');\n" + " for (var n = this._administratorRuleFuncs.length - 1; n >= 0; n--) {\n" + " var func = this._administratorRuleFuncs[n];\n" + " ret = func(action, subject);\n" + " if (ret)\n" + " break\n" + " }\n" + " return ret.join(',');\n" + "};\n" + "\n" + "polkit._authorizationRuleFuncs = [];\n" + "polkit.addAuthorizationRule = function(callback) {this._authorizationRuleFuncs.push(callback);};\n" + "polkit._runAuthorizationRules = function(action, pid, user, groups, is_local, is_active) {\n" + " var ret = null;\n" + " var subject = {};\n" + " subject.pid = pid;\n" + " subject.user = user;\n" + " subject.local = is_local;\n" + " subject.active = is_active;\n" + " subject.groups = groups.split(',');\n" + " for (var n = this._authorizationRuleFuncs.length - 1; n >= 0; n--) {\n" + " var func = this._authorizationRuleFuncs[n];\n" + " ret = func(action, subject);\n" + " if (ret)\n" + " break\n" + " }\n" + " return ret;\n" + "};\n" + "\n" + "polkit._deleteRules = function() {\n" + " this._administratorRuleFuncs = [];\n" + " this._authorizationRuleFuncs = [];\n" + "};\n" + "\n" + ""; + + +static void +polkit_backend_js_authority_constructed (GObject *object) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object); + + /* TODO: error checking */ + authority->priv->rt = JS_NewRuntime (8L * 1024L * 1024L); + authority->priv->cx = JS_NewContext (authority->priv->rt, 8192); + JS_SetOptions (authority->priv->cx, + JSOPTION_VAROBJFIX | + JSOPTION_JIT | + JSOPTION_METHODJIT); + JS_SetVersion(authority->priv->cx, JSVERSION_LATEST); + JS_SetErrorReporter(authority->priv->cx, report_error); + JS_SetContextPrivate (authority->priv->cx, authority); + + authority->priv->js_global = JS_NewCompartmentAndGlobalObject (authority->priv->cx, + &js_global_class, + NULL); + JS_InitStandardClasses (authority->priv->cx, authority->priv->js_global); + + authority->priv->js_polkit = JS_DefineObject(authority->priv->cx, + authority->priv->js_global, + "polkit", + &js_polkit_class, + NULL, + JSPROP_ENUMERATE); + JS_DefineFunctions (authority->priv->cx, + authority->priv->js_polkit, + js_polkit_functions); + + if (!JS_EvaluateScript (authority->priv->cx, + authority->priv->js_global, + js_polkit_init, + strlen (js_polkit_init), + NULL, /* filename */ + 0, /* lineno */ + NULL)) /* rval */ + { + g_printerr ("Error running init code\n"); + } + + load_scripts (authority); + + G_OBJECT_CLASS (polkit_backend_js_authority_parent_class)->constructed (object); +} + +static void +polkit_backend_js_authority_finalize (GObject *object) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object); + + g_free (authority->priv->rules_dir); + if (authority->priv->dir_monitor != NULL) + { + g_signal_handlers_disconnect_by_func (authority->priv->dir_monitor, + G_CALLBACK (on_dir_monitor_changed), + authority); + g_object_unref (authority->priv->dir_monitor); + } + + JS_DestroyContext (authority->priv->cx); + JS_DestroyRuntime (authority->priv->rt); + /* JS_ShutDown (); */ + + G_OBJECT_CLASS (polkit_backend_js_authority_parent_class)->finalize (object); +} + +static void +polkit_backend_js_authority_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object); + GFile *file; + GError *error; + + switch (property_id) + { + case PROP_RULES_DIR: + g_assert (authority->priv->rules_dir == NULL); + authority->priv->rules_dir = g_value_dup_string (value); + + file = g_file_new_for_path (authority->priv->rules_dir); + error = NULL; + authority->priv->dir_monitor = g_file_monitor_directory (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (authority->priv->dir_monitor == NULL) + { + g_warning ("Error monitoring directory %s: %s", + authority->priv->rules_dir, + error->message); + g_clear_error (&error); + } + else + { + g_signal_connect (authority->priv->dir_monitor, + "changed", + G_CALLBACK (on_dir_monitor_changed), + authority); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static const gchar * +polkit_backend_js_authority_get_name (PolkitBackendAuthority *authority) +{ + return "js"; +} + +static const gchar * +polkit_backend_js_authority_get_version (PolkitBackendAuthority *authority) +{ + return PACKAGE_VERSION; +} + +static PolkitAuthorityFeatures +polkit_backend_js_authority_get_features (PolkitBackendAuthority *authority) +{ + return POLKIT_AUTHORITY_FEATURES_TEMPORARY_AUTHORIZATION; +} + +static void +polkit_backend_js_authority_class_init (PolkitBackendJsAuthorityClass *klass) +{ + GObjectClass *gobject_class; + PolkitBackendAuthorityClass *authority_class; + PolkitBackendInteractiveAuthorityClass *interactive_authority_class; + + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = polkit_backend_js_authority_finalize; + gobject_class->set_property = polkit_backend_js_authority_set_property; + gobject_class->constructed = polkit_backend_js_authority_constructed; + + authority_class = POLKIT_BACKEND_AUTHORITY_CLASS (klass); + authority_class->get_name = polkit_backend_js_authority_get_name; + authority_class->get_version = polkit_backend_js_authority_get_version; + authority_class->get_features = polkit_backend_js_authority_get_features; + + interactive_authority_class = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_CLASS (klass); + interactive_authority_class->get_admin_identities = polkit_backend_js_authority_get_admin_auth_identities; + interactive_authority_class->check_authorization_sync = polkit_backend_js_authority_check_authorization_sync; + + g_object_class_install_property (gobject_class, + PROP_RULES_DIR, + g_param_spec_string ("rules-dir", + NULL, + NULL, + PACKAGE_SYSCONF_DIR "/polkit-1/rules.d", + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)); + + + g_type_class_add_private (klass, sizeof (PolkitBackendJsAuthorityPrivate)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +subject_to_js (PolkitBackendJsAuthority *authority, + PolkitSubject *subject, + PolkitIdentity *user_for_subject, + jsval *jsval_pid, + jsval *jsval_user, + jsval *jsval_groups, + GError **error) +{ + gboolean ret = FALSE; + JSString *user_name_jstr; + JSString *groups_jstr; + pid_t pid; + uid_t uid; + gchar *user_name = NULL; + GString *groups = NULL; + struct passwd *passwd; + + g_return_val_if_fail (jsval_pid != NULL, FALSE); + g_return_val_if_fail (jsval_user != NULL, FALSE); + g_return_val_if_fail (jsval_groups != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (POLKIT_IS_UNIX_PROCESS (subject)) + { + pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject)); + } + else if (POLKIT_IS_SYSTEM_BUS_NAME (subject)) + { + PolkitSubject *process; + process = polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject), NULL, error); + if (process == NULL) + goto out; + pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (process)); + g_object_unref (process); + } + else + { + g_assert_not_reached (); + } + + g_assert (POLKIT_IS_UNIX_USER (user_for_subject)); + uid = polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_for_subject)); + + groups = g_string_new (NULL); + + passwd = getpwuid (uid); + if (passwd == NULL) + { + user_name = g_strdup_printf ("%d", (gint) uid); + g_warning ("Error looking up info for uid %d: %m", (gint) uid); + } + else + { + gid_t gids[512]; + int num_gids = 512; + + user_name = g_strdup (passwd->pw_name); + + if (getgrouplist (passwd->pw_name, + passwd->pw_gid, + gids, + &num_gids) < 0) + { + g_warning ("Error looking up groups for uid %d: %m", (gint) uid); + } + else + { + gint n; + for (n = 0; n < num_gids; n++) + { + struct group *group; + if (n > 0) + g_string_append_c (groups, ','); + + group = getgrgid (gids[n]); + if (group == NULL) + { + g_string_append_printf (groups, "%d", (gint) gids[n]); + } + else + { + g_string_append_printf (groups, "%s", group->gr_name); + } + } + } + } + + user_name_jstr = JS_NewStringCopyZ (authority->priv->cx, user_name); + groups_jstr = JS_NewStringCopyZ (authority->priv->cx, groups->str); + *jsval_pid = INT_TO_JSVAL ((int32) pid); + *jsval_user = STRING_TO_JSVAL (user_name_jstr); + *jsval_groups = STRING_TO_JSVAL (groups_jstr); + + ret = TRUE; + + out: + /* TODO: are we leaking _jstr ? */ + g_free (user_name); + if (groups != NULL) + g_string_free (groups, TRUE); + return ret; +} + + +static GList * +polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority, + PolkitSubject *caller, + PolkitSubject *subject, + PolkitIdentity *user_for_subject, + const gchar *action_id, + PolkitDetails *details) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority); + GList *ret = NULL; + jsval argv[6] = {0}; + jsval rval = {0}; + JSString *action_id_jstr; + guint n; + GError *error = NULL; + JSString *ret_jsstr; + gchar *ret_str = NULL; + gchar **ret_strs = NULL; + + if (!subject_to_js (authority, subject, user_for_subject, &argv[1], &argv[2], &argv[3], &error)) + { + /* TODO: syslog? */ + g_printerr ("Error converting subject: %s\n", error->message); + g_clear_error (&error); + goto out; + } + + action_id_jstr = JS_NewStringCopyZ (authority->priv->cx, action_id); + argv[0] = STRING_TO_JSVAL (action_id_jstr); + argv[4] = BOOLEAN_TO_JSVAL (FALSE);//TODO:subject_is_local); + argv[5] = BOOLEAN_TO_JSVAL (FALSE);//TODO:subject_is_active); + + if (!JS_CallFunctionName(authority->priv->cx, + authority->priv->js_polkit, + "_runAdministratorRules", + 6, + argv, + &rval)) + { + /* TODO: syslog? */ + g_printerr ("boo, failed\n"); + goto out; + } + + if (!JSVAL_IS_STRING (rval) && !JSVAL_IS_NULL (rval)) + { + /* TODO: syslog? */ + g_printerr ("boo, not string\n"); + goto out; + } + + ret_jsstr = JSVAL_TO_STRING (rval); + ret_str = g_utf16_to_utf8 (JS_GetStringCharsZ (authority->priv->cx, ret_jsstr), -1, NULL, NULL, NULL); + if (ret_str == NULL) + { + /* TODO: syslog? */ + g_printerr ("boo, error converting to UTF-8\n"); + goto out; + } + + //g_print ("yay, worked `%s'\n", ret_str); + + ret_strs = g_strsplit (ret_str, ",", -1); + for (n = 0; ret_strs != NULL && ret_strs[n] != NULL; n++) + { + const gchar *identity_str = ret_strs[n]; + PolkitIdentity *identity; + + error = NULL; + identity = polkit_identity_from_string (identity_str, &error); + if (identity == NULL) + { + /* TODO: syslog? */ + g_printerr ("boo, identity `%s' is not valid, ignoring\n", identity_str); + } + else + { + ret = g_list_prepend (ret, identity); + } + } + ret = g_list_reverse (ret); + + out: + g_strfreev (ret_strs); + g_free (ret_str); + /* fallback to root password auth */ + if (ret == NULL) + ret = g_list_prepend (ret, polkit_unix_user_new (0)); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static PolkitImplicitAuthorization +polkit_backend_js_authority_check_authorization_sync (PolkitBackendInteractiveAuthority *_authority, + PolkitSubject *caller, + PolkitSubject *subject, + PolkitIdentity *user_for_subject, + gboolean subject_is_local, + gboolean subject_is_active, + const gchar *action_id, + PolkitDetails *details, + PolkitImplicitAuthorization implicit, + PolkitDetails *out_details) +{ + PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority); + PolkitImplicitAuthorization ret = implicit; + jsval argv[6] = {0}; + jsval rval = {0}; + JSString *action_id_jstr; + GError *error = NULL; + JSString *ret_jsstr; + const jschar *ret_utf16; + gchar *ret_str = NULL; + + if (!subject_to_js (authority, subject, user_for_subject, &argv[1], &argv[2], &argv[3], &error)) + { + /* TODO: syslog? */ + g_printerr ("Error converting subject: %s\n", error->message); + g_clear_error (&error); + goto out; + } + + action_id_jstr = JS_NewStringCopyZ (authority->priv->cx, action_id); + argv[0] = STRING_TO_JSVAL (action_id_jstr); + argv[4] = BOOLEAN_TO_JSVAL (subject_is_local); + argv[5] = BOOLEAN_TO_JSVAL (subject_is_active); + + if (!JS_CallFunctionName(authority->priv->cx, + authority->priv->js_polkit, + "_runAuthorizationRules", + 6, + argv, + &rval)) + { + /* TODO: syslog? */ + g_printerr ("boo, failed\n"); + goto out; + } + + if (!JSVAL_IS_STRING (rval) && !JSVAL_IS_NULL (rval)) + { + /* TODO: syslog? */ + g_printerr ("boo, not string\n"); + goto out; + } + + ret_jsstr = JSVAL_TO_STRING (rval); + if (ret_jsstr == NULL) + { + /* TODO: syslog? */ + g_printerr ("boo, string is null\n"); + goto out; + } + + ret_utf16 = JS_GetStringCharsZ (authority->priv->cx, ret_jsstr); + ret_str = g_utf16_to_utf8 (ret_utf16, -1, NULL, NULL, NULL); + if (ret_str == NULL) + { + /* TODO: syslog? */ + g_printerr ("boo, error converting to UTF-8\n"); + goto out; + } + + if (!polkit_implicit_authorization_from_string (ret_str, &ret)) + { + /* TODO: syslog? */ + g_printerr ("boo, returned result `%s' is not valid\n", ret_str); + goto out; + } + + g_print ("yay, worked `%s'\n", ret_str); + + out: + g_free (ret_str); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static JSBool +js_polkit_log (JSContext *cx, + uintN argc, + jsval *vp) +{ + /* PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (JS_GetContextPrivate (cx)); */ + JSBool ret = JS_FALSE; + JSString *str; + char *s; + + if (!JS_ConvertArguments (cx, argc, JS_ARGV (cx, vp), "S", &str)) + goto out; + + s = JS_EncodeString (cx, str); + JS_ReportWarning (cx, s); + JS_free (cx, s); + + ret = JS_TRUE; + + JS_SET_RVAL (cx, vp, JSVAL_VOID); /* return undefined */ + out: + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/polkitbackend/polkitbackendjsauthority.h b/src/polkitbackend/polkitbackendjsauthority.h new file mode 100644 index 0000000..6fd283b --- /dev/null +++ b/src/polkitbackend/polkitbackendjsauthority.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008-2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#if !defined (_POLKIT_BACKEND_COMPILATION) && !defined(_POLKIT_BACKEND_INSIDE_POLKIT_BACKEND_H) +#error "Only <polkitbackend/polkitbackend.h> can be included directly, this file may disappear or change contents." +#endif + +#ifndef __POLKIT_BACKEND_JS_AUTHORITY_H +#define __POLKIT_BACKEND_JS_AUTHORITY_H + +#include <glib-object.h> +#include <polkitbackend/polkitbackendtypes.h> +#include <polkitbackend/polkitbackendinteractiveauthority.h> + +G_BEGIN_DECLS + +#define POLKIT_BACKEND_TYPE_JS_AUTHORITY (polkit_backend_js_authority_get_type ()) +#define POLKIT_BACKEND_JS_AUTHORITY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_BACKEND_TYPE_JS_AUTHORITY, PolkitBackendJsAuthority)) +#define POLKIT_BACKEND_JS_AUTHORITY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), POLKIT_BACKEND_TYPE_JS_AUTHORITY, PolkitBackendJsAuthorityClass)) +#define POLKIT_BACKEND_JS_AUTHORITY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_BACKEND_TYPE_JS_AUTHORITY,PolkitBackendJsAuthorityClass)) +#define POLKIT_BACKEND_IS_JS_AUTHORITY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_BACKEND_TYPE_JS_AUTHORITY)) +#define POLKIT_BACKEND_IS_JS_AUTHORITY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_BACKEND_TYPE_JS_AUTHORITY)) + +typedef struct _PolkitBackendJsAuthorityClass PolkitBackendJsAuthorityClass; +typedef struct _PolkitBackendJsAuthorityPrivate PolkitBackendJsAuthorityPrivate; + +/** + * PolkitBackendJsAuthority: + * + * The #PolkitBackendJsAuthority struct should not be accessed directly. + */ +struct _PolkitBackendJsAuthority +{ + /*< private >*/ + PolkitBackendInteractiveAuthority parent_instance; + PolkitBackendJsAuthorityPrivate *priv; +}; + +/** + * PolkitBackendJsAuthorityClass: + * @parent_class: The parent class. + * + * Class structure for #PolkitBackendJsAuthority. + */ +struct _PolkitBackendJsAuthorityClass +{ + /*< public >*/ + PolkitBackendInteractiveAuthorityClass parent_class; +}; + +GType polkit_backend_js_authority_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __POLKIT_BACKEND_JS_AUTHORITY_H */ + + diff --git a/src/polkitbackend/polkitbackendtypes.h b/src/polkitbackend/polkitbackendtypes.h index d06f62a..2fe36ac 100644 --- a/src/polkitbackend/polkitbackendtypes.h +++ b/src/polkitbackend/polkitbackendtypes.h @@ -36,5 +36,8 @@ typedef struct _PolkitBackendInteractiveAuthority PolkitBackendInteractiveAuthor struct _PolkitBackendLocalAuthority; typedef struct _PolkitBackendLocalAuthority PolkitBackendLocalAuthority; +struct _PolkitBackendJsAuthority; +typedef struct _PolkitBackendJsAuthority PolkitBackendJsAuthority; + #endif /* __POLKIT_BACKEND_TYPES_H */ diff --git a/test/data/etc/polkit-1/rules.d/10-testing.rules b/test/data/etc/polkit-1/rules.d/10-testing.rules new file mode 100644 index 0000000..adf4f16 --- /dev/null +++ b/test/data/etc/polkit-1/rules.d/10-testing.rules @@ -0,0 +1,32 @@ +/* -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- */ + +polkit.addAdministratorRule(function(action, subject) { + return ["unix-group:admin", "unix-user:root"]; +}); + +polkit.addAdministratorRule(function(action, subject) { + if (action == "net.company.action1") { + return ["unix-group:admin"]; + } + return null; +}); + +polkit.addAdministratorRule(function(action, subject) { + if (action == "net.company.action2") { + return ["unix-group:users"]; + } + return null; +}); + +// ----- + +polkit.addAuthorizationRule(function(action, subject) { + return "auth_admin"; +}); + +polkit.addAuthorizationRule(function(action, subject) { + if (action == "org.freedesktop.policykit.exec") { + return "auth_admin"; + } + return null; +}); diff --git a/test/polkitbackend/Makefile.am b/test/polkitbackend/Makefile.am index c611b5b..46706d3 100644 --- a/test/polkitbackend/Makefile.am +++ b/test/polkitbackend/Makefile.am @@ -39,8 +39,12 @@ polkitbackendlocalauthorizationstoretest_SOURCES = polkitbackendlocalauthorizati TEST_PROGS += polkitbackendlocalauthoritytest polkitbackendlocalauthoritytest_SOURCES = polkitbackendlocalauthoritytest.c +TEST_PROGS += polkitbackendjsauthoritytest +polkitbackendjsauthoritytest_SOURCES = test-polkitbackendjsauthority.c + # ---------------------------------------------------------------------------------------------------- +noinst_PROGRAMS = $(TEST_PROGS) check_PROGRAMS = $(TEST_PROGS) TESTS = $(TEST_PROGS) diff --git a/test/polkitbackend/test-polkitbackendjsauthority.c b/test/polkitbackend/test-polkitbackendjsauthority.c new file mode 100644 index 0000000..c5015ff --- /dev/null +++ b/test/polkitbackend/test-polkitbackendjsauthority.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Nikki VonHollen <vonhollen@google.com> + * David Zeuthen <davidz@redhat.com> + */ + +#include "glib.h" + +#include <polkit/polkit.h> +#include <polkitbackend/polkitbackendjsauthority.h> +#include <polkittesthelper.h> + +/* Test helper types */ + +static PolkitBackendJsAuthority *get_authority (void); + +static PolkitBackendJsAuthority * +get_authority (void) +{ + gchar *rules_dir; + PolkitBackendJsAuthority *authority; + + rules_dir = polkit_test_get_data_path ("etc/polkit-1/rules.d"); + g_assert (rules_dir != NULL); + + authority = g_object_new (POLKIT_BACKEND_TYPE_JS_AUTHORITY, + "rules-dir", rules_dir, + NULL); + g_free (rules_dir); + return authority; +} + + +static void +test_get_admin_identities_for_action_id (const gchar *action_id, + const gchar *const *expected_admins) +{ + PolkitBackendJsAuthority *authority = NULL; + PolkitSubject *caller = NULL; + PolkitSubject *subject = NULL; + PolkitIdentity *user_for_subject = NULL; + PolkitDetails *details = NULL; + GError *error = NULL; + GList *admin_identities = NULL; + GList *l; + guint n; + + authority = get_authority (); + + caller = polkit_unix_process_new (getpid ()); + subject = polkit_unix_process_new (getpid ()); + user_for_subject = polkit_identity_from_string ("unix-user:root", &error); + g_assert_no_error (error); + + details = polkit_details_new (); + + /* Get the list of PolkitUnixUser objects who are admins */ + admin_identities = polkit_backend_interactive_authority_get_admin_identities (POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority), + caller, + subject, + user_for_subject, + action_id, + details); + for (l = admin_identities, n = 0; l != NULL; l = l->next, n++) + { + PolkitIdentity *test_identity = POLKIT_IDENTITY (l->data); + gchar *s; + + g_assert (expected_admins[n] != NULL); + + s = polkit_identity_to_string (test_identity); + g_assert_cmpstr (expected_admins[n], ==, s); + g_free (s); + } + g_assert (expected_admins[n] == NULL); + + g_list_free_full (admin_identities, g_object_unref); + g_clear_object (&user_for_subject); + g_clear_object (&subject); + g_clear_object (&caller); + g_clear_object (&authority); +} + +static void +test_get_admin_identities (void) +{ + struct { + const gchar *action_id; + const gchar *expected_admins[5]; + } test_cases[] = { + { + "com.example.doesntmatter", + { + "unix-group:admin", + "unix-user:root" + } + }, + { + "net.company.action1", + { + "unix-group:admin" + } + }, + { + "net.company.action2", + { + "unix-group:users" + } + }, + }; + guint n; + + for (n = 0; n < G_N_ELEMENTS (test_cases); n++) + { + test_get_admin_identities_for_action_id (test_cases[n].action_id, + test_cases[n].expected_admins); + } +} + + +int +main (int argc, char *argv[]) +{ + GIOExtensionPoint *ep; + + g_type_init (); + g_test_init (&argc, &argv, NULL); + //polkit_test_redirect_logs (); + + ep = g_io_extension_point_register (POLKIT_BACKEND_AUTHORITY_EXTENSION_POINT_NAME); + g_io_extension_point_set_required_type (ep, POLKIT_BACKEND_TYPE_AUTHORITY); + + g_test_add_func ("/PolkitBackendJsAuthority/get_admin_identities", test_get_admin_identities); + + return g_test_run (); +}; |