f19ea27ad0
* gnu/packages/polkit.scm (polkit): Disable a JavaScript related test, somehow triggered in the polkit-duktape build. (polkit-duktape): New variable. * gnu/packages/patches/polkit-use-duktape.patch: New file. * gnu/local.mk (dist_patch_DATA): Register it.
5030 lines
177 KiB
Diff
5030 lines
177 KiB
Diff
From 4f66a9549a393e4d74b93eb85301a04ea94bc750 Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Wed, 24 Jul 2019 15:55:17 +0800
|
|
Subject: [PATCH 01/16] Add duktape as javascript engine.
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
configure.ac | 28 +-
|
|
src/polkitbackend/Makefile.am | 14 +-
|
|
.../polkitbackendduktapeauthority.c | 1402 +++++++++++++++++
|
|
3 files changed, 1436 insertions(+), 8 deletions(-)
|
|
create mode 100644 src/polkitbackend/polkitbackendduktapeauthority.c
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index e434ca2..5a03593 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -80,11 +80,22 @@ PKG_CHECK_MODULES(GLIB, [gmodule-2.0 gio-unix-2.0 >= 2.30.0])
|
|
AC_SUBST(GLIB_CFLAGS)
|
|
AC_SUBST(GLIB_LIBS)
|
|
|
|
-PKG_CHECK_MODULES(LIBJS, [mozjs-78])
|
|
-
|
|
-AC_SUBST(LIBJS_CFLAGS)
|
|
-AC_SUBST(LIBJS_CXXFLAGS)
|
|
-AC_SUBST(LIBJS_LIBS)
|
|
+dnl ---------------------------------------------------------------------------
|
|
+dnl - Check javascript backend
|
|
+dnl ---------------------------------------------------------------------------
|
|
+AC_ARG_WITH(duktape, AS_HELP_STRING([--with-duktape],[Use Duktape as javascript backend]),with_duktape=yes,with_duktape=no)
|
|
+AS_IF([test x${with_duktape} == xyes], [
|
|
+ PKG_CHECK_MODULES(LIBJS, [duktape >= 2.0.0 ])
|
|
+ AC_SUBST(LIBJS_CFLAGS)
|
|
+ AC_SUBST(LIBJS_LIBS)
|
|
+], [
|
|
+ PKG_CHECK_MODULES(LIBJS, [mozjs-78])
|
|
+
|
|
+ AC_SUBST(LIBJS_CFLAGS)
|
|
+ AC_SUBST(LIBJS_CXXFLAGS)
|
|
+ AC_SUBST(LIBJS_LIBS)
|
|
+])
|
|
+AM_CONDITIONAL(USE_DUKTAPE, [test x$with_duktape == xyes], [Using duktape as javascript engine library])
|
|
|
|
EXPAT_LIB=""
|
|
AC_ARG_WITH(expat, [ --with-expat=<dir> Use expat from here],
|
|
@@ -585,6 +596,13 @@ echo "
|
|
PAM support: ${have_pam}
|
|
systemdsystemunitdir: ${systemdsystemunitdir}
|
|
polkitd user: ${POLKITD_USER}"
|
|
+if test "x${with_duktape}" = xyes; then
|
|
+echo "
|
|
+ Javascript engine: Duktape"
|
|
+else
|
|
+echo "
|
|
+ Javascript engine: Mozjs"
|
|
+fi
|
|
|
|
if test "$have_pam" = yes ; then
|
|
echo "
|
|
diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am
|
|
index 7e3c080..abcbc6f 100644
|
|
--- a/src/polkitbackend/Makefile.am
|
|
+++ b/src/polkitbackend/Makefile.am
|
|
@@ -33,7 +33,7 @@ libpolkit_backend_1_la_SOURCES = \
|
|
polkitbackendprivate.h \
|
|
polkitbackendauthority.h polkitbackendauthority.c \
|
|
polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \
|
|
- polkitbackendjsauthority.h polkitbackendjsauthority.cpp \
|
|
+ polkitbackendjsauthority.h \
|
|
polkitbackendactionpool.h polkitbackendactionpool.c \
|
|
polkitbackendactionlookup.h polkitbackendactionlookup.c \
|
|
$(NULL)
|
|
@@ -51,19 +51,27 @@ libpolkit_backend_1_la_CFLAGS = \
|
|
-D_POLKIT_BACKEND_COMPILATION \
|
|
$(GLIB_CFLAGS) \
|
|
$(LIBSYSTEMD_CFLAGS) \
|
|
- $(LIBJS_CFLAGS) \
|
|
+ $(LIBJS_CFLAGS) \
|
|
$(NULL)
|
|
|
|
libpolkit_backend_1_la_CXXFLAGS = $(libpolkit_backend_1_la_CFLAGS)
|
|
|
|
libpolkit_backend_1_la_LIBADD = \
|
|
$(GLIB_LIBS) \
|
|
+ $(DUKTAPE_LIBS) \
|
|
$(LIBSYSTEMD_LIBS) \
|
|
$(top_builddir)/src/polkit/libpolkit-gobject-1.la \
|
|
$(EXPAT_LIBS) \
|
|
- $(LIBJS_LIBS) \
|
|
+ $(LIBJS_LIBS) \
|
|
$(NULL)
|
|
|
|
+if USE_DUKTAPE
|
|
+libpolkit_backend_1_la_SOURCES += polkitbackendduktapeauthority.c
|
|
+libpolkit_backend_1_la_LIBADD += -lm
|
|
+else
|
|
+libpolkit_backend_1_la_SOURCES += polkitbackendjsauthority.cpp
|
|
+endif
|
|
+
|
|
rulesdir = $(sysconfdir)/polkit-1/rules.d
|
|
rules_DATA = 50-default.rules
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
new file mode 100644
|
|
index 0000000..ae98453
|
|
--- /dev/null
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -0,0 +1,1402 @@
|
|
+/*
|
|
+ * Copyright (C) 2008-2012 Red Hat, Inc.
|
|
+ * Copyright (C) 2015 Tangent Space <jstpierre@mecheye.net>
|
|
+ * Copyright (C) 2019 Wu Xiaotian <yetist@gmail.com>
|
|
+ *
|
|
+ * 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 <sys/wait.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>
|
|
+
|
|
+#ifdef HAVE_LIBSYSTEMD
|
|
+#include <systemd/sd-login.h>
|
|
+#endif /* HAVE_LIBSYSTEMD */
|
|
+
|
|
+#include "initjs.h" /* init.js */
|
|
+#include "duktape.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_dirs;
|
|
+ GFileMonitor **dir_monitors; /* NULL-terminated array of GFileMonitor instances */
|
|
+ duk_context *cx;
|
|
+};
|
|
+
|
|
+#define WATCHDOG_TIMEOUT (15 * G_TIME_SPAN_SECOND)
|
|
+
|
|
+static void utils_spawn (const gchar *const *argv,
|
|
+ guint timeout_seconds,
|
|
+ GCancellable *cancellable,
|
|
+ GAsyncReadyCallback callback,
|
|
+ gpointer user_data);
|
|
+
|
|
+gboolean utils_spawn_finish (GAsyncResult *res,
|
|
+ gint *out_exit_status,
|
|
+ gchar **out_standard_output,
|
|
+ gchar **out_standard_error,
|
|
+ GError **error);
|
|
+
|
|
+static void on_dir_monitor_changed (GFileMonitor *monitor,
|
|
+ GFile *file,
|
|
+ GFile *other_file,
|
|
+ GFileMonitorEvent event_type,
|
|
+ gpointer user_data);
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+enum
|
|
+{
|
|
+ PROP_0,
|
|
+ PROP_RULES_DIRS,
|
|
+};
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static GList *polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *authority,
|
|
+ PolkitSubject *caller,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ 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);
|
|
+
|
|
+G_DEFINE_TYPE (PolkitBackendJsAuthority, polkit_backend_js_authority, POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY);
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static void
|
|
+polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
+{
|
|
+ authority->priv = G_TYPE_INSTANCE_GET_PRIVATE (authority,
|
|
+ POLKIT_BACKEND_TYPE_JS_AUTHORITY,
|
|
+ PolkitBackendJsAuthorityPrivate);
|
|
+}
|
|
+
|
|
+static gint
|
|
+rules_file_name_cmp (const gchar *a,
|
|
+ const gchar *b)
|
|
+{
|
|
+ gint ret;
|
|
+ const gchar *a_base;
|
|
+ const gchar *b_base;
|
|
+
|
|
+ a_base = strrchr (a, '/');
|
|
+ b_base = strrchr (b, '/');
|
|
+
|
|
+ g_assert (a_base != NULL);
|
|
+ g_assert (b_base != NULL);
|
|
+ a_base += 1;
|
|
+ b_base += 1;
|
|
+
|
|
+ ret = g_strcmp0 (a_base, b_base);
|
|
+ if (ret == 0)
|
|
+ {
|
|
+ /* /etc wins over /usr */
|
|
+ ret = g_strcmp0 (a, b);
|
|
+ g_assert (ret != 0);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void
|
|
+load_scripts (PolkitBackendJsAuthority *authority)
|
|
+{
|
|
+ duk_context *cx = authority->priv->cx;
|
|
+ GList *files = NULL;
|
|
+ GList *l;
|
|
+ guint num_scripts = 0;
|
|
+ GError *error = NULL;
|
|
+ guint n;
|
|
+
|
|
+ files = NULL;
|
|
+
|
|
+ for (n = 0; authority->priv->rules_dirs != NULL && authority->priv->rules_dirs[n] != NULL; n++)
|
|
+ {
|
|
+ const gchar *dir_name = authority->priv->rules_dirs[n];
|
|
+ GDir *dir = NULL;
|
|
+
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Loading rules from directory %s",
|
|
+ dir_name);
|
|
+
|
|
+ dir = g_dir_open (dir_name,
|
|
+ 0,
|
|
+ &error);
|
|
+ if (dir == NULL)
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error opening rules directory: %s (%s, %d)",
|
|
+ error->message, g_quark_to_string (error->domain), error->code);
|
|
+ g_clear_error (&error);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ const gchar *name;
|
|
+ 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", dir_name, name));
|
|
+ }
|
|
+ g_dir_close (dir);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ files = g_list_sort (files, (GCompareFunc) rules_file_name_cmp);
|
|
+
|
|
+ for (l = files; l != NULL; l = l->next)
|
|
+ {
|
|
+ const gchar *filename = l->data;
|
|
+
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ gchar *contents;
|
|
+ gsize length;
|
|
+ GError *error = NULL;
|
|
+ if (!g_file_get_contents (filename, &contents, &length, &error)){
|
|
+ g_warning("Error when file contents of %s: %s\n", filename, error->message);
|
|
+ g_error_free (error);
|
|
+ continue;
|
|
+ }
|
|
+ if (duk_peval_lstring_noresult(cx, contents,length) != 0)
|
|
+#else
|
|
+ if (duk_peval_file_noresult (cx, filename) != 0)
|
|
+#endif
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error compiling script %s: %s",
|
|
+ filename, duk_safe_to_string (authority->priv->cx, -1));
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ g_free (contents);
|
|
+#endif
|
|
+ continue;
|
|
+ }
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ g_free (contents);
|
|
+#endif
|
|
+ num_scripts++;
|
|
+ }
|
|
+
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Finished loading, compiling and executing %d rules",
|
|
+ num_scripts);
|
|
+ g_list_free_full (files, g_free);
|
|
+}
|
|
+
|
|
+static void
|
|
+reload_scripts (PolkitBackendJsAuthority *authority)
|
|
+{
|
|
+ duk_context *cx = authority->priv->cx;
|
|
+
|
|
+ duk_set_top (cx, 0);
|
|
+ duk_get_global_string (cx, "polkit");
|
|
+ duk_push_string (cx, "_deleteRules");
|
|
+
|
|
+ duk_call_prop (cx, 0, 0);
|
|
+
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Collecting garbage unconditionally...");
|
|
+
|
|
+ load_scripts (authority);
|
|
+
|
|
+ /* Let applications know we have new rules... */
|
|
+ g_signal_emit_by_name (authority, "changed");
|
|
+}
|
|
+
|
|
+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 rules");
|
|
+ reload_scripts (authority);
|
|
+ }
|
|
+ g_free (name);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
+{
|
|
+ guint n;
|
|
+ GPtrArray *p;
|
|
+
|
|
+ p = g_ptr_array_new ();
|
|
+ for (n = 0; authority->priv->rules_dirs != NULL && authority->priv->rules_dirs[n] != NULL; n++)
|
|
+ {
|
|
+ GFile *file;
|
|
+ GError *error;
|
|
+ GFileMonitor *monitor;
|
|
+
|
|
+ file = g_file_new_for_path (authority->priv->rules_dirs[n]);
|
|
+ error = NULL;
|
|
+ monitor = g_file_monitor_directory (file,
|
|
+ G_FILE_MONITOR_NONE,
|
|
+ NULL,
|
|
+ &error);
|
|
+ g_object_unref (file);
|
|
+ if (monitor == NULL)
|
|
+ {
|
|
+ g_warning ("Error monitoring directory %s: %s",
|
|
+ authority->priv->rules_dirs[n],
|
|
+ error->message);
|
|
+ g_clear_error (&error);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ g_signal_connect (monitor,
|
|
+ "changed",
|
|
+ G_CALLBACK (on_dir_monitor_changed),
|
|
+ authority);
|
|
+ g_ptr_array_add (p, monitor);
|
|
+ }
|
|
+ }
|
|
+ g_ptr_array_add (p, NULL);
|
|
+ authority->priv->dir_monitors = (GFileMonitor**) g_ptr_array_free (p, FALSE);
|
|
+}
|
|
+
|
|
+static duk_ret_t js_polkit_log (duk_context *cx);
|
|
+static duk_ret_t js_polkit_spawn (duk_context *cx);
|
|
+static duk_ret_t js_polkit_user_is_in_netgroup (duk_context *cx);
|
|
+
|
|
+static const duk_function_list_entry js_polkit_functions[] =
|
|
+{
|
|
+ { "log", js_polkit_log, 1 },
|
|
+ { "spawn", js_polkit_spawn, 1 },
|
|
+ { "_userIsInNetGroup", js_polkit_user_is_in_netgroup, 2 },
|
|
+ { NULL, NULL, 0 },
|
|
+};
|
|
+
|
|
+static void
|
|
+polkit_backend_js_authority_constructed (GObject *object)
|
|
+{
|
|
+ PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
+ duk_context *cx;
|
|
+
|
|
+ cx = duk_create_heap (NULL, NULL, NULL, authority, NULL);
|
|
+ if (cx == NULL)
|
|
+ goto fail;
|
|
+
|
|
+ authority->priv->cx = cx;
|
|
+
|
|
+ duk_push_global_object (cx);
|
|
+ duk_push_object (cx);
|
|
+ duk_put_function_list (cx, -1, js_polkit_functions);
|
|
+ duk_put_prop_string (cx, -2, "polkit");
|
|
+
|
|
+ duk_eval_string (cx, init_js);
|
|
+
|
|
+ if (authority->priv->rules_dirs == NULL)
|
|
+ {
|
|
+ authority->priv->rules_dirs = g_new0 (gchar *, 3);
|
|
+ authority->priv->rules_dirs[0] = g_strdup (PACKAGE_SYSCONF_DIR "/polkit-1/rules.d");
|
|
+ authority->priv->rules_dirs[1] = g_strdup (PACKAGE_DATA_DIR "/polkit-1/rules.d");
|
|
+ }
|
|
+
|
|
+ setup_file_monitors (authority);
|
|
+ load_scripts (authority);
|
|
+
|
|
+ G_OBJECT_CLASS (polkit_backend_js_authority_parent_class)->constructed (object);
|
|
+ return;
|
|
+
|
|
+ fail:
|
|
+ g_critical ("Error initializing JavaScript environment");
|
|
+ g_assert_not_reached ();
|
|
+}
|
|
+
|
|
+static void
|
|
+polkit_backend_js_authority_finalize (GObject *object)
|
|
+{
|
|
+ PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
+ guint n;
|
|
+
|
|
+ for (n = 0; authority->priv->dir_monitors != NULL && authority->priv->dir_monitors[n] != NULL; n++)
|
|
+ {
|
|
+ GFileMonitor *monitor = authority->priv->dir_monitors[n];
|
|
+ g_signal_handlers_disconnect_by_func (monitor,
|
|
+ G_CALLBACK (on_dir_monitor_changed),
|
|
+ authority);
|
|
+ g_object_unref (monitor);
|
|
+ }
|
|
+ g_free (authority->priv->dir_monitors);
|
|
+ g_strfreev (authority->priv->rules_dirs);
|
|
+
|
|
+ duk_destroy_heap (authority->priv->cx);
|
|
+
|
|
+ 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);
|
|
+
|
|
+ switch (property_id)
|
|
+ {
|
|
+ case PROP_RULES_DIRS:
|
|
+ g_assert (authority->priv->rules_dirs == NULL);
|
|
+ authority->priv->rules_dirs = (gchar **) g_value_dup_boxed (value);
|
|
+ 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_DIRS,
|
|
+ g_param_spec_boxed ("rules-dirs",
|
|
+ NULL,
|
|
+ NULL,
|
|
+ G_TYPE_STRV,
|
|
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
|
|
+
|
|
+
|
|
+ g_type_class_add_private (klass, sizeof (PolkitBackendJsAuthorityPrivate));
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static void
|
|
+set_property_str (duk_context *cx,
|
|
+ const gchar *name,
|
|
+ const gchar *value)
|
|
+{
|
|
+ duk_push_string (cx, value);
|
|
+ duk_put_prop_string (cx, -2, name);
|
|
+}
|
|
+
|
|
+static void
|
|
+set_property_strv (duk_context *cx,
|
|
+ const gchar *name,
|
|
+ GPtrArray *value)
|
|
+{
|
|
+ guint n;
|
|
+ duk_push_array (cx);
|
|
+ for (n = 0; n < value->len; n++)
|
|
+ {
|
|
+ duk_push_string (cx, g_ptr_array_index (value, n));
|
|
+ duk_put_prop_index (cx, -2, n);
|
|
+ }
|
|
+ duk_put_prop_string (cx, -2, name);
|
|
+}
|
|
+
|
|
+static void
|
|
+set_property_int32 (duk_context *cx,
|
|
+ const gchar *name,
|
|
+ gint32 value)
|
|
+{
|
|
+ duk_push_int (cx, value);
|
|
+ duk_put_prop_string (cx, -2, name);
|
|
+}
|
|
+
|
|
+static void
|
|
+set_property_bool (duk_context *cx,
|
|
+ const char *name,
|
|
+ gboolean value)
|
|
+{
|
|
+ duk_push_boolean (cx, value);
|
|
+ duk_put_prop_string (cx, -2, name);
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static gboolean
|
|
+push_subject (duk_context *cx,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ GError **error)
|
|
+{
|
|
+ gboolean ret = FALSE;
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
+ gchar *user_name = NULL;
|
|
+ GPtrArray *groups = NULL;
|
|
+ struct passwd *passwd;
|
|
+ char *seat_str = NULL;
|
|
+ char *session_str = NULL;
|
|
+
|
|
+ duk_get_global_string (cx, "Subject");
|
|
+ duk_new (cx, 0);
|
|
+
|
|
+ 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 ();
|
|
+ }
|
|
+
|
|
+#ifdef HAVE_LIBSYSTEMD
|
|
+ if (sd_pid_get_session (pid, &session_str) == 0)
|
|
+ {
|
|
+ if (sd_session_get_seat (session_str, &seat_str) == 0)
|
|
+ {
|
|
+ /* do nothing */
|
|
+ }
|
|
+ }
|
|
+#endif /* HAVE_LIBSYSTEMD */
|
|
+
|
|
+ g_assert (POLKIT_IS_UNIX_USER (user_for_subject));
|
|
+ uid = polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_for_subject));
|
|
+
|
|
+ groups = g_ptr_array_new_with_free_func (g_free);
|
|
+
|
|
+ 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;
|
|
+ group = getgrgid (gids[n]);
|
|
+ if (group == NULL)
|
|
+ {
|
|
+ g_ptr_array_add (groups, g_strdup_printf ("%d", (gint) gids[n]));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ g_ptr_array_add (groups, g_strdup (group->gr_name));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ set_property_int32 (cx, "pid", pid);
|
|
+ set_property_str (cx, "user", user_name);
|
|
+ set_property_strv (cx, "groups", groups);
|
|
+ set_property_str (cx, "seat", seat_str);
|
|
+ set_property_str (cx, "session", session_str);
|
|
+ set_property_bool (cx, "local", subject_is_local);
|
|
+ set_property_bool (cx, "active", subject_is_active);
|
|
+
|
|
+ ret = TRUE;
|
|
+
|
|
+ out:
|
|
+ free (session_str);
|
|
+ free (seat_str);
|
|
+ g_free (user_name);
|
|
+ if (groups != NULL)
|
|
+ g_ptr_array_unref (groups);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static gboolean
|
|
+push_action_and_details (duk_context *cx,
|
|
+ const gchar *action_id,
|
|
+ PolkitDetails *details,
|
|
+ GError **error)
|
|
+{
|
|
+ gchar **keys;
|
|
+ guint n;
|
|
+
|
|
+ duk_get_global_string (cx, "Action");
|
|
+ duk_new (cx, 0);
|
|
+
|
|
+ set_property_str (cx, "id", action_id);
|
|
+
|
|
+ keys = polkit_details_get_keys (details);
|
|
+ for (n = 0; keys != NULL && keys[n] != NULL; n++)
|
|
+ {
|
|
+ gchar *key;
|
|
+ const gchar *value;
|
|
+ key = g_strdup_printf ("_detail_%s", keys[n]);
|
|
+ value = polkit_details_lookup (details, keys[n]);
|
|
+ set_property_str (cx, key, value);
|
|
+ g_free (key);
|
|
+ }
|
|
+ g_strfreev (keys);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static GList *
|
|
+polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
+ PolkitSubject *caller,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ const gchar *action_id,
|
|
+ PolkitDetails *details)
|
|
+{
|
|
+ PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
+ GList *ret = NULL;
|
|
+ guint n;
|
|
+ GError *error = NULL;
|
|
+ const char *ret_str = NULL;
|
|
+ gchar **ret_strs = NULL;
|
|
+ duk_context *cx = authority->priv->cx;
|
|
+
|
|
+ duk_set_top (cx, 0);
|
|
+ duk_get_global_string (cx, "polkit");
|
|
+ duk_push_string (cx, "_runAdminRules");
|
|
+
|
|
+ if (!push_action_and_details (cx, action_id, details, &error))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error converting action and details to JS object: %s",
|
|
+ error->message);
|
|
+ g_clear_error (&error);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!push_subject (cx, subject, user_for_subject, subject_is_local, subject_is_active, &error))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error converting subject to JS object: %s",
|
|
+ error->message);
|
|
+ g_clear_error (&error);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (duk_pcall_prop (cx, 0, 2) != DUK_ERR_NONE)
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error evaluating admin rules: ",
|
|
+ duk_safe_to_string (cx, -1));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret_str = duk_require_string (cx, -1);
|
|
+
|
|
+ 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)
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Identity `%s' is not valid, ignoring: %s",
|
|
+ identity_str, error->message);
|
|
+ g_clear_error (&error);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ret = g_list_prepend (ret, identity);
|
|
+ }
|
|
+ }
|
|
+ ret = g_list_reverse (ret);
|
|
+
|
|
+ out:
|
|
+ g_strfreev (ret_strs);
|
|
+ /* 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)
|
|
+{
|
|
+ PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
+ PolkitImplicitAuthorization ret = implicit;
|
|
+ GError *error = NULL;
|
|
+ gchar *ret_str = NULL;
|
|
+ gboolean good = FALSE;
|
|
+ duk_context *cx = authority->priv->cx;
|
|
+
|
|
+ duk_set_top (cx, 0);
|
|
+ duk_get_global_string (cx, "polkit");
|
|
+ duk_push_string (cx, "_runRules");
|
|
+
|
|
+ if (!push_action_and_details (cx, action_id, details, &error))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error converting action and details to JS object: %s",
|
|
+ error->message);
|
|
+ g_clear_error (&error);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!push_subject (cx, subject, user_for_subject, subject_is_local, subject_is_active, &error))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error converting subject to JS object: %s",
|
|
+ error->message);
|
|
+ g_clear_error (&error);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (duk_pcall_prop (cx, 0, 2) != DUK_ERR_NONE)
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error evaluating authorization rules: ",
|
|
+ duk_safe_to_string (cx, -1));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (duk_is_null(cx, -1)) {
|
|
+ good = TRUE;
|
|
+ goto out;
|
|
+ }
|
|
+ ret_str = g_strdup (duk_require_string (cx, -1));
|
|
+ if (!polkit_implicit_authorization_from_string (ret_str, &ret))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Returned result `%s' is not valid",
|
|
+ ret_str);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ good = TRUE;
|
|
+
|
|
+ out:
|
|
+ if (!good)
|
|
+ ret = POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED;
|
|
+ g_free (ret_str);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static duk_ret_t
|
|
+js_polkit_log (duk_context *cx)
|
|
+{
|
|
+ const char *str = duk_require_string (cx, 0);
|
|
+ fprintf (stderr, "%s\n", str);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+static const gchar *
|
|
+get_signal_name (gint signal_number)
|
|
+{
|
|
+ switch (signal_number)
|
|
+ {
|
|
+#define _HANDLE_SIG(sig) case sig: return #sig;
|
|
+ _HANDLE_SIG (SIGHUP);
|
|
+ _HANDLE_SIG (SIGINT);
|
|
+ _HANDLE_SIG (SIGQUIT);
|
|
+ _HANDLE_SIG (SIGILL);
|
|
+ _HANDLE_SIG (SIGABRT);
|
|
+ _HANDLE_SIG (SIGFPE);
|
|
+ _HANDLE_SIG (SIGKILL);
|
|
+ _HANDLE_SIG (SIGSEGV);
|
|
+ _HANDLE_SIG (SIGPIPE);
|
|
+ _HANDLE_SIG (SIGALRM);
|
|
+ _HANDLE_SIG (SIGTERM);
|
|
+ _HANDLE_SIG (SIGUSR1);
|
|
+ _HANDLE_SIG (SIGUSR2);
|
|
+ _HANDLE_SIG (SIGCHLD);
|
|
+ _HANDLE_SIG (SIGCONT);
|
|
+ _HANDLE_SIG (SIGSTOP);
|
|
+ _HANDLE_SIG (SIGTSTP);
|
|
+ _HANDLE_SIG (SIGTTIN);
|
|
+ _HANDLE_SIG (SIGTTOU);
|
|
+ _HANDLE_SIG (SIGBUS);
|
|
+#ifdef SIGPOLL
|
|
+ _HANDLE_SIG (SIGPOLL);
|
|
+#endif
|
|
+ _HANDLE_SIG (SIGPROF);
|
|
+ _HANDLE_SIG (SIGSYS);
|
|
+ _HANDLE_SIG (SIGTRAP);
|
|
+ _HANDLE_SIG (SIGURG);
|
|
+ _HANDLE_SIG (SIGVTALRM);
|
|
+ _HANDLE_SIG (SIGXCPU);
|
|
+ _HANDLE_SIG (SIGXFSZ);
|
|
+#undef _HANDLE_SIG
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return "UNKNOWN_SIGNAL";
|
|
+}
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ GMainLoop *loop;
|
|
+ GAsyncResult *res;
|
|
+} SpawnData;
|
|
+
|
|
+static void
|
|
+spawn_cb (GObject *source_object,
|
|
+ GAsyncResult *res,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ SpawnData *data = user_data;
|
|
+ data->res = g_object_ref (res);
|
|
+ g_main_loop_quit (data->loop);
|
|
+}
|
|
+
|
|
+static duk_ret_t
|
|
+js_polkit_spawn (duk_context *cx)
|
|
+{
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ duk_ret_t ret = DUK_RET_ERROR;
|
|
+#else
|
|
+ duk_ret_t ret = DUK_RET_INTERNAL_ERROR;
|
|
+#endif
|
|
+ gchar *standard_output = NULL;
|
|
+ gchar *standard_error = NULL;
|
|
+ gint exit_status;
|
|
+ GError *error = NULL;
|
|
+ guint32 array_len;
|
|
+ gchar **argv = NULL;
|
|
+ GMainContext *context = NULL;
|
|
+ GMainLoop *loop = NULL;
|
|
+ SpawnData data = {0};
|
|
+ char *err_str = NULL;
|
|
+ guint n;
|
|
+
|
|
+ if (!duk_is_array (cx, 0))
|
|
+ goto out;
|
|
+
|
|
+ array_len = duk_get_length (cx, 0);
|
|
+
|
|
+ argv = g_new0 (gchar*, array_len + 1);
|
|
+ for (n = 0; n < array_len; n++)
|
|
+ {
|
|
+ duk_get_prop_index (cx, 0, n);
|
|
+ argv[n] = g_strdup (duk_to_string (cx, -1));
|
|
+ duk_pop (cx);
|
|
+ }
|
|
+
|
|
+ context = g_main_context_new ();
|
|
+ loop = g_main_loop_new (context, FALSE);
|
|
+
|
|
+ g_main_context_push_thread_default (context);
|
|
+
|
|
+ data.loop = loop;
|
|
+ utils_spawn ((const gchar *const *) argv,
|
|
+ 10, /* timeout_seconds */
|
|
+ NULL, /* cancellable */
|
|
+ spawn_cb,
|
|
+ &data);
|
|
+
|
|
+ g_main_loop_run (loop);
|
|
+
|
|
+ g_main_context_pop_thread_default (context);
|
|
+
|
|
+ if (!utils_spawn_finish (data.res,
|
|
+ &exit_status,
|
|
+ &standard_output,
|
|
+ &standard_error,
|
|
+ &error))
|
|
+ {
|
|
+ err_str = g_strdup_printf ("Error spawning helper: %s (%s, %d)",
|
|
+ error->message, g_quark_to_string (error->domain), error->code);
|
|
+ g_clear_error (&error);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!(WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0))
|
|
+ {
|
|
+ GString *gstr;
|
|
+ gstr = g_string_new (NULL);
|
|
+ if (WIFEXITED (exit_status))
|
|
+ {
|
|
+ g_string_append_printf (gstr,
|
|
+ "Helper exited with non-zero exit status %d",
|
|
+ WEXITSTATUS (exit_status));
|
|
+ }
|
|
+ else if (WIFSIGNALED (exit_status))
|
|
+ {
|
|
+ g_string_append_printf (gstr,
|
|
+ "Helper was signaled with signal %s (%d)",
|
|
+ get_signal_name (WTERMSIG (exit_status)),
|
|
+ WTERMSIG (exit_status));
|
|
+ }
|
|
+ g_string_append_printf (gstr, ", stdout=`%s', stderr=`%s'",
|
|
+ standard_output, standard_error);
|
|
+ err_str = g_string_free (gstr, FALSE);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ duk_push_string (cx, standard_output);
|
|
+ ret = 1;
|
|
+
|
|
+ out:
|
|
+ g_strfreev (argv);
|
|
+ g_free (standard_output);
|
|
+ g_free (standard_error);
|
|
+ g_clear_object (&data.res);
|
|
+ if (loop != NULL)
|
|
+ g_main_loop_unref (loop);
|
|
+ if (context != NULL)
|
|
+ g_main_context_unref (context);
|
|
+
|
|
+ if (err_str)
|
|
+ duk_error (cx, DUK_ERR_ERROR, err_str);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+
|
|
+static duk_ret_t
|
|
+js_polkit_user_is_in_netgroup (duk_context *cx)
|
|
+{
|
|
+ const char *user;
|
|
+ const char *netgroup;
|
|
+ gboolean is_in_netgroup = FALSE;
|
|
+
|
|
+ user = duk_require_string (cx, 0);
|
|
+ netgroup = duk_require_string (cx, 1);
|
|
+
|
|
+ if (innetgr (netgroup,
|
|
+ NULL, /* host */
|
|
+ user,
|
|
+ NULL)) /* domain */
|
|
+ {
|
|
+ is_in_netgroup = TRUE;
|
|
+ }
|
|
+
|
|
+ duk_push_boolean (cx, is_in_netgroup);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------------------------------------------- */
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ GSimpleAsyncResult *simple; /* borrowed reference */
|
|
+ GMainContext *main_context; /* may be NULL */
|
|
+
|
|
+ GCancellable *cancellable; /* may be NULL */
|
|
+ gulong cancellable_handler_id;
|
|
+
|
|
+ GPid child_pid;
|
|
+ gint child_stdout_fd;
|
|
+ gint child_stderr_fd;
|
|
+
|
|
+ GIOChannel *child_stdout_channel;
|
|
+ GIOChannel *child_stderr_channel;
|
|
+
|
|
+ GSource *child_watch_source;
|
|
+ GSource *child_stdout_source;
|
|
+ GSource *child_stderr_source;
|
|
+
|
|
+ guint timeout_seconds;
|
|
+ gboolean timed_out;
|
|
+ GSource *timeout_source;
|
|
+
|
|
+ GString *child_stdout;
|
|
+ GString *child_stderr;
|
|
+
|
|
+ gint exit_status;
|
|
+} UtilsSpawnData;
|
|
+
|
|
+static void
|
|
+utils_child_watch_from_release_cb (GPid pid,
|
|
+ gint status,
|
|
+ gpointer user_data)
|
|
+{
|
|
+}
|
|
+
|
|
+static void
|
|
+utils_spawn_data_free (UtilsSpawnData *data)
|
|
+{
|
|
+ if (data->timeout_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->timeout_source);
|
|
+ data->timeout_source = NULL;
|
|
+ }
|
|
+
|
|
+ /* Nuke the child, if necessary */
|
|
+ if (data->child_watch_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_watch_source);
|
|
+ data->child_watch_source = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_pid != 0)
|
|
+ {
|
|
+ GSource *source;
|
|
+ kill (data->child_pid, SIGTERM);
|
|
+ /* OK, we need to reap for the child ourselves - we don't want
|
|
+ * to use waitpid() because that might block the calling
|
|
+ * thread (the child might handle SIGTERM and use several
|
|
+ * seconds for cleanup/rollback).
|
|
+ *
|
|
+ * So we use GChildWatch instead.
|
|
+ *
|
|
+ * Avoid taking a references to ourselves. but note that we need
|
|
+ * to pass the GSource so we can nuke it once handled.
|
|
+ */
|
|
+ source = g_child_watch_source_new (data->child_pid);
|
|
+ g_source_set_callback (source,
|
|
+ (GSourceFunc) utils_child_watch_from_release_cb,
|
|
+ source,
|
|
+ (GDestroyNotify) g_source_destroy);
|
|
+ g_source_attach (source, data->main_context);
|
|
+ g_source_unref (source);
|
|
+ data->child_pid = 0;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout != NULL)
|
|
+ {
|
|
+ g_string_free (data->child_stdout, TRUE);
|
|
+ data->child_stdout = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stderr != NULL)
|
|
+ {
|
|
+ g_string_free (data->child_stderr, TRUE);
|
|
+ data->child_stderr = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_channel != NULL)
|
|
+ {
|
|
+ g_io_channel_unref (data->child_stdout_channel);
|
|
+ data->child_stdout_channel = NULL;
|
|
+ }
|
|
+ if (data->child_stderr_channel != NULL)
|
|
+ {
|
|
+ g_io_channel_unref (data->child_stderr_channel);
|
|
+ data->child_stderr_channel = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_stdout_source);
|
|
+ data->child_stdout_source = NULL;
|
|
+ }
|
|
+ if (data->child_stderr_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_stderr_source);
|
|
+ data->child_stderr_source = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_fd != -1)
|
|
+ {
|
|
+ g_warn_if_fail (close (data->child_stdout_fd) == 0);
|
|
+ data->child_stdout_fd = -1;
|
|
+ }
|
|
+ if (data->child_stderr_fd != -1)
|
|
+ {
|
|
+ g_warn_if_fail (close (data->child_stderr_fd) == 0);
|
|
+ data->child_stderr_fd = -1;
|
|
+ }
|
|
+
|
|
+ if (data->cancellable_handler_id > 0)
|
|
+ {
|
|
+ g_cancellable_disconnect (data->cancellable, data->cancellable_handler_id);
|
|
+ data->cancellable_handler_id = 0;
|
|
+ }
|
|
+
|
|
+ if (data->main_context != NULL)
|
|
+ g_main_context_unref (data->main_context);
|
|
+
|
|
+ if (data->cancellable != NULL)
|
|
+ g_object_unref (data->cancellable);
|
|
+
|
|
+ g_slice_free (UtilsSpawnData, data);
|
|
+}
|
|
+
|
|
+/* called in the thread where @cancellable was cancelled */
|
|
+static void
|
|
+utils_on_cancelled (GCancellable *cancellable,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = user_data;
|
|
+ GError *error;
|
|
+
|
|
+ error = NULL;
|
|
+ g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_read_child_stderr (GIOChannel *channel,
|
|
+ GIOCondition condition,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = user_data;
|
|
+ gchar buf[1024];
|
|
+ gsize bytes_read;
|
|
+
|
|
+ g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
+ g_string_append_len (data->child_stderr, buf, bytes_read);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_read_child_stdout (GIOChannel *channel,
|
|
+ GIOCondition condition,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = user_data;
|
|
+ gchar buf[1024];
|
|
+ gsize bytes_read;
|
|
+
|
|
+ g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
+ g_string_append_len (data->child_stdout, buf, bytes_read);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static void
|
|
+utils_child_watch_cb (GPid pid,
|
|
+ gint status,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = user_data;
|
|
+ gchar *buf;
|
|
+ gsize buf_size;
|
|
+
|
|
+ if (g_io_channel_read_to_end (data->child_stdout_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
+ {
|
|
+ g_string_append_len (data->child_stdout, buf, buf_size);
|
|
+ g_free (buf);
|
|
+ }
|
|
+ if (g_io_channel_read_to_end (data->child_stderr_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
+ {
|
|
+ g_string_append_len (data->child_stderr, buf, buf_size);
|
|
+ g_free (buf);
|
|
+ }
|
|
+
|
|
+ data->exit_status = status;
|
|
+
|
|
+ /* ok, child watch is history, make sure we don't free it in spawn_data_free() */
|
|
+ data->child_pid = 0;
|
|
+ data->child_watch_source = NULL;
|
|
+
|
|
+ /* we're done */
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_timeout_cb (gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = user_data;
|
|
+
|
|
+ data->timed_out = TRUE;
|
|
+
|
|
+ /* ok, timeout is history, make sure we don't free it in spawn_data_free() */
|
|
+ data->timeout_source = NULL;
|
|
+
|
|
+ /* we're done */
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+
|
|
+ return FALSE; /* remove source */
|
|
+}
|
|
+
|
|
+static void
|
|
+utils_spawn (const gchar *const *argv,
|
|
+ guint timeout_seconds,
|
|
+ GCancellable *cancellable,
|
|
+ GAsyncReadyCallback callback,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data;
|
|
+ GError *error;
|
|
+
|
|
+ data = g_slice_new0 (UtilsSpawnData);
|
|
+ data->timeout_seconds = timeout_seconds;
|
|
+ data->simple = g_simple_async_result_new (NULL,
|
|
+ callback,
|
|
+ user_data,
|
|
+ utils_spawn);
|
|
+ data->main_context = g_main_context_get_thread_default ();
|
|
+ if (data->main_context != NULL)
|
|
+ g_main_context_ref (data->main_context);
|
|
+
|
|
+ data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
|
|
+
|
|
+ data->child_stdout = g_string_new (NULL);
|
|
+ data->child_stderr = g_string_new (NULL);
|
|
+ data->child_stdout_fd = -1;
|
|
+ data->child_stderr_fd = -1;
|
|
+
|
|
+ /* the life-cycle of UtilsSpawnData is tied to its GSimpleAsyncResult */
|
|
+ g_simple_async_result_set_op_res_gpointer (data->simple, data, (GDestroyNotify) utils_spawn_data_free);
|
|
+
|
|
+ error = NULL;
|
|
+ if (data->cancellable != NULL)
|
|
+ {
|
|
+ /* could already be cancelled */
|
|
+ error = NULL;
|
|
+ if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
|
|
+ {
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ data->cancellable_handler_id = g_cancellable_connect (data->cancellable,
|
|
+ G_CALLBACK (utils_on_cancelled),
|
|
+ data,
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
+ error = NULL;
|
|
+ if (!g_spawn_async_with_pipes (NULL, /* working directory */
|
|
+ (gchar **) argv,
|
|
+ NULL, /* envp */
|
|
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
|
|
+ NULL, /* child_setup */
|
|
+ NULL, /* child_setup's user_data */
|
|
+ &(data->child_pid),
|
|
+ NULL, /* gint *stdin_fd */
|
|
+ &(data->child_stdout_fd),
|
|
+ &(data->child_stderr_fd),
|
|
+ &error))
|
|
+ {
|
|
+ g_prefix_error (&error, "Error spawning: ");
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (timeout_seconds > 0)
|
|
+ {
|
|
+ data->timeout_source = g_timeout_source_new_seconds (timeout_seconds);
|
|
+ g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
|
|
+ g_source_set_callback (data->timeout_source, utils_timeout_cb, data, NULL);
|
|
+ g_source_attach (data->timeout_source, data->main_context);
|
|
+ g_source_unref (data->timeout_source);
|
|
+ }
|
|
+
|
|
+ data->child_watch_source = g_child_watch_source_new (data->child_pid);
|
|
+ g_source_set_callback (data->child_watch_source, (GSourceFunc) utils_child_watch_cb, data, NULL);
|
|
+ g_source_attach (data->child_watch_source, data->main_context);
|
|
+ g_source_unref (data->child_watch_source);
|
|
+
|
|
+ data->child_stdout_channel = g_io_channel_unix_new (data->child_stdout_fd);
|
|
+ g_io_channel_set_flags (data->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
+ data->child_stdout_source = g_io_create_watch (data->child_stdout_channel, G_IO_IN);
|
|
+ g_source_set_callback (data->child_stdout_source, (GSourceFunc) utils_read_child_stdout, data, NULL);
|
|
+ g_source_attach (data->child_stdout_source, data->main_context);
|
|
+ g_source_unref (data->child_stdout_source);
|
|
+
|
|
+ data->child_stderr_channel = g_io_channel_unix_new (data->child_stderr_fd);
|
|
+ g_io_channel_set_flags (data->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
+ data->child_stderr_source = g_io_create_watch (data->child_stderr_channel, G_IO_IN);
|
|
+ g_source_set_callback (data->child_stderr_source, (GSourceFunc) utils_read_child_stderr, data, NULL);
|
|
+ g_source_attach (data->child_stderr_source, data->main_context);
|
|
+ g_source_unref (data->child_stderr_source);
|
|
+
|
|
+ out:
|
|
+ ;
|
|
+}
|
|
+
|
|
+gboolean
|
|
+utils_spawn_finish (GAsyncResult *res,
|
|
+ gint *out_exit_status,
|
|
+ gchar **out_standard_output,
|
|
+ gchar **out_standard_error,
|
|
+ GError **error)
|
|
+{
|
|
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
|
|
+ UtilsSpawnData *data;
|
|
+ gboolean ret = FALSE;
|
|
+
|
|
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
|
|
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
+
|
|
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == utils_spawn);
|
|
+
|
|
+ if (g_simple_async_result_propagate_error (simple, error))
|
|
+ goto out;
|
|
+
|
|
+ data = g_simple_async_result_get_op_res_gpointer (simple);
|
|
+
|
|
+ if (data->timed_out)
|
|
+ {
|
|
+ g_set_error (error,
|
|
+ G_IO_ERROR,
|
|
+ G_IO_ERROR_TIMED_OUT,
|
|
+ "Timed out after %d seconds",
|
|
+ data->timeout_seconds);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (out_exit_status != NULL)
|
|
+ *out_exit_status = data->exit_status;
|
|
+
|
|
+ if (out_standard_output != NULL)
|
|
+ *out_standard_output = g_strdup (data->child_stdout->str);
|
|
+
|
|
+ if (out_standard_error != NULL)
|
|
+ *out_standard_error = g_strdup (data->child_stderr->str);
|
|
+
|
|
+ ret = TRUE;
|
|
+
|
|
+ out:
|
|
+ return ret;
|
|
+}
|
|
--
|
|
GitLab
|
|
|
|
|
|
From d74aad8152a7c51999fffa9abe28e4306a052399 Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 13:15:17 +0800
|
|
Subject: [PATCH 02/16] check netgroup.h header file
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 4 ++++
|
|
1 file changed, 4 insertions(+)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index ae98453..543d6fd 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -26,7 +26,11 @@
|
|
#include <errno.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
+#ifdef HAVE_NETGROUP_H
|
|
+#include <netgroup.h>
|
|
+#else
|
|
#include <netdb.h>
|
|
+#endif
|
|
#include <string.h>
|
|
#include <glib/gstdio.h>
|
|
#include <locale.h>
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 69c761506cbe458807e4ae2742c9e05bc60dad3d Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 10:59:03 +0800
|
|
Subject: [PATCH 03/16] check return value
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 6 +++++-
|
|
1 file changed, 5 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 543d6fd..a54ed5b 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -249,7 +249,11 @@ reload_scripts (PolkitBackendJsAuthority *authority)
|
|
duk_context *cx = authority->priv->cx;
|
|
|
|
duk_set_top (cx, 0);
|
|
- duk_get_global_string (cx, "polkit");
|
|
+ if (!duk_get_global_string (cx, "polkit")) {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error deleting old rules, not loading new ones");
|
|
+ return;
|
|
+ }
|
|
duk_push_string (cx, "_deleteRules");
|
|
|
|
duk_call_prop (cx, 0, 0);
|
|
--
|
|
GitLab
|
|
|
|
|
|
From f1536c4899934fd3c8243fda2d084a472fe57d2e Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 11:22:39 +0800
|
|
Subject: [PATCH 04/16] check return value
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 12 ++++++++++--
|
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index a54ed5b..1a7e6d3 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -656,7 +656,10 @@ push_action_and_details (duk_context *cx,
|
|
gchar **keys;
|
|
guint n;
|
|
|
|
- duk_get_global_string (cx, "Action");
|
|
+ if (!duk_get_global_string (cx, "Action")) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
duk_new (cx, 0);
|
|
|
|
set_property_str (cx, "id", action_id);
|
|
@@ -699,7 +702,12 @@ polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveA
|
|
duk_context *cx = authority->priv->cx;
|
|
|
|
duk_set_top (cx, 0);
|
|
- duk_get_global_string (cx, "polkit");
|
|
+ if (!duk_get_global_string (cx, "polkit")) {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error deleting old rules, not loading new ones");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
duk_push_string (cx, "_runAdminRules");
|
|
|
|
if (!push_action_and_details (cx, action_id, details, &error))
|
|
--
|
|
GitLab
|
|
|
|
|
|
From ca15eecf5dc7755947515c1bfc651fd8770aaf8f Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 13:17:16 +0800
|
|
Subject: [PATCH 05/16] check return value
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 10 ++++++++--
|
|
1 file changed, 8 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 1a7e6d3..3f1b32d 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -550,7 +550,10 @@ push_subject (duk_context *cx,
|
|
char *seat_str = NULL;
|
|
char *session_str = NULL;
|
|
|
|
- duk_get_global_string (cx, "Subject");
|
|
+ if (!duk_get_global_string (cx, "Subject")) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
duk_new (cx, 0);
|
|
|
|
if (POLKIT_IS_UNIX_PROCESS (subject))
|
|
@@ -789,8 +792,11 @@ polkit_backend_js_authority_check_authorization_sync (PolkitBackendInteractiveAu
|
|
gboolean good = FALSE;
|
|
duk_context *cx = authority->priv->cx;
|
|
|
|
+ if (!duk_get_global_string (cx, "polkit")) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
duk_set_top (cx, 0);
|
|
- duk_get_global_string (cx, "polkit");
|
|
duk_push_string (cx, "_runRules");
|
|
|
|
if (!push_action_and_details (cx, action_id, details, &error))
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 870348365cc0166e14f28e0d144ed552bba4d794 Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 13:18:13 +0800
|
|
Subject: [PATCH 06/16] check return value
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 3f1b32d..6294ad9 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -843,7 +843,8 @@ polkit_backend_js_authority_check_authorization_sync (PolkitBackendInteractiveAu
|
|
out:
|
|
if (!good)
|
|
ret = POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED;
|
|
- g_free (ret_str);
|
|
+ if (ret_str != NULL)
|
|
+ g_free (ret_str);
|
|
|
|
return ret;
|
|
}
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 81c916ff08fdcee3c7340c4b2d4632086b89666c Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 11:23:04 +0800
|
|
Subject: [PATCH 07/16] fix typecase
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 10 +++++-----
|
|
1 file changed, 5 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 6294ad9..d466c9d 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -1191,7 +1191,7 @@ static void
|
|
utils_on_cancelled (GCancellable *cancellable,
|
|
gpointer user_data)
|
|
{
|
|
- UtilsSpawnData *data = user_data;
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
GError *error;
|
|
|
|
error = NULL;
|
|
@@ -1206,7 +1206,7 @@ utils_read_child_stderr (GIOChannel *channel,
|
|
GIOCondition condition,
|
|
gpointer user_data)
|
|
{
|
|
- UtilsSpawnData *data = user_data;
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
gchar buf[1024];
|
|
gsize bytes_read;
|
|
|
|
@@ -1220,7 +1220,7 @@ utils_read_child_stdout (GIOChannel *channel,
|
|
GIOCondition condition,
|
|
gpointer user_data)
|
|
{
|
|
- UtilsSpawnData *data = user_data;
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
gchar buf[1024];
|
|
gsize bytes_read;
|
|
|
|
@@ -1234,7 +1234,7 @@ utils_child_watch_cb (GPid pid,
|
|
gint status,
|
|
gpointer user_data)
|
|
{
|
|
- UtilsSpawnData *data = user_data;
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
gchar *buf;
|
|
gsize buf_size;
|
|
|
|
@@ -1263,7 +1263,7 @@ utils_child_watch_cb (GPid pid,
|
|
static gboolean
|
|
utils_timeout_cb (gpointer user_data)
|
|
{
|
|
- UtilsSpawnData *data = user_data;
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
|
|
data->timed_out = TRUE;
|
|
|
|
--
|
|
GitLab
|
|
|
|
|
|
From acb956bf52f0a78bf7aaf925876f96e97a146995 Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 18:04:27 +0800
|
|
Subject: [PATCH 08/16] typecase
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 10 +++++-----
|
|
1 file changed, 5 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index d466c9d..237b1ad 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -915,8 +915,8 @@ spawn_cb (GObject *source_object,
|
|
GAsyncResult *res,
|
|
gpointer user_data)
|
|
{
|
|
- SpawnData *data = user_data;
|
|
- data->res = g_object_ref (res);
|
|
+ SpawnData *data = (SpawnData *)user_data;
|
|
+ data->res = (GAsyncResult*)g_object_ref (res);
|
|
g_main_loop_quit (data->loop);
|
|
}
|
|
|
|
@@ -1292,12 +1292,12 @@ utils_spawn (const gchar *const *argv,
|
|
data->simple = g_simple_async_result_new (NULL,
|
|
callback,
|
|
user_data,
|
|
- utils_spawn);
|
|
+ (gpointer*)utils_spawn);
|
|
data->main_context = g_main_context_get_thread_default ();
|
|
if (data->main_context != NULL)
|
|
g_main_context_ref (data->main_context);
|
|
|
|
- data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
|
|
+ data->cancellable = cancellable != NULL ? (GCancellable*)g_object_ref (cancellable) : NULL;
|
|
|
|
data->child_stdout = g_string_new (NULL);
|
|
data->child_stderr = g_string_new (NULL);
|
|
@@ -1397,7 +1397,7 @@ utils_spawn_finish (GAsyncResult *res,
|
|
if (g_simple_async_result_propagate_error (simple, error))
|
|
goto out;
|
|
|
|
- data = g_simple_async_result_get_op_res_gpointer (simple);
|
|
+ data = (UtilsSpawnData*)g_simple_async_result_get_op_res_gpointer (simple);
|
|
|
|
if (data->timed_out)
|
|
{
|
|
--
|
|
GitLab
|
|
|
|
|
|
From be060e4d48aceb09af34868b555b6c73c7afdabb Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 13:53:23 +0800
|
|
Subject: [PATCH 09/16] some change
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
.../polkitbackendduktapeauthority.c | 26 +++++++++++--------
|
|
1 file changed, 15 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 237b1ad..fad9017 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -207,18 +207,22 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
|
|
for (l = files; l != NULL; l = l->next)
|
|
{
|
|
- const gchar *filename = l->data;
|
|
-
|
|
+ const gchar *filename = (gchar *)l->data;
|
|
#if (DUK_VERSION >= 20000)
|
|
- gchar *contents;
|
|
- gsize length;
|
|
- GError *error = NULL;
|
|
- if (!g_file_get_contents (filename, &contents, &length, &error)){
|
|
- g_warning("Error when file contents of %s: %s\n", filename, error->message);
|
|
- g_error_free (error);
|
|
- continue;
|
|
- }
|
|
- if (duk_peval_lstring_noresult(cx, contents,length) != 0)
|
|
+ GFile *file = g_file_new_for_path (filename);
|
|
+ char *contents;
|
|
+ gsize len;
|
|
+ if (!g_file_load_contents (file, NULL, &contents, &len, NULL, NULL))
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "Error compiling script %s",
|
|
+ filename);
|
|
+ g_object_unref (file);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ g_object_unref (file);
|
|
+ if (duk_peval_lstring_noresult(cx, contents,len) != 0)
|
|
#else
|
|
if (duk_peval_file_noresult (cx, filename) != 0)
|
|
#endif
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 2ffb62048a5ebedfe3bb053feb7385c7270ede28 Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 15:25:45 +0800
|
|
Subject: [PATCH 10/16] some change
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
.../polkitbackendduktapeauthority.c | 24 +++++++++----------
|
|
1 file changed, 12 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index fad9017..6fac3be 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -125,6 +125,18 @@ G_DEFINE_TYPE (PolkitBackendJsAuthority, polkit_backend_js_authority, POLKIT_BAC
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
+static duk_ret_t js_polkit_log (duk_context *cx);
|
|
+static duk_ret_t js_polkit_spawn (duk_context *cx);
|
|
+static duk_ret_t js_polkit_user_is_in_netgroup (duk_context *cx);
|
|
+
|
|
+static const duk_function_list_entry js_polkit_functions[] =
|
|
+{
|
|
+ { "log", js_polkit_log, 1 },
|
|
+ { "spawn", js_polkit_spawn, 1 },
|
|
+ { "_userIsInNetGroup", js_polkit_user_is_in_netgroup, 2 },
|
|
+ { NULL, NULL, 0 },
|
|
+};
|
|
+
|
|
static void
|
|
polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
{
|
|
@@ -347,18 +359,6 @@ setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
authority->priv->dir_monitors = (GFileMonitor**) g_ptr_array_free (p, FALSE);
|
|
}
|
|
|
|
-static duk_ret_t js_polkit_log (duk_context *cx);
|
|
-static duk_ret_t js_polkit_spawn (duk_context *cx);
|
|
-static duk_ret_t js_polkit_user_is_in_netgroup (duk_context *cx);
|
|
-
|
|
-static const duk_function_list_entry js_polkit_functions[] =
|
|
-{
|
|
- { "log", js_polkit_log, 1 },
|
|
- { "spawn", js_polkit_spawn, 1 },
|
|
- { "_userIsInNetGroup", js_polkit_user_is_in_netgroup, 2 },
|
|
- { NULL, NULL, 0 },
|
|
-};
|
|
-
|
|
static void
|
|
polkit_backend_js_authority_constructed (GObject *object)
|
|
{
|
|
--
|
|
GitLab
|
|
|
|
|
|
From edb70ef69eed3275f5654510d135e680eb46c85d Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 15:25:35 +0800
|
|
Subject: [PATCH 11/16] remove WATCHDOG_TIMEOUT define
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 1 -
|
|
1 file changed, 1 deletion(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 6fac3be..51e03fd 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -69,7 +69,6 @@ struct _PolkitBackendJsAuthorityPrivate
|
|
duk_context *cx;
|
|
};
|
|
|
|
-#define WATCHDOG_TIMEOUT (15 * G_TIME_SPAN_SECOND)
|
|
|
|
static void utils_spawn (const gchar *const *argv,
|
|
guint timeout_seconds,
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 906ae404f29f15ef8c529b999bf091b5d18ed7ac Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 12:46:40 +0800
|
|
Subject: [PATCH 12/16] add meson build system support
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
meson.build | 11 ++++++++++-
|
|
meson_options.txt | 1 +
|
|
src/polkitbackend/meson.build | 10 ++++++++--
|
|
3 files changed, 19 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/meson.build b/meson.build
|
|
index 858078d..4e44723 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -133,7 +133,13 @@ expat_dep = dependency('expat')
|
|
assert(cc.has_header('expat.h', dependencies: expat_dep), 'Can\'t find expat.h. Please install expat.')
|
|
assert(cc.has_function('XML_ParserCreate', dependencies: expat_dep), 'Can\'t find expat library. Please install expat.')
|
|
|
|
-mozjs_dep = dependency('mozjs-78')
|
|
+js_engine = get_option('js_engine')
|
|
+if js_engine == 'duktape'
|
|
+ js_dep = dependency('duktape')
|
|
+ libm_dep = cc.find_library('m')
|
|
+elif js_engine == 'mozjs'
|
|
+ js_dep = dependency('mozjs-78')
|
|
+endif
|
|
|
|
dbus_dep = dependency('dbus-1', required: false)
|
|
dbus_policydir = pk_prefix / pk_datadir / 'dbus-1/system.d'
|
|
@@ -361,6 +367,9 @@ if enable_logind
|
|
output += ' systemdsystemunitdir: ' + systemd_systemdsystemunitdir + '\n'
|
|
endif
|
|
output += ' polkitd user: ' + polkitd_user + ' \n'
|
|
+output += ' Javascript engine: ' + js_engine + '\n'
|
|
+if enable_logind
|
|
+endif
|
|
output += ' PAM support: ' + enable_pam.to_string() + '\n\n'
|
|
if enable_pam
|
|
output += ' PAM file auth: ' + pam_conf['PAM_FILE_INCLUDE_AUTH'] + '\n'
|
|
diff --git a/meson_options.txt b/meson_options.txt
|
|
index 25e3e77..76aa311 100644
|
|
--- a/meson_options.txt
|
|
+++ b/meson_options.txt
|
|
@@ -16,3 +16,4 @@ option('introspection', type: 'boolean', value: true, description: 'Enable intro
|
|
|
|
option('gtk_doc', type: 'boolean', value: false, description: 'use gtk-doc to build documentation')
|
|
option('man', type: 'boolean', value: false, description: 'build manual pages')
|
|
+option('js_engine', type: 'combo', choices: ['mozjs', 'duktape'], value: 'duktape', description: 'javascript engine')
|
|
diff --git a/src/polkitbackend/meson.build b/src/polkitbackend/meson.build
|
|
index 64f0e4a..489897d 100644
|
|
--- a/src/polkitbackend/meson.build
|
|
+++ b/src/polkitbackend/meson.build
|
|
@@ -5,7 +5,6 @@ sources = files(
|
|
'polkitbackendactionpool.c',
|
|
'polkitbackendauthority.c',
|
|
'polkitbackendinteractiveauthority.c',
|
|
- 'polkitbackendjsauthority.cpp',
|
|
)
|
|
|
|
output = 'initjs.h'
|
|
@@ -21,7 +20,7 @@ sources += custom_target(
|
|
deps = [
|
|
expat_dep,
|
|
libpolkit_gobject_dep,
|
|
- mozjs_dep,
|
|
+ js_dep,
|
|
]
|
|
|
|
c_flags = [
|
|
@@ -31,6 +30,13 @@ c_flags = [
|
|
'-DPACKAGE_SYSCONF_DIR="@0@"'.format(pk_prefix / pk_sysconfdir),
|
|
]
|
|
|
|
+if js_engine == 'duktape'
|
|
+ sources += files('polkitbackendduktapeauthority.c')
|
|
+ deps += libm_dep
|
|
+elif js_engine == 'mozjs'
|
|
+ sources += files('polkitbackendjsauthority.cpp')
|
|
+endif
|
|
+
|
|
if enable_logind
|
|
sources += files('polkitbackendsessionmonitor-systemd.c')
|
|
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 1380b505c25be4aebe54b1b4223a570d64af83cc Mon Sep 17 00:00:00 2001
|
|
From: Wu Xiaotian <yetist@gmail.com>
|
|
Date: Sun, 22 Nov 2020 18:49:14 +0800
|
|
Subject: [PATCH 13/16] fix run error
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/polkitbackendduktapeauthority.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 51e03fd..4b4f8fd 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -795,11 +795,11 @@ polkit_backend_js_authority_check_authorization_sync (PolkitBackendInteractiveAu
|
|
gboolean good = FALSE;
|
|
duk_context *cx = authority->priv->cx;
|
|
|
|
+ duk_set_top (cx, 0);
|
|
if (!duk_get_global_string (cx, "polkit")) {
|
|
goto out;
|
|
}
|
|
|
|
- duk_set_top (cx, 0);
|
|
duk_push_string (cx, "_runRules");
|
|
|
|
if (!push_action_and_details (cx, action_id, details, &error))
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 6856a704b70378948ef5f66e9b09555d97d4070b Mon Sep 17 00:00:00 2001
|
|
From: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
Date: Fri, 10 Sep 2021 15:17:58 -0700
|
|
Subject: [PATCH 14/16] Deduplicate code for "Add duktape as JS engine backend"
|
|
effort/MR
|
|
|
|
This leverages Wu Xiaotian (@yetist)'s original MR
|
|
(https://gitlab.freedesktop.org/polkit/polkit/-/merge_requests/35), in
|
|
an effort to complete said work.
|
|
|
|
This is the first of the requests from maintainers--to reduce
|
|
eliminate code duplication.
|
|
|
|
The runaway-killer missing functionality will come in the sequence.
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
src/polkitbackend/Makefile.am | 1 +
|
|
src/polkitbackend/meson.build | 1 +
|
|
src/polkitbackend/polkitbackendcommon.c | 530 +++++++++++++
|
|
src/polkitbackend/polkitbackendcommon.h | 156 ++++
|
|
.../polkitbackendduktapeauthority.c | 714 ++----------------
|
|
.../polkitbackendjsauthority.cpp | 711 ++---------------
|
|
6 files changed, 790 insertions(+), 1323 deletions(-)
|
|
create mode 100644 src/polkitbackend/polkitbackendcommon.c
|
|
create mode 100644 src/polkitbackend/polkitbackendcommon.h
|
|
|
|
diff --git a/src/polkitbackend/Makefile.am b/src/polkitbackend/Makefile.am
|
|
index abcbc6f..6a8b4ae 100644
|
|
--- a/src/polkitbackend/Makefile.am
|
|
+++ b/src/polkitbackend/Makefile.am
|
|
@@ -31,6 +31,7 @@ libpolkit_backend_1_la_SOURCES = \
|
|
polkitbackend.h \
|
|
polkitbackendtypes.h \
|
|
polkitbackendprivate.h \
|
|
+ polkitbackendcommon.h polkitbackendcommon.c \
|
|
polkitbackendauthority.h polkitbackendauthority.c \
|
|
polkitbackendinteractiveauthority.h polkitbackendinteractiveauthority.c \
|
|
polkitbackendjsauthority.h \
|
|
diff --git a/src/polkitbackend/meson.build b/src/polkitbackend/meson.build
|
|
index 489897d..9ec01b2 100644
|
|
--- a/src/polkitbackend/meson.build
|
|
+++ b/src/polkitbackend/meson.build
|
|
@@ -4,6 +4,7 @@ sources = files(
|
|
'polkitbackendactionlookup.c',
|
|
'polkitbackendactionpool.c',
|
|
'polkitbackendauthority.c',
|
|
+ 'polkitbackendcommon.c',
|
|
'polkitbackendinteractiveauthority.c',
|
|
)
|
|
|
|
diff --git a/src/polkitbackend/polkitbackendcommon.c b/src/polkitbackend/polkitbackendcommon.c
|
|
new file mode 100644
|
|
index 0000000..6783dff
|
|
--- /dev/null
|
|
+++ b/src/polkitbackend/polkitbackendcommon.c
|
|
@@ -0,0 +1,530 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 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 "polkitbackendcommon.h"
|
|
+
|
|
+static void
|
|
+utils_child_watch_from_release_cb (GPid pid,
|
|
+ gint status,
|
|
+ gpointer user_data)
|
|
+{
|
|
+}
|
|
+
|
|
+static void
|
|
+utils_spawn_data_free (UtilsSpawnData *data)
|
|
+{
|
|
+ if (data->timeout_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->timeout_source);
|
|
+ data->timeout_source = NULL;
|
|
+ }
|
|
+
|
|
+ /* Nuke the child, if necessary */
|
|
+ if (data->child_watch_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_watch_source);
|
|
+ data->child_watch_source = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_pid != 0)
|
|
+ {
|
|
+ GSource *source;
|
|
+ kill (data->child_pid, SIGTERM);
|
|
+ /* OK, we need to reap for the child ourselves - we don't want
|
|
+ * to use waitpid() because that might block the calling
|
|
+ * thread (the child might handle SIGTERM and use several
|
|
+ * seconds for cleanup/rollback).
|
|
+ *
|
|
+ * So we use GChildWatch instead.
|
|
+ *
|
|
+ * Avoid taking a references to ourselves. but note that we need
|
|
+ * to pass the GSource so we can nuke it once handled.
|
|
+ */
|
|
+ source = g_child_watch_source_new (data->child_pid);
|
|
+ g_source_set_callback (source,
|
|
+ (GSourceFunc) utils_child_watch_from_release_cb,
|
|
+ source,
|
|
+ (GDestroyNotify) g_source_destroy);
|
|
+ g_source_attach (source, data->main_context);
|
|
+ g_source_unref (source);
|
|
+ data->child_pid = 0;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout != NULL)
|
|
+ {
|
|
+ g_string_free (data->child_stdout, TRUE);
|
|
+ data->child_stdout = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stderr != NULL)
|
|
+ {
|
|
+ g_string_free (data->child_stderr, TRUE);
|
|
+ data->child_stderr = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_channel != NULL)
|
|
+ {
|
|
+ g_io_channel_unref (data->child_stdout_channel);
|
|
+ data->child_stdout_channel = NULL;
|
|
+ }
|
|
+ if (data->child_stderr_channel != NULL)
|
|
+ {
|
|
+ g_io_channel_unref (data->child_stderr_channel);
|
|
+ data->child_stderr_channel = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_stdout_source);
|
|
+ data->child_stdout_source = NULL;
|
|
+ }
|
|
+ if (data->child_stderr_source != NULL)
|
|
+ {
|
|
+ g_source_destroy (data->child_stderr_source);
|
|
+ data->child_stderr_source = NULL;
|
|
+ }
|
|
+
|
|
+ if (data->child_stdout_fd != -1)
|
|
+ {
|
|
+ g_warn_if_fail (close (data->child_stdout_fd) == 0);
|
|
+ data->child_stdout_fd = -1;
|
|
+ }
|
|
+ if (data->child_stderr_fd != -1)
|
|
+ {
|
|
+ g_warn_if_fail (close (data->child_stderr_fd) == 0);
|
|
+ data->child_stderr_fd = -1;
|
|
+ }
|
|
+
|
|
+ if (data->cancellable_handler_id > 0)
|
|
+ {
|
|
+ g_cancellable_disconnect (data->cancellable, data->cancellable_handler_id);
|
|
+ data->cancellable_handler_id = 0;
|
|
+ }
|
|
+
|
|
+ if (data->main_context != NULL)
|
|
+ g_main_context_unref (data->main_context);
|
|
+
|
|
+ if (data->cancellable != NULL)
|
|
+ g_object_unref (data->cancellable);
|
|
+
|
|
+ g_slice_free (UtilsSpawnData, data);
|
|
+}
|
|
+
|
|
+/* called in the thread where @cancellable was cancelled */
|
|
+static void
|
|
+utils_on_cancelled (GCancellable *cancellable,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
+ GError *error;
|
|
+
|
|
+ error = NULL;
|
|
+ g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_timeout_cb (gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
+
|
|
+ data->timed_out = TRUE;
|
|
+
|
|
+ /* ok, timeout is history, make sure we don't free it in spawn_data_free() */
|
|
+ data->timeout_source = NULL;
|
|
+
|
|
+ /* we're done */
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+
|
|
+ return FALSE; /* remove source */
|
|
+}
|
|
+
|
|
+static void
|
|
+utils_child_watch_cb (GPid pid,
|
|
+ gint status,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
+ gchar *buf;
|
|
+ gsize buf_size;
|
|
+
|
|
+ if (g_io_channel_read_to_end (data->child_stdout_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
+ {
|
|
+ g_string_append_len (data->child_stdout, buf, buf_size);
|
|
+ g_free (buf);
|
|
+ }
|
|
+ if (g_io_channel_read_to_end (data->child_stderr_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
+ {
|
|
+ g_string_append_len (data->child_stderr, buf, buf_size);
|
|
+ g_free (buf);
|
|
+ }
|
|
+
|
|
+ data->exit_status = status;
|
|
+
|
|
+ /* ok, child watch is history, make sure we don't free it in spawn_data_free() */
|
|
+ data->child_pid = 0;
|
|
+ data->child_watch_source = NULL;
|
|
+
|
|
+ /* we're done */
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_read_child_stderr (GIOChannel *channel,
|
|
+ GIOCondition condition,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
+ gchar buf[1024];
|
|
+ gsize bytes_read;
|
|
+
|
|
+ g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
+ g_string_append_len (data->child_stderr, buf, bytes_read);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+utils_read_child_stdout (GIOChannel *channel,
|
|
+ GIOCondition condition,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
+ gchar buf[1024];
|
|
+ gsize bytes_read;
|
|
+
|
|
+ g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
+ g_string_append_len (data->child_stdout, buf, bytes_read);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+void
|
|
+polkit_backend_common_spawn (const gchar *const *argv,
|
|
+ guint timeout_seconds,
|
|
+ GCancellable *cancellable,
|
|
+ GAsyncReadyCallback callback,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ UtilsSpawnData *data;
|
|
+ GError *error;
|
|
+
|
|
+ data = g_slice_new0 (UtilsSpawnData);
|
|
+ data->timeout_seconds = timeout_seconds;
|
|
+ data->simple = g_simple_async_result_new (NULL,
|
|
+ callback,
|
|
+ user_data,
|
|
+ (gpointer*)polkit_backend_common_spawn);
|
|
+ data->main_context = g_main_context_get_thread_default ();
|
|
+ if (data->main_context != NULL)
|
|
+ g_main_context_ref (data->main_context);
|
|
+
|
|
+ data->cancellable = cancellable != NULL ? (GCancellable*)g_object_ref (cancellable) : NULL;
|
|
+
|
|
+ data->child_stdout = g_string_new (NULL);
|
|
+ data->child_stderr = g_string_new (NULL);
|
|
+ data->child_stdout_fd = -1;
|
|
+ data->child_stderr_fd = -1;
|
|
+
|
|
+ /* the life-cycle of UtilsSpawnData is tied to its GSimpleAsyncResult */
|
|
+ g_simple_async_result_set_op_res_gpointer (data->simple, data, (GDestroyNotify) utils_spawn_data_free);
|
|
+
|
|
+ error = NULL;
|
|
+ if (data->cancellable != NULL)
|
|
+ {
|
|
+ /* could already be cancelled */
|
|
+ error = NULL;
|
|
+ if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
|
|
+ {
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ data->cancellable_handler_id = g_cancellable_connect (data->cancellable,
|
|
+ G_CALLBACK (utils_on_cancelled),
|
|
+ data,
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
+ error = NULL;
|
|
+ if (!g_spawn_async_with_pipes (NULL, /* working directory */
|
|
+ (gchar **) argv,
|
|
+ NULL, /* envp */
|
|
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
|
|
+ NULL, /* child_setup */
|
|
+ NULL, /* child_setup's user_data */
|
|
+ &(data->child_pid),
|
|
+ NULL, /* gint *stdin_fd */
|
|
+ &(data->child_stdout_fd),
|
|
+ &(data->child_stderr_fd),
|
|
+ &error))
|
|
+ {
|
|
+ g_prefix_error (&error, "Error spawning: ");
|
|
+ g_simple_async_result_take_error (data->simple, error);
|
|
+ g_simple_async_result_complete_in_idle (data->simple);
|
|
+ g_object_unref (data->simple);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (timeout_seconds > 0)
|
|
+ {
|
|
+ data->timeout_source = g_timeout_source_new_seconds (timeout_seconds);
|
|
+ g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
|
|
+ g_source_set_callback (data->timeout_source, utils_timeout_cb, data, NULL);
|
|
+ g_source_attach (data->timeout_source, data->main_context);
|
|
+ g_source_unref (data->timeout_source);
|
|
+ }
|
|
+
|
|
+ data->child_watch_source = g_child_watch_source_new (data->child_pid);
|
|
+ g_source_set_callback (data->child_watch_source, (GSourceFunc) utils_child_watch_cb, data, NULL);
|
|
+ g_source_attach (data->child_watch_source, data->main_context);
|
|
+ g_source_unref (data->child_watch_source);
|
|
+
|
|
+ data->child_stdout_channel = g_io_channel_unix_new (data->child_stdout_fd);
|
|
+ g_io_channel_set_flags (data->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
+ data->child_stdout_source = g_io_create_watch (data->child_stdout_channel, G_IO_IN);
|
|
+ g_source_set_callback (data->child_stdout_source, (GSourceFunc) utils_read_child_stdout, data, NULL);
|
|
+ g_source_attach (data->child_stdout_source, data->main_context);
|
|
+ g_source_unref (data->child_stdout_source);
|
|
+
|
|
+ data->child_stderr_channel = g_io_channel_unix_new (data->child_stderr_fd);
|
|
+ g_io_channel_set_flags (data->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
+ data->child_stderr_source = g_io_create_watch (data->child_stderr_channel, G_IO_IN);
|
|
+ g_source_set_callback (data->child_stderr_source, (GSourceFunc) utils_read_child_stderr, data, NULL);
|
|
+ g_source_attach (data->child_stderr_source, data->main_context);
|
|
+ g_source_unref (data->child_stderr_source);
|
|
+
|
|
+ out:
|
|
+ ;
|
|
+}
|
|
+
|
|
+void
|
|
+polkit_backend_common_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 rules");
|
|
+ polkit_backend_common_reload_scripts (authority);
|
|
+ }
|
|
+ g_free (name);
|
|
+ }
|
|
+}
|
|
+
|
|
+gboolean
|
|
+polkit_backend_common_spawn_finish (GAsyncResult *res,
|
|
+ gint *out_exit_status,
|
|
+ gchar **out_standard_output,
|
|
+ gchar **out_standard_error,
|
|
+ GError **error)
|
|
+{
|
|
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
|
|
+ UtilsSpawnData *data;
|
|
+ gboolean ret = FALSE;
|
|
+
|
|
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
|
|
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
+
|
|
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_backend_common_spawn);
|
|
+
|
|
+ if (g_simple_async_result_propagate_error (simple, error))
|
|
+ goto out;
|
|
+
|
|
+ data = (UtilsSpawnData*)g_simple_async_result_get_op_res_gpointer (simple);
|
|
+
|
|
+ if (data->timed_out)
|
|
+ {
|
|
+ g_set_error (error,
|
|
+ G_IO_ERROR,
|
|
+ G_IO_ERROR_TIMED_OUT,
|
|
+ "Timed out after %d seconds",
|
|
+ data->timeout_seconds);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (out_exit_status != NULL)
|
|
+ *out_exit_status = data->exit_status;
|
|
+
|
|
+ if (out_standard_output != NULL)
|
|
+ *out_standard_output = g_strdup (data->child_stdout->str);
|
|
+
|
|
+ if (out_standard_error != NULL)
|
|
+ *out_standard_error = g_strdup (data->child_stderr->str);
|
|
+
|
|
+ ret = TRUE;
|
|
+
|
|
+ out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+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;
|
|
+}
|
|
+
|
|
+void
|
|
+polkit_backend_common_js_authority_class_init_common (PolkitBackendJsAuthorityClass *klass)
|
|
+{
|
|
+ GObjectClass *gobject_class;
|
|
+ PolkitBackendAuthorityClass *authority_class;
|
|
+ PolkitBackendInteractiveAuthorityClass *interactive_authority_class;
|
|
+
|
|
+ gobject_class = G_OBJECT_CLASS (klass);
|
|
+ gobject_class->finalize = polkit_backend_common_js_authority_finalize;
|
|
+ gobject_class->set_property = polkit_backend_common_js_authority_set_property;
|
|
+ gobject_class->constructed = polkit_backend_common_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_common_js_authority_get_admin_auth_identities;
|
|
+ interactive_authority_class->check_authorization_sync = polkit_backend_common_js_authority_check_authorization_sync;
|
|
+
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_RULES_DIRS,
|
|
+ g_param_spec_boxed ("rules-dirs",
|
|
+ NULL,
|
|
+ NULL,
|
|
+ G_TYPE_STRV,
|
|
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
|
|
+}
|
|
+
|
|
+gint
|
|
+polkit_backend_common_rules_file_name_cmp (const gchar *a,
|
|
+ const gchar *b)
|
|
+{
|
|
+ gint ret;
|
|
+ const gchar *a_base;
|
|
+ const gchar *b_base;
|
|
+
|
|
+ a_base = strrchr (a, '/');
|
|
+ b_base = strrchr (b, '/');
|
|
+
|
|
+ g_assert (a_base != NULL);
|
|
+ g_assert (b_base != NULL);
|
|
+ a_base += 1;
|
|
+ b_base += 1;
|
|
+
|
|
+ ret = g_strcmp0 (a_base, b_base);
|
|
+ if (ret == 0)
|
|
+ {
|
|
+ /* /etc wins over /usr */
|
|
+ ret = g_strcmp0 (a, b);
|
|
+ g_assert (ret != 0);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+polkit_backend_common_get_signal_name (gint signal_number)
|
|
+{
|
|
+ switch (signal_number)
|
|
+ {
|
|
+#define _HANDLE_SIG(sig) case sig: return #sig;
|
|
+ _HANDLE_SIG (SIGHUP);
|
|
+ _HANDLE_SIG (SIGINT);
|
|
+ _HANDLE_SIG (SIGQUIT);
|
|
+ _HANDLE_SIG (SIGILL);
|
|
+ _HANDLE_SIG (SIGABRT);
|
|
+ _HANDLE_SIG (SIGFPE);
|
|
+ _HANDLE_SIG (SIGKILL);
|
|
+ _HANDLE_SIG (SIGSEGV);
|
|
+ _HANDLE_SIG (SIGPIPE);
|
|
+ _HANDLE_SIG (SIGALRM);
|
|
+ _HANDLE_SIG (SIGTERM);
|
|
+ _HANDLE_SIG (SIGUSR1);
|
|
+ _HANDLE_SIG (SIGUSR2);
|
|
+ _HANDLE_SIG (SIGCHLD);
|
|
+ _HANDLE_SIG (SIGCONT);
|
|
+ _HANDLE_SIG (SIGSTOP);
|
|
+ _HANDLE_SIG (SIGTSTP);
|
|
+ _HANDLE_SIG (SIGTTIN);
|
|
+ _HANDLE_SIG (SIGTTOU);
|
|
+ _HANDLE_SIG (SIGBUS);
|
|
+#ifdef SIGPOLL
|
|
+ _HANDLE_SIG (SIGPOLL);
|
|
+#endif
|
|
+ _HANDLE_SIG (SIGPROF);
|
|
+ _HANDLE_SIG (SIGSYS);
|
|
+ _HANDLE_SIG (SIGTRAP);
|
|
+ _HANDLE_SIG (SIGURG);
|
|
+ _HANDLE_SIG (SIGVTALRM);
|
|
+ _HANDLE_SIG (SIGXCPU);
|
|
+ _HANDLE_SIG (SIGXFSZ);
|
|
+#undef _HANDLE_SIG
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return "UNKNOWN_SIGNAL";
|
|
+}
|
|
+
|
|
+void
|
|
+polkit_backend_common_spawn_cb (GObject *source_object,
|
|
+ GAsyncResult *res,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ SpawnData *data = (SpawnData *)user_data;
|
|
+ data->res = (GAsyncResult*)g_object_ref (res);
|
|
+ g_main_loop_quit (data->loop);
|
|
+}
|
|
diff --git a/src/polkitbackend/polkitbackendcommon.h b/src/polkitbackend/polkitbackendcommon.h
|
|
new file mode 100644
|
|
index 0000000..6d0d267
|
|
--- /dev/null
|
|
+++ b/src/polkitbackend/polkitbackendcommon.h
|
|
@@ -0,0 +1,156 @@
|
|
+/*
|
|
+ * Copyright (C) 2008 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_COMMON_H
|
|
+#define __POLKIT_BACKEND_COMMON_H
|
|
+
|
|
+#include "config.h"
|
|
+#include <sys/wait.h>
|
|
+#include <errno.h>
|
|
+#include <pwd.h>
|
|
+#include <grp.h>
|
|
+#ifdef HAVE_NETGROUP_H
|
|
+#include <netgroup.h>
|
|
+#else
|
|
+#include <netdb.h>
|
|
+#endif
|
|
+#include <string.h>
|
|
+#include <glib/gstdio.h>
|
|
+#include <locale.h>
|
|
+#include <glib/gi18n-lib.h> //here, all things glib via glib.h (including -> gspawn.h)
|
|
+
|
|
+#include <polkit/polkit.h>
|
|
+#include "polkitbackendjsauthority.h"
|
|
+
|
|
+#include <polkit/polkitprivate.h>
|
|
+
|
|
+#ifdef HAVE_LIBSYSTEMD
|
|
+#include <systemd/sd-login.h>
|
|
+#endif /* HAVE_LIBSYSTEMD */
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+enum
|
|
+{
|
|
+ PROP_0,
|
|
+ PROP_RULES_DIRS,
|
|
+};
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ GSimpleAsyncResult *simple; /* borrowed reference */
|
|
+ GMainContext *main_context; /* may be NULL */
|
|
+
|
|
+ GCancellable *cancellable; /* may be NULL */
|
|
+ gulong cancellable_handler_id;
|
|
+
|
|
+ GPid child_pid;
|
|
+ gint child_stdout_fd;
|
|
+ gint child_stderr_fd;
|
|
+
|
|
+ GIOChannel *child_stdout_channel;
|
|
+ GIOChannel *child_stderr_channel;
|
|
+
|
|
+ GSource *child_watch_source;
|
|
+ GSource *child_stdout_source;
|
|
+ GSource *child_stderr_source;
|
|
+
|
|
+ guint timeout_seconds;
|
|
+ gboolean timed_out;
|
|
+ GSource *timeout_source;
|
|
+
|
|
+ GString *child_stdout;
|
|
+ GString *child_stderr;
|
|
+
|
|
+ gint exit_status;
|
|
+} UtilsSpawnData;
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ GMainLoop *loop;
|
|
+ GAsyncResult *res;
|
|
+} SpawnData;
|
|
+
|
|
+void polkit_backend_common_spawn (const gchar *const *argv,
|
|
+ guint timeout_seconds,
|
|
+ GCancellable *cancellable,
|
|
+ GAsyncReadyCallback callback,
|
|
+ gpointer user_data);
|
|
+void polkit_backend_common_spawn_cb (GObject *source_object,
|
|
+ GAsyncResult *res,
|
|
+ gpointer user_data);
|
|
+gboolean polkit_backend_common_spawn_finish (GAsyncResult *res,
|
|
+ gint *out_exit_status,
|
|
+ gchar **out_standard_output,
|
|
+ gchar **out_standard_error,
|
|
+ GError **error);
|
|
+
|
|
+void polkit_backend_common_on_dir_monitor_changed (GFileMonitor *monitor,
|
|
+ GFile *file,
|
|
+ GFile *other_file,
|
|
+ GFileMonitorEvent event_type,
|
|
+ gpointer user_data);
|
|
+
|
|
+void polkit_backend_common_js_authority_class_init_common (PolkitBackendJsAuthorityClass *klass);
|
|
+
|
|
+gint polkit_backend_common_rules_file_name_cmp (const gchar *a,
|
|
+ const gchar *b);
|
|
+
|
|
+const gchar *polkit_backend_common_get_signal_name (gint signal_number);
|
|
+
|
|
+/* To be provided by each JS backend, from here onwards ---------------------------------------------- */
|
|
+
|
|
+void polkit_backend_common_reload_scripts (PolkitBackendJsAuthority *authority);
|
|
+void polkit_backend_common_js_authority_finalize (GObject *object);
|
|
+void polkit_backend_common_js_authority_constructed (GObject *object);
|
|
+GList *polkit_backend_common_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
+ PolkitSubject *caller,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ const gchar *action_id,
|
|
+ PolkitDetails *details);
|
|
+void polkit_backend_common_js_authority_set_property (GObject *object,
|
|
+ guint property_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec);
|
|
+PolkitImplicitAuthorization polkit_backend_common_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);
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* __POLKIT_BACKEND_COMMON_H */
|
|
+
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index 4b4f8fd..a2b4420 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -21,32 +21,12 @@
|
|
* Author: David Zeuthen <davidz@redhat.com>
|
|
*/
|
|
|
|
-#include "config.h"
|
|
-#include <sys/wait.h>
|
|
-#include <errno.h>
|
|
-#include <pwd.h>
|
|
-#include <grp.h>
|
|
-#ifdef HAVE_NETGROUP_H
|
|
-#include <netgroup.h>
|
|
-#else
|
|
-#include <netdb.h>
|
|
-#endif
|
|
-#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 "polkitbackendcommon.h"
|
|
|
|
-#ifdef HAVE_LIBSYSTEMD
|
|
-#include <systemd/sd-login.h>
|
|
-#endif /* HAVE_LIBSYSTEMD */
|
|
+#include "duktape.h"
|
|
|
|
+/* Built source and not too big to worry about deduplication */
|
|
#include "initjs.h" /* init.js */
|
|
-#include "duktape.h"
|
|
|
|
/**
|
|
* SECTION:polkitbackendjsauthority
|
|
@@ -54,10 +34,9 @@
|
|
* @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).
|
|
+ * An (Duktape-based) implementation of #PolkitBackendAuthority that reads and
|
|
+ * evaluates Javascript files and supports interaction with authentication
|
|
+ * agents (virtue of being based on #PolkitBackendInteractiveAuthority).
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
@@ -66,64 +45,16 @@ struct _PolkitBackendJsAuthorityPrivate
|
|
{
|
|
gchar **rules_dirs;
|
|
GFileMonitor **dir_monitors; /* NULL-terminated array of GFileMonitor instances */
|
|
- duk_context *cx;
|
|
-};
|
|
-
|
|
-
|
|
-static void utils_spawn (const gchar *const *argv,
|
|
- guint timeout_seconds,
|
|
- GCancellable *cancellable,
|
|
- GAsyncReadyCallback callback,
|
|
- gpointer user_data);
|
|
-
|
|
-gboolean utils_spawn_finish (GAsyncResult *res,
|
|
- gint *out_exit_status,
|
|
- gchar **out_standard_output,
|
|
- gchar **out_standard_error,
|
|
- GError **error);
|
|
|
|
-static void on_dir_monitor_changed (GFileMonitor *monitor,
|
|
- GFile *file,
|
|
- GFile *other_file,
|
|
- GFileMonitorEvent event_type,
|
|
- gpointer user_data);
|
|
-
|
|
-/* ---------------------------------------------------------------------------------------------------- */
|
|
-
|
|
-enum
|
|
-{
|
|
- PROP_0,
|
|
- PROP_RULES_DIRS,
|
|
+ duk_context *cx;
|
|
};
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-static GList *polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *authority,
|
|
- PolkitSubject *caller,
|
|
- PolkitSubject *subject,
|
|
- PolkitIdentity *user_for_subject,
|
|
- gboolean subject_is_local,
|
|
- gboolean subject_is_active,
|
|
- 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);
|
|
-
|
|
G_DEFINE_TYPE (PolkitBackendJsAuthority, polkit_backend_js_authority, POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY);
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-/* ---------------------------------------------------------------------------------------------------- */
|
|
-
|
|
static duk_ret_t js_polkit_log (duk_context *cx);
|
|
static duk_ret_t js_polkit_spawn (duk_context *cx);
|
|
static duk_ret_t js_polkit_user_is_in_netgroup (duk_context *cx);
|
|
@@ -144,33 +75,6 @@ polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
PolkitBackendJsAuthorityPrivate);
|
|
}
|
|
|
|
-static gint
|
|
-rules_file_name_cmp (const gchar *a,
|
|
- const gchar *b)
|
|
-{
|
|
- gint ret;
|
|
- const gchar *a_base;
|
|
- const gchar *b_base;
|
|
-
|
|
- a_base = strrchr (a, '/');
|
|
- b_base = strrchr (b, '/');
|
|
-
|
|
- g_assert (a_base != NULL);
|
|
- g_assert (b_base != NULL);
|
|
- a_base += 1;
|
|
- b_base += 1;
|
|
-
|
|
- ret = g_strcmp0 (a_base, b_base);
|
|
- if (ret == 0)
|
|
- {
|
|
- /* /etc wins over /usr */
|
|
- ret = g_strcmp0 (a, b);
|
|
- g_assert (ret != 0);
|
|
- }
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
static void
|
|
load_scripts (PolkitBackendJsAuthority *authority)
|
|
{
|
|
@@ -214,7 +118,7 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
}
|
|
}
|
|
|
|
- files = g_list_sort (files, (GCompareFunc) rules_file_name_cmp);
|
|
+ files = g_list_sort (files, (GCompareFunc) polkit_backend_common_rules_file_name_cmp);
|
|
|
|
for (l = files; l != NULL; l = l->next)
|
|
{
|
|
@@ -258,8 +162,8 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
g_list_free_full (files, g_free);
|
|
}
|
|
|
|
-static void
|
|
-reload_scripts (PolkitBackendJsAuthority *authority)
|
|
+void
|
|
+polkit_backend_common_reload_scripts (PolkitBackendJsAuthority *authority)
|
|
{
|
|
duk_context *cx = authority->priv->cx;
|
|
|
|
@@ -282,42 +186,6 @@ reload_scripts (PolkitBackendJsAuthority *authority)
|
|
g_signal_emit_by_name (authority, "changed");
|
|
}
|
|
|
|
-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 rules");
|
|
- reload_scripts (authority);
|
|
- }
|
|
- g_free (name);
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
static void
|
|
setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
{
|
|
@@ -349,7 +217,7 @@ setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
{
|
|
g_signal_connect (monitor,
|
|
"changed",
|
|
- G_CALLBACK (on_dir_monitor_changed),
|
|
+ G_CALLBACK (polkit_backend_common_on_dir_monitor_changed),
|
|
authority);
|
|
g_ptr_array_add (p, monitor);
|
|
}
|
|
@@ -358,8 +226,8 @@ setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
authority->priv->dir_monitors = (GFileMonitor**) g_ptr_array_free (p, FALSE);
|
|
}
|
|
|
|
-static void
|
|
-polkit_backend_js_authority_constructed (GObject *object)
|
|
+void
|
|
+polkit_backend_common_js_authority_constructed (GObject *object)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
duk_context *cx;
|
|
@@ -395,8 +263,8 @@ polkit_backend_js_authority_constructed (GObject *object)
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
-static void
|
|
-polkit_backend_js_authority_finalize (GObject *object)
|
|
+void
|
|
+polkit_backend_common_js_authority_finalize (GObject *object)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
guint n;
|
|
@@ -405,7 +273,7 @@ polkit_backend_js_authority_finalize (GObject *object)
|
|
{
|
|
GFileMonitor *monitor = authority->priv->dir_monitors[n];
|
|
g_signal_handlers_disconnect_by_func (monitor,
|
|
- G_CALLBACK (on_dir_monitor_changed),
|
|
+ G_CALLBACK (polkit_backend_common_on_dir_monitor_changed),
|
|
authority);
|
|
g_object_unref (monitor);
|
|
}
|
|
@@ -417,11 +285,11 @@ polkit_backend_js_authority_finalize (GObject *object)
|
|
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)
|
|
+void
|
|
+polkit_backend_common_js_authority_set_property (GObject *object,
|
|
+ guint property_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
|
|
@@ -438,55 +306,10 @@ polkit_backend_js_authority_set_property (GObject *object,
|
|
}
|
|
}
|
|
|
|
-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_DIRS,
|
|
- g_param_spec_boxed ("rules-dirs",
|
|
- NULL,
|
|
- NULL,
|
|
- G_TYPE_STRV,
|
|
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
|
|
-
|
|
-
|
|
+ polkit_backend_common_js_authority_class_init_common (klass);
|
|
g_type_class_add_private (klass, sizeof (PolkitBackendJsAuthorityPrivate));
|
|
}
|
|
|
|
@@ -689,15 +512,15 @@ push_action_and_details (duk_context *cx,
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-static GList *
|
|
-polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
- PolkitSubject *caller,
|
|
- PolkitSubject *subject,
|
|
- PolkitIdentity *user_for_subject,
|
|
- gboolean subject_is_local,
|
|
- gboolean subject_is_active,
|
|
- const gchar *action_id,
|
|
- PolkitDetails *details)
|
|
+GList *
|
|
+polkit_backend_common_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
+ PolkitSubject *caller,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ const gchar *action_id,
|
|
+ PolkitDetails *details)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
GList *ret = NULL;
|
|
@@ -777,16 +600,16 @@ polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveA
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-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)
|
|
+PolkitImplicitAuthorization
|
|
+polkit_backend_common_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)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
PolkitImplicitAuthorization ret = implicit;
|
|
@@ -864,65 +687,6 @@ js_polkit_log (duk_context *cx)
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-static const gchar *
|
|
-get_signal_name (gint signal_number)
|
|
-{
|
|
- switch (signal_number)
|
|
- {
|
|
-#define _HANDLE_SIG(sig) case sig: return #sig;
|
|
- _HANDLE_SIG (SIGHUP);
|
|
- _HANDLE_SIG (SIGINT);
|
|
- _HANDLE_SIG (SIGQUIT);
|
|
- _HANDLE_SIG (SIGILL);
|
|
- _HANDLE_SIG (SIGABRT);
|
|
- _HANDLE_SIG (SIGFPE);
|
|
- _HANDLE_SIG (SIGKILL);
|
|
- _HANDLE_SIG (SIGSEGV);
|
|
- _HANDLE_SIG (SIGPIPE);
|
|
- _HANDLE_SIG (SIGALRM);
|
|
- _HANDLE_SIG (SIGTERM);
|
|
- _HANDLE_SIG (SIGUSR1);
|
|
- _HANDLE_SIG (SIGUSR2);
|
|
- _HANDLE_SIG (SIGCHLD);
|
|
- _HANDLE_SIG (SIGCONT);
|
|
- _HANDLE_SIG (SIGSTOP);
|
|
- _HANDLE_SIG (SIGTSTP);
|
|
- _HANDLE_SIG (SIGTTIN);
|
|
- _HANDLE_SIG (SIGTTOU);
|
|
- _HANDLE_SIG (SIGBUS);
|
|
-#ifdef SIGPOLL
|
|
- _HANDLE_SIG (SIGPOLL);
|
|
-#endif
|
|
- _HANDLE_SIG (SIGPROF);
|
|
- _HANDLE_SIG (SIGSYS);
|
|
- _HANDLE_SIG (SIGTRAP);
|
|
- _HANDLE_SIG (SIGURG);
|
|
- _HANDLE_SIG (SIGVTALRM);
|
|
- _HANDLE_SIG (SIGXCPU);
|
|
- _HANDLE_SIG (SIGXFSZ);
|
|
-#undef _HANDLE_SIG
|
|
- default:
|
|
- break;
|
|
- }
|
|
- return "UNKNOWN_SIGNAL";
|
|
-}
|
|
-
|
|
-typedef struct
|
|
-{
|
|
- GMainLoop *loop;
|
|
- GAsyncResult *res;
|
|
-} SpawnData;
|
|
-
|
|
-static void
|
|
-spawn_cb (GObject *source_object,
|
|
- GAsyncResult *res,
|
|
- gpointer user_data)
|
|
-{
|
|
- SpawnData *data = (SpawnData *)user_data;
|
|
- data->res = (GAsyncResult*)g_object_ref (res);
|
|
- g_main_loop_quit (data->loop);
|
|
-}
|
|
-
|
|
static duk_ret_t
|
|
js_polkit_spawn (duk_context *cx)
|
|
{
|
|
@@ -962,21 +726,21 @@ js_polkit_spawn (duk_context *cx)
|
|
g_main_context_push_thread_default (context);
|
|
|
|
data.loop = loop;
|
|
- utils_spawn ((const gchar *const *) argv,
|
|
- 10, /* timeout_seconds */
|
|
- NULL, /* cancellable */
|
|
- spawn_cb,
|
|
- &data);
|
|
+ polkit_backend_common_spawn ((const gchar *const *) argv,
|
|
+ 10, /* timeout_seconds */
|
|
+ NULL, /* cancellable */
|
|
+ polkit_backend_common_spawn_cb,
|
|
+ &data);
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
g_main_context_pop_thread_default (context);
|
|
|
|
- if (!utils_spawn_finish (data.res,
|
|
- &exit_status,
|
|
- &standard_output,
|
|
- &standard_error,
|
|
- &error))
|
|
+ if (!polkit_backend_common_spawn_finish (data.res,
|
|
+ &exit_status,
|
|
+ &standard_output,
|
|
+ &standard_error,
|
|
+ &error))
|
|
{
|
|
err_str = g_strdup_printf ("Error spawning helper: %s (%s, %d)",
|
|
error->message, g_quark_to_string (error->domain), error->code);
|
|
@@ -998,7 +762,7 @@ js_polkit_spawn (duk_context *cx)
|
|
{
|
|
g_string_append_printf (gstr,
|
|
"Helper was signaled with signal %s (%d)",
|
|
- get_signal_name (WTERMSIG (exit_status)),
|
|
+ polkit_backend_common_get_signal_name (WTERMSIG (exit_status)),
|
|
WTERMSIG (exit_status));
|
|
}
|
|
g_string_append_printf (gstr, ", stdout=`%s', stderr=`%s'",
|
|
@@ -1052,377 +816,3 @@ js_polkit_user_is_in_netgroup (duk_context *cx)
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
-
|
|
-typedef struct
|
|
-{
|
|
- GSimpleAsyncResult *simple; /* borrowed reference */
|
|
- GMainContext *main_context; /* may be NULL */
|
|
-
|
|
- GCancellable *cancellable; /* may be NULL */
|
|
- gulong cancellable_handler_id;
|
|
-
|
|
- GPid child_pid;
|
|
- gint child_stdout_fd;
|
|
- gint child_stderr_fd;
|
|
-
|
|
- GIOChannel *child_stdout_channel;
|
|
- GIOChannel *child_stderr_channel;
|
|
-
|
|
- GSource *child_watch_source;
|
|
- GSource *child_stdout_source;
|
|
- GSource *child_stderr_source;
|
|
-
|
|
- guint timeout_seconds;
|
|
- gboolean timed_out;
|
|
- GSource *timeout_source;
|
|
-
|
|
- GString *child_stdout;
|
|
- GString *child_stderr;
|
|
-
|
|
- gint exit_status;
|
|
-} UtilsSpawnData;
|
|
-
|
|
-static void
|
|
-utils_child_watch_from_release_cb (GPid pid,
|
|
- gint status,
|
|
- gpointer user_data)
|
|
-{
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_spawn_data_free (UtilsSpawnData *data)
|
|
-{
|
|
- if (data->timeout_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->timeout_source);
|
|
- data->timeout_source = NULL;
|
|
- }
|
|
-
|
|
- /* Nuke the child, if necessary */
|
|
- if (data->child_watch_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_watch_source);
|
|
- data->child_watch_source = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_pid != 0)
|
|
- {
|
|
- GSource *source;
|
|
- kill (data->child_pid, SIGTERM);
|
|
- /* OK, we need to reap for the child ourselves - we don't want
|
|
- * to use waitpid() because that might block the calling
|
|
- * thread (the child might handle SIGTERM and use several
|
|
- * seconds for cleanup/rollback).
|
|
- *
|
|
- * So we use GChildWatch instead.
|
|
- *
|
|
- * Avoid taking a references to ourselves. but note that we need
|
|
- * to pass the GSource so we can nuke it once handled.
|
|
- */
|
|
- source = g_child_watch_source_new (data->child_pid);
|
|
- g_source_set_callback (source,
|
|
- (GSourceFunc) utils_child_watch_from_release_cb,
|
|
- source,
|
|
- (GDestroyNotify) g_source_destroy);
|
|
- g_source_attach (source, data->main_context);
|
|
- g_source_unref (source);
|
|
- data->child_pid = 0;
|
|
- }
|
|
-
|
|
- if (data->child_stdout != NULL)
|
|
- {
|
|
- g_string_free (data->child_stdout, TRUE);
|
|
- data->child_stdout = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stderr != NULL)
|
|
- {
|
|
- g_string_free (data->child_stderr, TRUE);
|
|
- data->child_stderr = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_channel != NULL)
|
|
- {
|
|
- g_io_channel_unref (data->child_stdout_channel);
|
|
- data->child_stdout_channel = NULL;
|
|
- }
|
|
- if (data->child_stderr_channel != NULL)
|
|
- {
|
|
- g_io_channel_unref (data->child_stderr_channel);
|
|
- data->child_stderr_channel = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_stdout_source);
|
|
- data->child_stdout_source = NULL;
|
|
- }
|
|
- if (data->child_stderr_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_stderr_source);
|
|
- data->child_stderr_source = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_fd != -1)
|
|
- {
|
|
- g_warn_if_fail (close (data->child_stdout_fd) == 0);
|
|
- data->child_stdout_fd = -1;
|
|
- }
|
|
- if (data->child_stderr_fd != -1)
|
|
- {
|
|
- g_warn_if_fail (close (data->child_stderr_fd) == 0);
|
|
- data->child_stderr_fd = -1;
|
|
- }
|
|
-
|
|
- if (data->cancellable_handler_id > 0)
|
|
- {
|
|
- g_cancellable_disconnect (data->cancellable, data->cancellable_handler_id);
|
|
- data->cancellable_handler_id = 0;
|
|
- }
|
|
-
|
|
- if (data->main_context != NULL)
|
|
- g_main_context_unref (data->main_context);
|
|
-
|
|
- if (data->cancellable != NULL)
|
|
- g_object_unref (data->cancellable);
|
|
-
|
|
- g_slice_free (UtilsSpawnData, data);
|
|
-}
|
|
-
|
|
-/* called in the thread where @cancellable was cancelled */
|
|
-static void
|
|
-utils_on_cancelled (GCancellable *cancellable,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- GError *error;
|
|
-
|
|
- error = NULL;
|
|
- g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_read_child_stderr (GIOChannel *channel,
|
|
- GIOCondition condition,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar buf[1024];
|
|
- gsize bytes_read;
|
|
-
|
|
- g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
- g_string_append_len (data->child_stderr, buf, bytes_read);
|
|
- return TRUE;
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_read_child_stdout (GIOChannel *channel,
|
|
- GIOCondition condition,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar buf[1024];
|
|
- gsize bytes_read;
|
|
-
|
|
- g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
- g_string_append_len (data->child_stdout, buf, bytes_read);
|
|
- return TRUE;
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_child_watch_cb (GPid pid,
|
|
- gint status,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar *buf;
|
|
- gsize buf_size;
|
|
-
|
|
- if (g_io_channel_read_to_end (data->child_stdout_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
- {
|
|
- g_string_append_len (data->child_stdout, buf, buf_size);
|
|
- g_free (buf);
|
|
- }
|
|
- if (g_io_channel_read_to_end (data->child_stderr_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
- {
|
|
- g_string_append_len (data->child_stderr, buf, buf_size);
|
|
- g_free (buf);
|
|
- }
|
|
-
|
|
- data->exit_status = status;
|
|
-
|
|
- /* ok, child watch is history, make sure we don't free it in spawn_data_free() */
|
|
- data->child_pid = 0;
|
|
- data->child_watch_source = NULL;
|
|
-
|
|
- /* we're done */
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_timeout_cb (gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
-
|
|
- data->timed_out = TRUE;
|
|
-
|
|
- /* ok, timeout is history, make sure we don't free it in spawn_data_free() */
|
|
- data->timeout_source = NULL;
|
|
-
|
|
- /* we're done */
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-
|
|
- return FALSE; /* remove source */
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_spawn (const gchar *const *argv,
|
|
- guint timeout_seconds,
|
|
- GCancellable *cancellable,
|
|
- GAsyncReadyCallback callback,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data;
|
|
- GError *error;
|
|
-
|
|
- data = g_slice_new0 (UtilsSpawnData);
|
|
- data->timeout_seconds = timeout_seconds;
|
|
- data->simple = g_simple_async_result_new (NULL,
|
|
- callback,
|
|
- user_data,
|
|
- (gpointer*)utils_spawn);
|
|
- data->main_context = g_main_context_get_thread_default ();
|
|
- if (data->main_context != NULL)
|
|
- g_main_context_ref (data->main_context);
|
|
-
|
|
- data->cancellable = cancellable != NULL ? (GCancellable*)g_object_ref (cancellable) : NULL;
|
|
-
|
|
- data->child_stdout = g_string_new (NULL);
|
|
- data->child_stderr = g_string_new (NULL);
|
|
- data->child_stdout_fd = -1;
|
|
- data->child_stderr_fd = -1;
|
|
-
|
|
- /* the life-cycle of UtilsSpawnData is tied to its GSimpleAsyncResult */
|
|
- g_simple_async_result_set_op_res_gpointer (data->simple, data, (GDestroyNotify) utils_spawn_data_free);
|
|
-
|
|
- error = NULL;
|
|
- if (data->cancellable != NULL)
|
|
- {
|
|
- /* could already be cancelled */
|
|
- error = NULL;
|
|
- if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
|
|
- {
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- data->cancellable_handler_id = g_cancellable_connect (data->cancellable,
|
|
- G_CALLBACK (utils_on_cancelled),
|
|
- data,
|
|
- NULL);
|
|
- }
|
|
-
|
|
- error = NULL;
|
|
- if (!g_spawn_async_with_pipes (NULL, /* working directory */
|
|
- (gchar **) argv,
|
|
- NULL, /* envp */
|
|
- G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
|
|
- NULL, /* child_setup */
|
|
- NULL, /* child_setup's user_data */
|
|
- &(data->child_pid),
|
|
- NULL, /* gint *stdin_fd */
|
|
- &(data->child_stdout_fd),
|
|
- &(data->child_stderr_fd),
|
|
- &error))
|
|
- {
|
|
- g_prefix_error (&error, "Error spawning: ");
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (timeout_seconds > 0)
|
|
- {
|
|
- data->timeout_source = g_timeout_source_new_seconds (timeout_seconds);
|
|
- g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
|
|
- g_source_set_callback (data->timeout_source, utils_timeout_cb, data, NULL);
|
|
- g_source_attach (data->timeout_source, data->main_context);
|
|
- g_source_unref (data->timeout_source);
|
|
- }
|
|
-
|
|
- data->child_watch_source = g_child_watch_source_new (data->child_pid);
|
|
- g_source_set_callback (data->child_watch_source, (GSourceFunc) utils_child_watch_cb, data, NULL);
|
|
- g_source_attach (data->child_watch_source, data->main_context);
|
|
- g_source_unref (data->child_watch_source);
|
|
-
|
|
- data->child_stdout_channel = g_io_channel_unix_new (data->child_stdout_fd);
|
|
- g_io_channel_set_flags (data->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
- data->child_stdout_source = g_io_create_watch (data->child_stdout_channel, G_IO_IN);
|
|
- g_source_set_callback (data->child_stdout_source, (GSourceFunc) utils_read_child_stdout, data, NULL);
|
|
- g_source_attach (data->child_stdout_source, data->main_context);
|
|
- g_source_unref (data->child_stdout_source);
|
|
-
|
|
- data->child_stderr_channel = g_io_channel_unix_new (data->child_stderr_fd);
|
|
- g_io_channel_set_flags (data->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
- data->child_stderr_source = g_io_create_watch (data->child_stderr_channel, G_IO_IN);
|
|
- g_source_set_callback (data->child_stderr_source, (GSourceFunc) utils_read_child_stderr, data, NULL);
|
|
- g_source_attach (data->child_stderr_source, data->main_context);
|
|
- g_source_unref (data->child_stderr_source);
|
|
-
|
|
- out:
|
|
- ;
|
|
-}
|
|
-
|
|
-gboolean
|
|
-utils_spawn_finish (GAsyncResult *res,
|
|
- gint *out_exit_status,
|
|
- gchar **out_standard_output,
|
|
- gchar **out_standard_error,
|
|
- GError **error)
|
|
-{
|
|
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
|
|
- UtilsSpawnData *data;
|
|
- gboolean ret = FALSE;
|
|
-
|
|
- g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
|
|
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
-
|
|
- g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == utils_spawn);
|
|
-
|
|
- if (g_simple_async_result_propagate_error (simple, error))
|
|
- goto out;
|
|
-
|
|
- data = (UtilsSpawnData*)g_simple_async_result_get_op_res_gpointer (simple);
|
|
-
|
|
- if (data->timed_out)
|
|
- {
|
|
- g_set_error (error,
|
|
- G_IO_ERROR,
|
|
- G_IO_ERROR_TIMED_OUT,
|
|
- "Timed out after %d seconds",
|
|
- data->timeout_seconds);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (out_exit_status != NULL)
|
|
- *out_exit_status = data->exit_status;
|
|
-
|
|
- if (out_standard_output != NULL)
|
|
- *out_standard_output = g_strdup (data->child_stdout->str);
|
|
-
|
|
- if (out_standard_error != NULL)
|
|
- *out_standard_error = g_strdup (data->child_stderr->str);
|
|
-
|
|
- ret = TRUE;
|
|
-
|
|
- out:
|
|
- return ret;
|
|
-}
|
|
diff --git a/src/polkitbackend/polkitbackendjsauthority.cpp b/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
index ca17108..e28091d 100644
|
|
--- a/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
+++ b/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
@@ -19,29 +19,7 @@
|
|
* Author: David Zeuthen <davidz@redhat.com>
|
|
*/
|
|
|
|
-#include "config.h"
|
|
-#include <sys/wait.h>
|
|
-#include <errno.h>
|
|
-#include <pwd.h>
|
|
-#include <grp.h>
|
|
-#ifdef HAVE_NETGROUP_H
|
|
-#include <netgroup.h>
|
|
-#else
|
|
-#include <netdb.h>
|
|
-#endif
|
|
-#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>
|
|
-
|
|
-#ifdef HAVE_LIBSYSTEMD
|
|
-#include <systemd/sd-login.h>
|
|
-#endif /* HAVE_LIBSYSTEMD */
|
|
+#include "polkitbackendcommon.h"
|
|
|
|
#include <js/CompilationAndEvaluation.h>
|
|
#include <js/ContextOptions.h>
|
|
@@ -52,6 +30,7 @@
|
|
#include <js/Array.h>
|
|
#include <jsapi.h>
|
|
|
|
+/* Built source and not too big to worry about deduplication */
|
|
#include "initjs.h" /* init.js */
|
|
|
|
#ifdef JSGC_USE_EXACT_ROOTING
|
|
@@ -67,10 +46,9 @@
|
|
* @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).
|
|
+ * An (SpiderMonkey-based) implementation of #PolkitBackendAuthority that reads
|
|
+ * and evaluates Javascript files and supports interaction with authentication
|
|
+ * agents (virtue of being based on #PolkitBackendInteractiveAuthority).
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
@@ -100,57 +78,11 @@ static bool execute_script_with_runaway_killer (PolkitBackendJsAuthority *author
|
|
JS::HandleScript script,
|
|
JS::MutableHandleValue rval);
|
|
|
|
-static void utils_spawn (const gchar *const *argv,
|
|
- guint timeout_seconds,
|
|
- GCancellable *cancellable,
|
|
- GAsyncReadyCallback callback,
|
|
- gpointer user_data);
|
|
-
|
|
-gboolean utils_spawn_finish (GAsyncResult *res,
|
|
- gint *out_exit_status,
|
|
- gchar **out_standard_output,
|
|
- gchar **out_standard_error,
|
|
- GError **error);
|
|
-
|
|
-static void on_dir_monitor_changed (GFileMonitor *monitor,
|
|
- GFile *file,
|
|
- GFile *other_file,
|
|
- GFileMonitorEvent event_type,
|
|
- gpointer user_data);
|
|
-
|
|
-/* ---------------------------------------------------------------------------------------------------- */
|
|
-
|
|
-enum
|
|
-{
|
|
- PROP_0,
|
|
- PROP_RULES_DIRS,
|
|
-};
|
|
-
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
static gpointer runaway_killer_thread_func (gpointer user_data);
|
|
static void runaway_killer_terminate (PolkitBackendJsAuthority *authority);
|
|
|
|
-static GList *polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *authority,
|
|
- PolkitSubject *caller,
|
|
- PolkitSubject *subject,
|
|
- PolkitIdentity *user_for_subject,
|
|
- gboolean subject_is_local,
|
|
- gboolean subject_is_active,
|
|
- 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);
|
|
-
|
|
G_DEFINE_TYPE (PolkitBackendJsAuthority, polkit_backend_js_authority, POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY);
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
@@ -229,33 +161,6 @@ polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
PolkitBackendJsAuthorityPrivate);
|
|
}
|
|
|
|
-static gint
|
|
-rules_file_name_cmp (const gchar *a,
|
|
- const gchar *b)
|
|
-{
|
|
- gint ret;
|
|
- const gchar *a_base;
|
|
- const gchar *b_base;
|
|
-
|
|
- a_base = strrchr (a, '/');
|
|
- b_base = strrchr (b, '/');
|
|
-
|
|
- g_assert (a_base != NULL);
|
|
- g_assert (b_base != NULL);
|
|
- a_base += 1;
|
|
- b_base += 1;
|
|
-
|
|
- ret = g_strcmp0 (a_base, b_base);
|
|
- if (ret == 0)
|
|
- {
|
|
- /* /etc wins over /usr */
|
|
- ret = g_strcmp0 (a, b);
|
|
- g_assert (ret != 0);
|
|
- }
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
/* authority->priv->cx must be within a request */
|
|
static void
|
|
load_scripts (PolkitBackendJsAuthority *authority)
|
|
@@ -299,7 +204,7 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
}
|
|
}
|
|
|
|
- files = g_list_sort (files, (GCompareFunc) rules_file_name_cmp);
|
|
+ files = g_list_sort (files, (GCompareFunc) polkit_backend_common_rules_file_name_cmp);
|
|
|
|
for (l = files; l != NULL; l = l->next)
|
|
{
|
|
@@ -365,8 +270,8 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
g_list_free_full (files, g_free);
|
|
}
|
|
|
|
-static void
|
|
-reload_scripts (PolkitBackendJsAuthority *authority)
|
|
+void
|
|
+polkit_backend_common_reload_scripts (PolkitBackendJsAuthority *authority)
|
|
{
|
|
JS::RootedValueArray<1> args(authority->priv->cx);
|
|
JS::RootedValue rval(authority->priv->cx);
|
|
@@ -395,42 +300,6 @@ reload_scripts (PolkitBackendJsAuthority *authority)
|
|
g_signal_emit_by_name (authority, "changed");
|
|
}
|
|
|
|
-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 rules");
|
|
- reload_scripts (authority);
|
|
- }
|
|
- g_free (name);
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
static void
|
|
setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
{
|
|
@@ -462,7 +331,7 @@ setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
{
|
|
g_signal_connect (monitor,
|
|
"changed",
|
|
- G_CALLBACK (on_dir_monitor_changed),
|
|
+ G_CALLBACK (polkit_backend_common_on_dir_monitor_changed),
|
|
authority);
|
|
g_ptr_array_add (p, monitor);
|
|
}
|
|
@@ -471,8 +340,8 @@ setup_file_monitors (PolkitBackendJsAuthority *authority)
|
|
authority->priv->dir_monitors = (GFileMonitor**) g_ptr_array_free (p, FALSE);
|
|
}
|
|
|
|
-static void
|
|
-polkit_backend_js_authority_constructed (GObject *object)
|
|
+void
|
|
+polkit_backend_common_js_authority_constructed (GObject *object)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
|
|
@@ -561,8 +430,8 @@ polkit_backend_js_authority_constructed (GObject *object)
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
-static void
|
|
-polkit_backend_js_authority_finalize (GObject *object)
|
|
+void
|
|
+polkit_backend_common_js_authority_finalize (GObject *object)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
guint n;
|
|
@@ -577,7 +446,7 @@ polkit_backend_js_authority_finalize (GObject *object)
|
|
{
|
|
GFileMonitor *monitor = authority->priv->dir_monitors[n];
|
|
g_signal_handlers_disconnect_by_func (monitor,
|
|
- (gpointer*)G_CALLBACK (on_dir_monitor_changed),
|
|
+ (gpointer*)G_CALLBACK (polkit_backend_common_on_dir_monitor_changed),
|
|
authority);
|
|
g_object_unref (monitor);
|
|
}
|
|
@@ -594,11 +463,11 @@ polkit_backend_js_authority_finalize (GObject *object)
|
|
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)
|
|
+void
|
|
+polkit_backend_common_js_authority_set_property (GObject *object,
|
|
+ guint property_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
|
|
@@ -615,57 +484,12 @@ polkit_backend_js_authority_set_property (GObject *object,
|
|
}
|
|
}
|
|
|
|
-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_DIRS,
|
|
- g_param_spec_boxed ("rules-dirs",
|
|
- NULL,
|
|
- NULL,
|
|
- G_TYPE_STRV,
|
|
- GParamFlags(G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE)));
|
|
-
|
|
+ polkit_backend_common_js_authority_class_init_common (klass);
|
|
|
|
g_type_class_add_private (klass, sizeof (PolkitBackendJsAuthorityPrivate));
|
|
-
|
|
JS_Init ();
|
|
}
|
|
|
|
@@ -1099,15 +923,15 @@ call_js_function_with_runaway_killer (PolkitBackendJsAuthority *authority,
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-static GList *
|
|
-polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
- PolkitSubject *caller,
|
|
- PolkitSubject *subject,
|
|
- PolkitIdentity *user_for_subject,
|
|
- gboolean subject_is_local,
|
|
- gboolean subject_is_active,
|
|
- const gchar *action_id,
|
|
- PolkitDetails *details)
|
|
+GList *
|
|
+polkit_backend_common_js_authority_get_admin_auth_identities (PolkitBackendInteractiveAuthority *_authority,
|
|
+ PolkitSubject *caller,
|
|
+ PolkitSubject *subject,
|
|
+ PolkitIdentity *user_for_subject,
|
|
+ gboolean subject_is_local,
|
|
+ gboolean subject_is_active,
|
|
+ const gchar *action_id,
|
|
+ PolkitDetails *details)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
GList *ret = NULL;
|
|
@@ -1202,16 +1026,16 @@ polkit_backend_js_authority_get_admin_auth_identities (PolkitBackendInteractiveA
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-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)
|
|
+PolkitImplicitAuthorization
|
|
+polkit_backend_common_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)
|
|
{
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (_authority);
|
|
PolkitImplicitAuthorization ret = implicit;
|
|
@@ -1324,65 +1148,6 @@ js_polkit_log (JSContext *cx,
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-static const gchar *
|
|
-get_signal_name (gint signal_number)
|
|
-{
|
|
- switch (signal_number)
|
|
- {
|
|
-#define _HANDLE_SIG(sig) case sig: return #sig;
|
|
- _HANDLE_SIG (SIGHUP);
|
|
- _HANDLE_SIG (SIGINT);
|
|
- _HANDLE_SIG (SIGQUIT);
|
|
- _HANDLE_SIG (SIGILL);
|
|
- _HANDLE_SIG (SIGABRT);
|
|
- _HANDLE_SIG (SIGFPE);
|
|
- _HANDLE_SIG (SIGKILL);
|
|
- _HANDLE_SIG (SIGSEGV);
|
|
- _HANDLE_SIG (SIGPIPE);
|
|
- _HANDLE_SIG (SIGALRM);
|
|
- _HANDLE_SIG (SIGTERM);
|
|
- _HANDLE_SIG (SIGUSR1);
|
|
- _HANDLE_SIG (SIGUSR2);
|
|
- _HANDLE_SIG (SIGCHLD);
|
|
- _HANDLE_SIG (SIGCONT);
|
|
- _HANDLE_SIG (SIGSTOP);
|
|
- _HANDLE_SIG (SIGTSTP);
|
|
- _HANDLE_SIG (SIGTTIN);
|
|
- _HANDLE_SIG (SIGTTOU);
|
|
- _HANDLE_SIG (SIGBUS);
|
|
-#ifdef SIGPOLL
|
|
- _HANDLE_SIG (SIGPOLL);
|
|
-#endif
|
|
- _HANDLE_SIG (SIGPROF);
|
|
- _HANDLE_SIG (SIGSYS);
|
|
- _HANDLE_SIG (SIGTRAP);
|
|
- _HANDLE_SIG (SIGURG);
|
|
- _HANDLE_SIG (SIGVTALRM);
|
|
- _HANDLE_SIG (SIGXCPU);
|
|
- _HANDLE_SIG (SIGXFSZ);
|
|
-#undef _HANDLE_SIG
|
|
- default:
|
|
- break;
|
|
- }
|
|
- return "UNKNOWN_SIGNAL";
|
|
-}
|
|
-
|
|
-typedef struct
|
|
-{
|
|
- GMainLoop *loop;
|
|
- GAsyncResult *res;
|
|
-} SpawnData;
|
|
-
|
|
-static void
|
|
-spawn_cb (GObject *source_object,
|
|
- GAsyncResult *res,
|
|
- gpointer user_data)
|
|
-{
|
|
- SpawnData *data = (SpawnData *)user_data;
|
|
- data->res = (GAsyncResult*)g_object_ref (res);
|
|
- g_main_loop_quit (data->loop);
|
|
-}
|
|
-
|
|
static bool
|
|
js_polkit_spawn (JSContext *cx,
|
|
unsigned js_argc,
|
|
@@ -1440,21 +1205,21 @@ js_polkit_spawn (JSContext *cx,
|
|
g_main_context_push_thread_default (context);
|
|
|
|
data.loop = loop;
|
|
- utils_spawn ((const gchar *const *) argv,
|
|
- 10, /* timeout_seconds */
|
|
- NULL, /* cancellable */
|
|
- spawn_cb,
|
|
- &data);
|
|
+ polkit_backend_common_spawn ((const gchar *const *) argv,
|
|
+ 10, /* timeout_seconds */
|
|
+ NULL, /* cancellable */
|
|
+ polkit_backend_common_spawn_cb,
|
|
+ &data);
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
g_main_context_pop_thread_default (context);
|
|
|
|
- if (!utils_spawn_finish (data.res,
|
|
- &exit_status,
|
|
- &standard_output,
|
|
- &standard_error,
|
|
- &error))
|
|
+ if (!polkit_backend_common_spawn_finish (data.res,
|
|
+ &exit_status,
|
|
+ &standard_output,
|
|
+ &standard_error,
|
|
+ &error))
|
|
{
|
|
JS_ReportErrorUTF8 (cx,
|
|
"Error spawning helper: %s (%s, %d)",
|
|
@@ -1477,7 +1242,7 @@ js_polkit_spawn (JSContext *cx,
|
|
{
|
|
g_string_append_printf (gstr,
|
|
"Helper was signaled with signal %s (%d)",
|
|
- get_signal_name (WTERMSIG (exit_status)),
|
|
+ polkit_backend_common_get_signal_name (WTERMSIG (exit_status)),
|
|
WTERMSIG (exit_status));
|
|
}
|
|
g_string_append_printf (gstr, ", stdout=`%s', stderr=`%s'",
|
|
@@ -1542,381 +1307,5 @@ js_polkit_user_is_in_netgroup (JSContext *cx,
|
|
return ret;
|
|
}
|
|
|
|
-
|
|
-
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
-typedef struct
|
|
-{
|
|
- GSimpleAsyncResult *simple; /* borrowed reference */
|
|
- GMainContext *main_context; /* may be NULL */
|
|
-
|
|
- GCancellable *cancellable; /* may be NULL */
|
|
- gulong cancellable_handler_id;
|
|
-
|
|
- GPid child_pid;
|
|
- gint child_stdout_fd;
|
|
- gint child_stderr_fd;
|
|
-
|
|
- GIOChannel *child_stdout_channel;
|
|
- GIOChannel *child_stderr_channel;
|
|
-
|
|
- GSource *child_watch_source;
|
|
- GSource *child_stdout_source;
|
|
- GSource *child_stderr_source;
|
|
-
|
|
- guint timeout_seconds;
|
|
- gboolean timed_out;
|
|
- GSource *timeout_source;
|
|
-
|
|
- GString *child_stdout;
|
|
- GString *child_stderr;
|
|
-
|
|
- gint exit_status;
|
|
-} UtilsSpawnData;
|
|
-
|
|
-static void
|
|
-utils_child_watch_from_release_cb (GPid pid,
|
|
- gint status,
|
|
- gpointer user_data)
|
|
-{
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_spawn_data_free (UtilsSpawnData *data)
|
|
-{
|
|
- if (data->timeout_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->timeout_source);
|
|
- data->timeout_source = NULL;
|
|
- }
|
|
-
|
|
- /* Nuke the child, if necessary */
|
|
- if (data->child_watch_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_watch_source);
|
|
- data->child_watch_source = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_pid != 0)
|
|
- {
|
|
- GSource *source;
|
|
- kill (data->child_pid, SIGTERM);
|
|
- /* OK, we need to reap for the child ourselves - we don't want
|
|
- * to use waitpid() because that might block the calling
|
|
- * thread (the child might handle SIGTERM and use several
|
|
- * seconds for cleanup/rollback).
|
|
- *
|
|
- * So we use GChildWatch instead.
|
|
- *
|
|
- * Avoid taking a references to ourselves. but note that we need
|
|
- * to pass the GSource so we can nuke it once handled.
|
|
- */
|
|
- source = g_child_watch_source_new (data->child_pid);
|
|
- g_source_set_callback (source,
|
|
- (GSourceFunc) utils_child_watch_from_release_cb,
|
|
- source,
|
|
- (GDestroyNotify) g_source_destroy);
|
|
- /* attach source to the global default main context */
|
|
- g_source_attach (source, NULL);
|
|
- g_source_unref (source);
|
|
- data->child_pid = 0;
|
|
- }
|
|
-
|
|
- if (data->child_stdout != NULL)
|
|
- {
|
|
- g_string_free (data->child_stdout, TRUE);
|
|
- data->child_stdout = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stderr != NULL)
|
|
- {
|
|
- g_string_free (data->child_stderr, TRUE);
|
|
- data->child_stderr = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_channel != NULL)
|
|
- {
|
|
- g_io_channel_unref (data->child_stdout_channel);
|
|
- data->child_stdout_channel = NULL;
|
|
- }
|
|
- if (data->child_stderr_channel != NULL)
|
|
- {
|
|
- g_io_channel_unref (data->child_stderr_channel);
|
|
- data->child_stderr_channel = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_stdout_source);
|
|
- data->child_stdout_source = NULL;
|
|
- }
|
|
- if (data->child_stderr_source != NULL)
|
|
- {
|
|
- g_source_destroy (data->child_stderr_source);
|
|
- data->child_stderr_source = NULL;
|
|
- }
|
|
-
|
|
- if (data->child_stdout_fd != -1)
|
|
- {
|
|
- g_warn_if_fail (close (data->child_stdout_fd) == 0);
|
|
- data->child_stdout_fd = -1;
|
|
- }
|
|
- if (data->child_stderr_fd != -1)
|
|
- {
|
|
- g_warn_if_fail (close (data->child_stderr_fd) == 0);
|
|
- data->child_stderr_fd = -1;
|
|
- }
|
|
-
|
|
- if (data->cancellable_handler_id > 0)
|
|
- {
|
|
- g_cancellable_disconnect (data->cancellable, data->cancellable_handler_id);
|
|
- data->cancellable_handler_id = 0;
|
|
- }
|
|
-
|
|
- if (data->main_context != NULL)
|
|
- g_main_context_unref (data->main_context);
|
|
-
|
|
- if (data->cancellable != NULL)
|
|
- g_object_unref (data->cancellable);
|
|
-
|
|
- g_slice_free (UtilsSpawnData, data);
|
|
-}
|
|
-
|
|
-/* called in the thread where @cancellable was cancelled */
|
|
-static void
|
|
-utils_on_cancelled (GCancellable *cancellable,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- GError *error;
|
|
-
|
|
- error = NULL;
|
|
- g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_read_child_stderr (GIOChannel *channel,
|
|
- GIOCondition condition,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar buf[1024];
|
|
- gsize bytes_read;
|
|
-
|
|
- g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
- g_string_append_len (data->child_stderr, buf, bytes_read);
|
|
- return TRUE;
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_read_child_stdout (GIOChannel *channel,
|
|
- GIOCondition condition,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar buf[1024];
|
|
- gsize bytes_read;
|
|
-
|
|
- g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
|
|
- g_string_append_len (data->child_stdout, buf, bytes_read);
|
|
- return TRUE;
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_child_watch_cb (GPid pid,
|
|
- gint status,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
- gchar *buf;
|
|
- gsize buf_size;
|
|
-
|
|
- if (g_io_channel_read_to_end (data->child_stdout_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
- {
|
|
- g_string_append_len (data->child_stdout, buf, buf_size);
|
|
- g_free (buf);
|
|
- }
|
|
- if (g_io_channel_read_to_end (data->child_stderr_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
|
|
- {
|
|
- g_string_append_len (data->child_stderr, buf, buf_size);
|
|
- g_free (buf);
|
|
- }
|
|
-
|
|
- data->exit_status = status;
|
|
-
|
|
- /* ok, child watch is history, make sure we don't free it in spawn_data_free() */
|
|
- data->child_pid = 0;
|
|
- data->child_watch_source = NULL;
|
|
-
|
|
- /* we're done */
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-utils_timeout_cb (gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data = (UtilsSpawnData *)user_data;
|
|
-
|
|
- data->timed_out = TRUE;
|
|
-
|
|
- /* ok, timeout is history, make sure we don't free it in spawn_data_free() */
|
|
- data->timeout_source = NULL;
|
|
-
|
|
- /* we're done */
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
-
|
|
- return FALSE; /* remove source */
|
|
-}
|
|
-
|
|
-static void
|
|
-utils_spawn (const gchar *const *argv,
|
|
- guint timeout_seconds,
|
|
- GCancellable *cancellable,
|
|
- GAsyncReadyCallback callback,
|
|
- gpointer user_data)
|
|
-{
|
|
- UtilsSpawnData *data;
|
|
- GError *error;
|
|
-
|
|
- data = g_slice_new0 (UtilsSpawnData);
|
|
- data->timeout_seconds = timeout_seconds;
|
|
- data->simple = g_simple_async_result_new (NULL,
|
|
- callback,
|
|
- user_data,
|
|
- (gpointer*)utils_spawn);
|
|
- data->main_context = g_main_context_get_thread_default ();
|
|
- if (data->main_context != NULL)
|
|
- g_main_context_ref (data->main_context);
|
|
-
|
|
- data->cancellable = cancellable != NULL ? (GCancellable*)g_object_ref (cancellable) : NULL;
|
|
-
|
|
- data->child_stdout = g_string_new (NULL);
|
|
- data->child_stderr = g_string_new (NULL);
|
|
- data->child_stdout_fd = -1;
|
|
- data->child_stderr_fd = -1;
|
|
-
|
|
- /* the life-cycle of UtilsSpawnData is tied to its GSimpleAsyncResult */
|
|
- g_simple_async_result_set_op_res_gpointer (data->simple, data, (GDestroyNotify) utils_spawn_data_free);
|
|
-
|
|
- error = NULL;
|
|
- if (data->cancellable != NULL)
|
|
- {
|
|
- /* could already be cancelled */
|
|
- error = NULL;
|
|
- if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
|
|
- {
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- data->cancellable_handler_id = g_cancellable_connect (data->cancellable,
|
|
- G_CALLBACK (utils_on_cancelled),
|
|
- data,
|
|
- NULL);
|
|
- }
|
|
-
|
|
- error = NULL;
|
|
- if (!g_spawn_async_with_pipes (NULL, /* working directory */
|
|
- (gchar **) argv,
|
|
- NULL, /* envp */
|
|
- GSpawnFlags(G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD),
|
|
- NULL, /* child_setup */
|
|
- NULL, /* child_setup's user_data */
|
|
- &(data->child_pid),
|
|
- NULL, /* gint *stdin_fd */
|
|
- &(data->child_stdout_fd),
|
|
- &(data->child_stderr_fd),
|
|
- &error))
|
|
- {
|
|
- g_prefix_error (&error, "Error spawning: ");
|
|
- g_simple_async_result_take_error (data->simple, error);
|
|
- g_simple_async_result_complete_in_idle (data->simple);
|
|
- g_object_unref (data->simple);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (timeout_seconds > 0)
|
|
- {
|
|
- data->timeout_source = g_timeout_source_new_seconds (timeout_seconds);
|
|
- g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
|
|
- g_source_set_callback (data->timeout_source, utils_timeout_cb, data, NULL);
|
|
- g_source_attach (data->timeout_source, data->main_context);
|
|
- g_source_unref (data->timeout_source);
|
|
- }
|
|
-
|
|
- data->child_watch_source = g_child_watch_source_new (data->child_pid);
|
|
- g_source_set_callback (data->child_watch_source, (GSourceFunc) utils_child_watch_cb, data, NULL);
|
|
- g_source_attach (data->child_watch_source, data->main_context);
|
|
- g_source_unref (data->child_watch_source);
|
|
-
|
|
- data->child_stdout_channel = g_io_channel_unix_new (data->child_stdout_fd);
|
|
- g_io_channel_set_flags (data->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
- data->child_stdout_source = g_io_create_watch (data->child_stdout_channel, G_IO_IN);
|
|
- g_source_set_callback (data->child_stdout_source, (GSourceFunc) utils_read_child_stdout, data, NULL);
|
|
- g_source_attach (data->child_stdout_source, data->main_context);
|
|
- g_source_unref (data->child_stdout_source);
|
|
-
|
|
- data->child_stderr_channel = g_io_channel_unix_new (data->child_stderr_fd);
|
|
- g_io_channel_set_flags (data->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL);
|
|
- data->child_stderr_source = g_io_create_watch (data->child_stderr_channel, G_IO_IN);
|
|
- g_source_set_callback (data->child_stderr_source, (GSourceFunc) utils_read_child_stderr, data, NULL);
|
|
- g_source_attach (data->child_stderr_source, data->main_context);
|
|
- g_source_unref (data->child_stderr_source);
|
|
-
|
|
- out:
|
|
- ;
|
|
-}
|
|
-
|
|
-gboolean
|
|
-utils_spawn_finish (GAsyncResult *res,
|
|
- gint *out_exit_status,
|
|
- gchar **out_standard_output,
|
|
- gchar **out_standard_error,
|
|
- GError **error)
|
|
-{
|
|
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
|
|
- UtilsSpawnData *data;
|
|
- gboolean ret = FALSE;
|
|
-
|
|
- g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
|
|
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
-
|
|
- g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == utils_spawn);
|
|
-
|
|
- if (g_simple_async_result_propagate_error (simple, error))
|
|
- goto out;
|
|
-
|
|
- data = (UtilsSpawnData*)g_simple_async_result_get_op_res_gpointer (simple);
|
|
-
|
|
- if (data->timed_out)
|
|
- {
|
|
- g_set_error (error,
|
|
- G_IO_ERROR,
|
|
- G_IO_ERROR_TIMED_OUT,
|
|
- "Timed out after %d seconds",
|
|
- data->timeout_seconds);
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (out_exit_status != NULL)
|
|
- *out_exit_status = data->exit_status;
|
|
-
|
|
- if (out_standard_output != NULL)
|
|
- *out_standard_output = g_strdup (data->child_stdout->str);
|
|
-
|
|
- if (out_standard_error != NULL)
|
|
- *out_standard_error = g_strdup (data->child_stderr->str);
|
|
-
|
|
- ret = TRUE;
|
|
-
|
|
- out:
|
|
- return ret;
|
|
-}
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 4858128107be9c3ab11828ee8f35c5e26efd36ce Mon Sep 17 00:00:00 2001
|
|
From: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
Date: Tue, 14 Sep 2021 14:38:15 -0700
|
|
Subject: [PATCH 15/16] Gitlab CI: add duktape pkgconfig dependency
|
|
|
|
Make way for the CI to be able to build with duktape too
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
.gitlab-ci.yml | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
GitLab
|
|
|
|
|
|
From cd5d6da837fce95f8831a355dad88c83347c7337 Mon Sep 17 00:00:00 2001
|
|
From: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
Date: Mon, 20 Sep 2021 17:17:26 -0700
|
|
Subject: [PATCH 16/16] duktape: implement runaway scripts killer timeout
|
|
|
|
This was missing on Duktape's JS backend proposal, now in. As
|
|
discussed in
|
|
https://gitlab.freedesktop.org/polkit/polkit/-/merge_requests/35 and
|
|
verified by the commit author, Duktape has no interrupt injection
|
|
mechanism (it has no thread-safe API entry whatsoever, even). Using
|
|
DUK_USE_EXEC_TIMEOUT_CHECK is also not feasible, because:
|
|
|
|
i) It must be enabled at build time and shared object builds of the
|
|
lib on distros go with the default options, something we cannot
|
|
change/control
|
|
|
|
ii) That does not account for non-ECMAScript explicit execution
|
|
contexts, like regex execution, native C calls, etc.
|
|
|
|
It has been agreed, on that thread, that pthread_cond_timedwait()-ing
|
|
and having proper Duktape evaluation/execution calls take place in a
|
|
separate thread, to be killed after the runaway script killer's
|
|
accorded timeout value, a reasonable approach. We have considered
|
|
using glib wrappers for direct pthread usage, but that way would make
|
|
it impossible to issue
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, ...) and we want to
|
|
be paranoid in that regard.
|
|
|
|
On Duktape, we don't get to err from the JS context (to be captured by
|
|
the offending script), but to be forcibly killed on timeout scenarios,
|
|
leading to null returns, thus polkit negation, by definition. It's a
|
|
reasonable design/compromise.
|
|
|
|
A fatal error handler routine, for the Duktape context, has also been
|
|
added, using the polkit_backend_authority_log() logging infra to
|
|
better assist users on what went wrong.
|
|
|
|
Finally, the script evaluation routine has been made to use
|
|
duk_peval_lstring() (previously using _noresult variant), so to able
|
|
to present the user with proper error messages, should any occur.
|
|
|
|
The original runaway script killer test has been adjusted to please
|
|
both JS backends.
|
|
|
|
Signed-off-by: Gustavo Lima Chaves <gustavo.chaves@microsoft.com>
|
|
---
|
|
meson.build | 1 +
|
|
src/polkitbackend/meson.build | 1 +
|
|
src/polkitbackend/polkitbackendcommon.h | 2 +
|
|
.../polkitbackendduktapeauthority.c | 236 ++++++++++++++----
|
|
.../polkitbackendjsauthority.cpp | 10 +-
|
|
.../etc/polkit-1/rules.d/10-testing.rules | 6 +-
|
|
.../test-polkitbackendjsauthority.c | 2 +-
|
|
7 files changed, 209 insertions(+), 49 deletions(-)
|
|
|
|
diff --git a/meson.build b/meson.build
|
|
index 4e44723..46956e3 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -137,6 +137,7 @@ js_engine = get_option('js_engine')
|
|
if js_engine == 'duktape'
|
|
js_dep = dependency('duktape')
|
|
libm_dep = cc.find_library('m')
|
|
+ libpthread_dep = cc.find_library('pthread')
|
|
elif js_engine == 'mozjs'
|
|
js_dep = dependency('mozjs-78')
|
|
endif
|
|
diff --git a/src/polkitbackend/meson.build b/src/polkitbackend/meson.build
|
|
index 9ec01b2..4dfea39 100644
|
|
--- a/src/polkitbackend/meson.build
|
|
+++ b/src/polkitbackend/meson.build
|
|
@@ -34,6 +34,7 @@ c_flags = [
|
|
if js_engine == 'duktape'
|
|
sources += files('polkitbackendduktapeauthority.c')
|
|
deps += libm_dep
|
|
+ deps += libpthread_dep
|
|
elif js_engine == 'mozjs'
|
|
sources += files('polkitbackendjsauthority.cpp')
|
|
endif
|
|
diff --git a/src/polkitbackend/polkitbackendcommon.h b/src/polkitbackend/polkitbackendcommon.h
|
|
index 6d0d267..dd700fc 100644
|
|
--- a/src/polkitbackend/polkitbackendcommon.h
|
|
+++ b/src/polkitbackend/polkitbackendcommon.h
|
|
@@ -50,6 +50,8 @@
|
|
#include <systemd/sd-login.h>
|
|
#endif /* HAVE_LIBSYSTEMD */
|
|
|
|
+#define RUNAWAY_KILLER_TIMEOUT (15)
|
|
+
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
diff --git a/src/polkitbackend/polkitbackendduktapeauthority.c b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
index a2b4420..80f1976 100644
|
|
--- a/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
+++ b/src/polkitbackend/polkitbackendduktapeauthority.c
|
|
@@ -47,8 +47,20 @@ struct _PolkitBackendJsAuthorityPrivate
|
|
GFileMonitor **dir_monitors; /* NULL-terminated array of GFileMonitor instances */
|
|
|
|
duk_context *cx;
|
|
+
|
|
+ pthread_t runaway_killer_thread;
|
|
+};
|
|
+
|
|
+enum
|
|
+{
|
|
+ RUNAWAY_KILLER_THREAD_EXIT_STATUS_UNSET,
|
|
+ RUNAWAY_KILLER_THREAD_EXIT_STATUS_SUCCESS,
|
|
+ RUNAWAY_KILLER_THREAD_EXIT_STATUS_FAILURE,
|
|
};
|
|
|
|
+static gboolean execute_script_with_runaway_killer(PolkitBackendJsAuthority *authority,
|
|
+ const gchar *filename);
|
|
+
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
G_DEFINE_TYPE (PolkitBackendJsAuthority, polkit_backend_js_authority, POLKIT_BACKEND_TYPE_INTERACTIVE_AUTHORITY);
|
|
@@ -67,6 +79,15 @@ static const duk_function_list_entry js_polkit_functions[] =
|
|
{ NULL, NULL, 0 },
|
|
};
|
|
|
|
+static void report_error (void *udata,
|
|
+ const char *msg)
|
|
+{
|
|
+ PolkitBackendJsAuthority *authority = udata;
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
+ "fatal Duktape JS backend error: %s",
|
|
+ (msg ? msg : "no message"));
|
|
+}
|
|
+
|
|
static void
|
|
polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
{
|
|
@@ -78,7 +99,6 @@ polkit_backend_js_authority_init (PolkitBackendJsAuthority *authority)
|
|
static void
|
|
load_scripts (PolkitBackendJsAuthority *authority)
|
|
{
|
|
- duk_context *cx = authority->priv->cx;
|
|
GList *files = NULL;
|
|
GList *l;
|
|
guint num_scripts = 0;
|
|
@@ -123,36 +143,9 @@ load_scripts (PolkitBackendJsAuthority *authority)
|
|
for (l = files; l != NULL; l = l->next)
|
|
{
|
|
const gchar *filename = (gchar *)l->data;
|
|
-#if (DUK_VERSION >= 20000)
|
|
- GFile *file = g_file_new_for_path (filename);
|
|
- char *contents;
|
|
- gsize len;
|
|
- if (!g_file_load_contents (file, NULL, &contents, &len, NULL, NULL))
|
|
- {
|
|
- polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
- "Error compiling script %s",
|
|
- filename);
|
|
- g_object_unref (file);
|
|
- continue;
|
|
- }
|
|
|
|
- g_object_unref (file);
|
|
- if (duk_peval_lstring_noresult(cx, contents,len) != 0)
|
|
-#else
|
|
- if (duk_peval_file_noresult (cx, filename) != 0)
|
|
-#endif
|
|
- {
|
|
- polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
- "Error compiling script %s: %s",
|
|
- filename, duk_safe_to_string (authority->priv->cx, -1));
|
|
-#if (DUK_VERSION >= 20000)
|
|
- g_free (contents);
|
|
-#endif
|
|
+ if (!execute_script_with_runaway_killer(authority, filename))
|
|
continue;
|
|
- }
|
|
-#if (DUK_VERSION >= 20000)
|
|
- g_free (contents);
|
|
-#endif
|
|
num_scripts++;
|
|
}
|
|
|
|
@@ -232,7 +225,7 @@ polkit_backend_common_js_authority_constructed (GObject *object)
|
|
PolkitBackendJsAuthority *authority = POLKIT_BACKEND_JS_AUTHORITY (object);
|
|
duk_context *cx;
|
|
|
|
- cx = duk_create_heap (NULL, NULL, NULL, authority, NULL);
|
|
+ cx = duk_create_heap (NULL, NULL, NULL, authority, report_error);
|
|
if (cx == NULL)
|
|
goto fail;
|
|
|
|
@@ -243,6 +236,9 @@ polkit_backend_common_js_authority_constructed (GObject *object)
|
|
duk_put_function_list (cx, -1, js_polkit_functions);
|
|
duk_put_prop_string (cx, -2, "polkit");
|
|
|
|
+ /* load polkit objects/functions into JS context (e.g. addRule(),
|
|
+ * _deleteRules(), _runRules() et al)
|
|
+ */
|
|
duk_eval_string (cx, init_js);
|
|
|
|
if (authority->priv->rules_dirs == NULL)
|
|
@@ -510,6 +506,167 @@ push_action_and_details (duk_context *cx,
|
|
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
+typedef struct {
|
|
+ PolkitBackendJsAuthority *authority;
|
|
+ const gchar *filename;
|
|
+ pthread_cond_t cond;
|
|
+ pthread_mutex_t mutex;
|
|
+ gint ret;
|
|
+} RunawayKillerCtx;
|
|
+
|
|
+static gpointer
|
|
+runaway_killer_thread_execute_js (gpointer user_data)
|
|
+{
|
|
+ RunawayKillerCtx *ctx = user_data;
|
|
+ duk_context *cx = ctx->authority->priv->cx;
|
|
+
|
|
+ int oldtype;
|
|
+
|
|
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
|
|
+
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ GFile *file = g_file_new_for_path(ctx->filename);
|
|
+ char *contents;
|
|
+ gsize len;
|
|
+
|
|
+ if (!g_file_load_contents(file, NULL, &contents, &len, NULL, NULL)) {
|
|
+ polkit_backend_authority_log(POLKIT_BACKEND_AUTHORITY(ctx->authority),
|
|
+ "Error compiling script %s", ctx->filename);
|
|
+ g_object_unref(file);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ g_object_unref(file);
|
|
+
|
|
+ /* evaluate the script, trying to print context in any syntax errors
|
|
+ found */
|
|
+ if (duk_peval_lstring(cx, contents, len) != 0)
|
|
+#else
|
|
+ if (duk_peval_file(cx, ctx->filename) != 0)
|
|
+#endif
|
|
+ {
|
|
+ polkit_backend_authority_log(POLKIT_BACKEND_AUTHORITY(ctx->authority),
|
|
+ "Error compiling script %s: %s", ctx->filename,
|
|
+ duk_safe_to_string(cx, -1));
|
|
+ duk_pop(cx);
|
|
+ goto free_err;
|
|
+ }
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ g_free(contents);
|
|
+#endif
|
|
+
|
|
+ ctx->ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_SUCCESS;
|
|
+ goto end;
|
|
+
|
|
+free_err:
|
|
+#if (DUK_VERSION >= 20000)
|
|
+ g_free(contents);
|
|
+#endif
|
|
+err:
|
|
+ ctx->ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_FAILURE;
|
|
+end:
|
|
+ pthread_cond_signal(&ctx->cond);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static gpointer
|
|
+runaway_killer_thread_call_js (gpointer user_data)
|
|
+{
|
|
+ RunawayKillerCtx *ctx = user_data;
|
|
+ duk_context *cx = ctx->authority->priv->cx;
|
|
+ int oldtype;
|
|
+
|
|
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
|
|
+
|
|
+ if (duk_pcall_prop (cx, 0, 2) != DUK_EXEC_SUCCESS)
|
|
+ {
|
|
+ polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (ctx->authority),
|
|
+ "Error evaluating admin rules: ",
|
|
+ duk_safe_to_string (cx, -1));
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ctx->ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_SUCCESS;
|
|
+ goto end;
|
|
+
|
|
+err:
|
|
+ ctx->ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_FAILURE;
|
|
+end:
|
|
+ pthread_cond_signal(&ctx->cond);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Blocking for at most for RUNAWAY_KILLER_TIMEOUT */
|
|
+static gboolean
|
|
+execute_script_with_runaway_killer(PolkitBackendJsAuthority *authority,
|
|
+ const gchar *filename)
|
|
+{
|
|
+ gint64 end_time;
|
|
+ gboolean cancel = FALSE;
|
|
+ RunawayKillerCtx ctx = {.authority = authority, .filename = filename,
|
|
+ .ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_UNSET,
|
|
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
|
|
+ .cond = PTHREAD_COND_INITIALIZER};
|
|
+ struct timespec abs_time;
|
|
+
|
|
+ pthread_mutex_lock(&ctx.mutex);
|
|
+
|
|
+ clock_gettime(CLOCK_REALTIME, &abs_time);
|
|
+ abs_time.tv_sec += RUNAWAY_KILLER_TIMEOUT;
|
|
+
|
|
+ pthread_create(&authority->priv->runaway_killer_thread, NULL, runaway_killer_thread_execute_js, &ctx);
|
|
+
|
|
+ while (ctx.ret == RUNAWAY_KILLER_THREAD_EXIT_STATUS_UNSET) /* loop to treat spurious wakeups */
|
|
+ if (pthread_cond_timedwait(&ctx.cond, &ctx.mutex, &abs_time) == ETIMEDOUT) {
|
|
+ cancel = TRUE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&ctx.mutex);
|
|
+
|
|
+ if (cancel)
|
|
+ pthread_cancel (authority->priv->runaway_killer_thread);
|
|
+ pthread_join (authority->priv->runaway_killer_thread, NULL);
|
|
+
|
|
+ return ctx.ret == RUNAWAY_KILLER_THREAD_EXIT_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+/* Calls already stacked function and args. Blocking for at most for
|
|
+ * RUNAWAY_KILLER_TIMEOUT
|
|
+ */
|
|
+static gboolean
|
|
+call_js_function_with_runaway_killer(PolkitBackendJsAuthority *authority)
|
|
+{
|
|
+ gint64 end_time;
|
|
+ gboolean cancel = FALSE;
|
|
+ RunawayKillerCtx ctx = {.authority = authority,
|
|
+ .ret = RUNAWAY_KILLER_THREAD_EXIT_STATUS_UNSET,
|
|
+ .mutex = PTHREAD_MUTEX_INITIALIZER,
|
|
+ .cond = PTHREAD_COND_INITIALIZER};
|
|
+ struct timespec abs_time;
|
|
+
|
|
+ pthread_mutex_lock(&ctx.mutex);
|
|
+
|
|
+ clock_gettime(CLOCK_REALTIME, &abs_time);
|
|
+ abs_time.tv_sec += RUNAWAY_KILLER_TIMEOUT;
|
|
+
|
|
+ pthread_create(&authority->priv->runaway_killer_thread, NULL, runaway_killer_thread_call_js, &ctx);
|
|
+
|
|
+ while (ctx.ret == RUNAWAY_KILLER_THREAD_EXIT_STATUS_UNSET) /* loop to treat spurious wakeups */
|
|
+ if (pthread_cond_timedwait(&ctx.cond, &ctx.mutex, &abs_time) == ETIMEDOUT) {
|
|
+ cancel = TRUE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&ctx.mutex);
|
|
+
|
|
+ if (cancel)
|
|
+ pthread_cancel (authority->priv->runaway_killer_thread);
|
|
+ pthread_join (authority->priv->runaway_killer_thread, NULL);
|
|
+
|
|
+ return ctx.ret == RUNAWAY_KILLER_THREAD_EXIT_STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
/* ---------------------------------------------------------------------------------------------------- */
|
|
|
|
GList *
|
|
@@ -557,13 +714,8 @@ polkit_backend_common_js_authority_get_admin_auth_identities (PolkitBackendInter
|
|
goto out;
|
|
}
|
|
|
|
- if (duk_pcall_prop (cx, 0, 2) != DUK_ERR_NONE)
|
|
- {
|
|
- polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
- "Error evaluating admin rules: ",
|
|
- duk_safe_to_string (cx, -1));
|
|
- goto out;
|
|
- }
|
|
+ if (!call_js_function_with_runaway_killer (authority))
|
|
+ goto out;
|
|
|
|
ret_str = duk_require_string (cx, -1);
|
|
|
|
@@ -643,15 +795,11 @@ polkit_backend_common_js_authority_check_authorization_sync (PolkitBackendIntera
|
|
goto out;
|
|
}
|
|
|
|
- if (duk_pcall_prop (cx, 0, 2) != DUK_ERR_NONE)
|
|
- {
|
|
- polkit_backend_authority_log (POLKIT_BACKEND_AUTHORITY (authority),
|
|
- "Error evaluating authorization rules: ",
|
|
- duk_safe_to_string (cx, -1));
|
|
- goto out;
|
|
- }
|
|
+ if (!call_js_function_with_runaway_killer (authority))
|
|
+ goto out;
|
|
|
|
if (duk_is_null(cx, -1)) {
|
|
+ /* this fine, means there was no match, use implicit authorizations */
|
|
good = TRUE;
|
|
goto out;
|
|
}
|
|
diff --git a/src/polkitbackend/polkitbackendjsauthority.cpp b/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
index e28091d..11e91c0 100644
|
|
--- a/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
+++ b/src/polkitbackend/polkitbackendjsauthority.cpp
|
|
@@ -829,11 +829,14 @@ runaway_killer_setup (PolkitBackendJsAuthority *authority)
|
|
{
|
|
g_assert (authority->priv->rkt_source == NULL);
|
|
|
|
- /* set-up timer for runaway scripts, will be executed in runaway_killer_thread */
|
|
+ /* set-up timer for runaway scripts, will be executed in
|
|
+ runaway_killer_thread, that is one, permanent thread running a glib
|
|
+ mainloop (rkt_loop) whose context (rkt_context) has a timeout source
|
|
+ (rkt_source) */
|
|
g_mutex_lock (&authority->priv->rkt_timeout_pending_mutex);
|
|
authority->priv->rkt_timeout_pending = FALSE;
|
|
g_mutex_unlock (&authority->priv->rkt_timeout_pending_mutex);
|
|
- authority->priv->rkt_source = g_timeout_source_new_seconds (15);
|
|
+ authority->priv->rkt_source = g_timeout_source_new_seconds (RUNAWAY_KILLER_TIMEOUT);
|
|
g_source_set_callback (authority->priv->rkt_source, rkt_on_timeout, authority, NULL);
|
|
g_source_attach (authority->priv->rkt_source, authority->priv->rkt_context);
|
|
|
|
@@ -893,6 +896,9 @@ execute_script_with_runaway_killer (PolkitBackendJsAuthority *authority,
|
|
{
|
|
bool ret;
|
|
|
|
+ // tries to JS_ExecuteScript(), may hang for > RUNAWAY_KILLER_TIMEOUT,
|
|
+ // runaway_killer_thread makes sure the call returns, due to exception
|
|
+ // injection
|
|
runaway_killer_setup (authority);
|
|
ret = JS_ExecuteScript (authority->priv->cx,
|
|
script,
|
|
diff --git a/test/data/etc/polkit-1/rules.d/10-testing.rules b/test/data/etc/polkit-1/rules.d/10-testing.rules
|
|
index 98bf062..e346b5d 100644
|
|
--- a/test/data/etc/polkit-1/rules.d/10-testing.rules
|
|
+++ b/test/data/etc/polkit-1/rules.d/10-testing.rules
|
|
@@ -189,8 +189,10 @@ polkit.addRule(function(action, subject) {
|
|
;
|
|
} catch (error) {
|
|
if (error == "Terminating runaway script")
|
|
- return polkit.Result.YES;
|
|
- return polkit.Result.NO;
|
|
+ // Inverted logic to accomodate Duktape's model as well, which
|
|
+ // will always fail with negation, on timeouts
|
|
+ return polkit.Result.NO;
|
|
+ return polkit.Result.YES;
|
|
}
|
|
}
|
|
});
|
|
diff --git a/test/polkitbackend/test-polkitbackendjsauthority.c b/test/polkitbackend/test-polkitbackendjsauthority.c
|
|
index f97e0e0..2103b17 100644
|
|
--- a/test/polkitbackend/test-polkitbackendjsauthority.c
|
|
+++ b/test/polkitbackend/test-polkitbackendjsauthority.c
|
|
@@ -328,7 +328,7 @@ static const RulesTestCase rules_test_cases[] = {
|
|
"net.company.run_away_script",
|
|
"unix-user:root",
|
|
NULL,
|
|
- POLKIT_IMPLICIT_AUTHORIZATION_AUTHORIZED,
|
|
+ POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED,
|
|
},
|
|
|
|
{
|
|
--
|
|
GitLab
|
|
|