PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Fri May 15 12:32:58 PDT 2009


 actions/org.freedesktop.policykit.policy.in                      |   10 
 data/org.freedesktop.PolicyKit1.Authority.xml                    |    2 
 docs/man/Makefile.am                                             |    7 
 docs/man/pkexec.xml                                              |  155 +++
 docs/polkit/Makefile.am                                          |    1 
 docs/polkit/polkit-1-docs.xml                                    |    1 
 po/POTFILES.in                                                   |    2 
 po/da.po                                                         |   72 +
 src/examples/Makefile.am                                         |   39 
 src/examples/frobnicate.c                                        |   68 +
 src/examples/org.freedesktop.policykit.examples.pkexec.policy.in |   22 
 src/polkit/polkitauthority.c                                     |    1 
 src/polkitbackend/polkitbackendlocalauthority.c                  |    2 
 src/programs/Makefile.am                                         |   56 +
 src/programs/pkexec-action-lookup.c                              |  205 ++++
 src/programs/pkexec.c                                            |  473 ++++++++++
 16 files changed, 1091 insertions(+), 25 deletions(-)

New commits:
commit c8c3d835d24fc4ce5a9c596c7d55d85a0311e8d1
Author: David Zeuthen <davidz at redhat.com>
Date:   Fri May 15 15:30:25 2009 -0400

    Add a pkexec(1) command

diff --git a/actions/org.freedesktop.policykit.policy.in b/actions/org.freedesktop.policykit.policy.in
index 72aa67e..d44a0c1 100644
--- a/actions/org.freedesktop.policykit.policy.in
+++ b/actions/org.freedesktop.policykit.policy.in
@@ -48,4 +48,14 @@
       <allow_active>auth_admin_keep</allow_active>
     </defaults>
   </action>
+
+  <action id="org.freedesktop.policykit.exec">
+    <_description>Run programs as another user</_description>
+    <_message>Authentication is required to run a program as another user</_message>
+    <defaults>
+      <allow_any>auth_admin</allow_any>
+      <allow_inactive>auth_admin</allow_inactive>
+      <allow_active>auth_admin</allow_active>
+    </defaults>
+  </action>
 </policyconfig>
diff --git a/data/org.freedesktop.PolicyKit1.Authority.xml b/data/org.freedesktop.PolicyKit1.Authority.xml
index abe0d3f..2347302 100644
--- a/data/org.freedesktop.PolicyKit1.Authority.xml
+++ b/data/org.freedesktop.PolicyKit1.Authority.xml
@@ -108,7 +108,7 @@
 
     <!-- ---------------------------------------------------------------------------------------------------- -->
 
-    <!-- An enumeration for results when checking for an authorization -->
+    <!-- An structure containing the results of an authorization check -->
     <annotation name="org.gtk.EggDBus.DeclareStruct" value="AuthorizationResult">
       <annotation name="org.gtk.EggDBus.DocString.Summary" value="Authorization Results"/>
       <annotation name="org.gtk.EggDBus.DocString" value="Describes the result of calling org.freedesktop.PolicyKit1.Authority.CheckAuthorization()."/>
diff --git a/docs/man/Makefile.am b/docs/man/Makefile.am
index 51db971..67522c1 100644
--- a/docs/man/Makefile.am
+++ b/docs/man/Makefile.am
@@ -6,16 +6,21 @@ if MAN_PAGES_ENABLED
 man_MANS = 				\
 	PolicyKit-1.8			\
 	polkit-1.1			\
+	pkexec.1			\
 	$(NULL)
 
 %-1.8 %-1.1 : %.xml
-	$(XSLTPROC) -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+	$(XSLTPROC) -nonet --xinclude http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+
+pkexec.1 : pkexec.xml
+	$(XSLTPROC) -nonet --xinclude http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
 
 endif # MAN_PAGES_ENABLED
 
 EXTRA_DIST = 				\
 	PolicyKit.xml                   \
 	polkit.xml			\
+	pkexec.xml			\
 	$(NULL)
 
 clean-local:
diff --git a/docs/man/pkexec.xml b/docs/man/pkexec.xml
new file mode 100644
index 0000000..0dd6105
--- /dev/null
+++ b/docs/man/pkexec.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY version SYSTEM "../version.xml">
+]>
+<refentry id="pkexec.1" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <refentryinfo>
+    <title>pkexec</title>
+    <date>May 2009</date>
+    <productname>PolicyKit-1</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>pkexec</refentrytitle>
+    <manvolnum>1</manvolnum>
+    <refmiscinfo class="version"></refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>pkexec</refname>
+    <refpurpose>Execute a command as another user</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>pkexec</command>
+      <arg><option>--version</option></arg>
+      <arg><option>--help</option></arg>
+    </cmdsynopsis>
+
+    <cmdsynopsis>
+      <command>pkexec</command>
+      <group>
+        <arg choice="plain">
+          <option>--user</option>
+          <replaceable>username</replaceable>
+        </arg>
+      </group>
+      <arg choice="plain"><replaceable>PROGRAM</replaceable></arg>
+      <group rep="repeat">
+        <arg choice="plain"><replaceable>ARGUMENTS</replaceable></arg>
+      </group>
+    </cmdsynopsis>
+
+  </refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      <command>pkexec</command> allows an authorized user to
+      execute <replaceable>PROGRAM</replaceable> as another
+      user. If <replaceable>username</replaceable> is not specified,
+      then the program will be executed as the administrative super
+      user, <emphasis>root</emphasis>.
+    </para>
+  </refsect1>
+
+  <refsect1><title>RETURN VALUE</title>
+    <para>
+      Upon successful completion, the return value is the return value
+      of <replaceable>PROGRAM</replaceable>. If the calling process is
+      not authorized or an authorization could not be obtained through
+      authentication or an error occured, <command>pkexec</command>
+      exits with a return value of 127.
+    </para>
+  </refsect1>
+
+  <refsect1><title>SECURITY NOTES</title>
+    <para>
+      Executing a program as another user is a privileged
+      operation. By default the required authorization (See
+      <xref linkend="pkexec-required-authz"/>) requires administrator
+      authentication. In addition, the authentication dialog presented
+      to the user will display the full path to the program to be
+      executed so the user is aware of what will happen.
+    </para>
+    <para>
+      The environment that <replaceable>PROGRAM</replaceable> will run
+      it, will be set to a minimal known and safe environment in order
+      to avoid injecting code
+      through <literal>LD_LIBRARY_PATH</literal> or similar
+      mechanisms. In addition the <literal>PKEXEC_UID</literal>
+      environment variable is set to the user id of the process
+      invoking <command>pkexec</command>. As a
+      result, <command>pkexec</command> will not allow you to run X11
+      applications as another user.
+    </para>
+  </refsect1>
+
+  <refsect1 id="pkexec-required-authz"><title>REQUIRED AUTHORIZATIONS</title>
+    <para>
+      By default,
+      the <emphasis>org.freedesktop.policykit.exec</emphasis>
+      authorization is required unless an action definition file is
+      present for the program in question. To require another
+      authorization, it can be specified using the <emphasis>org.freedesktop.policykit.exec.path</emphasis> annotation on an action (See <xref linkend="pkexec-example"/> for details).
+    </para>
+  </refsect1>
+
+  <refsect1 id="pkexec-example"><title>EXAMPLE</title>
+    <para>
+      To specify what kind of authorization is needed to execute the
+      program <filename>/usr/bin/pk-example-frobnicate</filename> as
+      another user, simply write an action definition file like this
+    </para>
+    <programlisting>
+<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../src/examples/org.freedesktop.policykit.examples.pkexec.policy"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
+    <para>
+      and drop it in
+      the <filename>/usr/share/polkit-1/actions</filename> directory
+      under a suitable name (e.g. matching the namespace of the
+      action).  Note that in addition to specifying the program, the
+      authentication message, description, icon and defaults can be
+      specified.
+    </para>
+    <para>
+      Note that <command>pkexec</command> does no validation of
+      the <replaceable>ARGUMENTS</replaceable> passed
+      to <replaceable>PROGRAM</replaceable>. In the normal case (where
+      administrator authentication is required every
+      time <command>pkexec</command> is used), this is not a
+      problem. However, if an action is used for which the user can
+      retain authorization (or if the user is implicitly authorized),
+      this could be a security hole. Therefore, as a rule of thumb,
+      programs for which the default required authorization is
+      changed, should never implicitly trust user input (e.g. like any
+      other <emphasis>suid</emphasis> program).
+    </para>
+  </refsect1>
+
+  <refsect1><title>AUTHOR</title>
+    <para>
+      Written by David Zeuthen <email>davidz at redhat.com</email> with
+      a lot of help from many others.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>BUGS</title>
+    <para>
+      Please send bug reports to either the distribution or the
+      polkit-devel mailing list,
+      see the link <ulink url="http://lists.freedesktop.org/mailman/listinfo/polkit-devel"/>
+      on how to subscribe.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>PolicyKit-1</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+</refentry>
diff --git a/docs/polkit/Makefile.am b/docs/polkit/Makefile.am
index 0674221..a60dab9 100644
--- a/docs/polkit/Makefile.am
+++ b/docs/polkit/Makefile.am
@@ -54,6 +54,7 @@ content_files =  			    								\
 	../../src/polkit/docbook-interface-org.freedesktop.PolicyKit1.AuthenticationAgent.xml		\
 	../man/PolicyKit.xml										\
 	../man/polkit.xml										\
+	../man/pkexec.xml										\
 	$(NULL)
 
 # Images to copy into HTML directory
diff --git a/docs/polkit/polkit-1-docs.xml b/docs/polkit/polkit-1-docs.xml
index c2da1ea..452c5a7 100644
--- a/docs/polkit/polkit-1-docs.xml
+++ b/docs/polkit/polkit-1-docs.xml
@@ -105,6 +105,7 @@
     <title>Manual Pages</title>
     <xi:include href="../man/PolicyKit.xml"/>
     <xi:include href="../man/polkit.xml"/>
+    <xi:include href="../man/pkexec.xml"/>
   </reference>
 
   <index>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 61bc0ac..00f5500 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,3 +2,5 @@
 # Please keep this file sorted alphabetically.
 [encoding: UTF-8]
 actions/org.freedesktop.policykit.policy.in
+src/examples/org.freedesktop.policykit.examples.pkexec.policy.in
+src/programs/pkexec-action-lookup.c
diff --git a/po/da.po b/po/da.po
index 0ff6eb5..bd88712 100644
--- a/po/da.po
+++ b/po/da.po
@@ -1,51 +1,93 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+# Danish translations for PolicyKit.
+# Copyright (C) 2009 Red Hat, Inc.
+# This file is distributed under the same license as the PolicyKit package.
+# David Zeuthen <davidz at redhat.com>, 2009.
 #
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
+"Project-Id-Version: DeviceKit-disks\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-12-07 16:14-0500\n"
-"PO-Revision-Date: 2008-12-07 16:17-0500\n"
+"POT-Creation-Date: 2009-05-15 13:45-0400\n"
+"PO-Revision-Date: 2009-05-12 17:01-0400\n"
 "Last-Translator: David Zeuthen <davidz at redhat.com>\n"
-"Language-Team: LANGUAGE <LL at li.org>\n"
+"Language-Team: Danish <dansk at dansk-gruppen.dk>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #: ../actions/org.freedesktop.policykit.policy.in.h:1
 msgid "Authentication is required to grant authorizations to other users"
-msgstr "Autentificering er påkrævet for at autorisere andre brugere"
+msgstr "Autorisering er påkrævet for at autorisere andre brugere"
 
 #: ../actions/org.freedesktop.policykit.policy.in.h:2
 msgid ""
 "Authentication is required to modify the defaults for implicit authorizations"
-msgstr "Autentificering er påkrævet for ændre implicit autorisering"
+msgstr "Autorisering er påkrævet for ændre implicit autorisering"
 
 #: ../actions/org.freedesktop.policykit.policy.in.h:3
 msgid "Authentication is required to read authorizations of other users"
-msgstr "Autentificering er påkrævet for at læse andre brugers autoriseringer"
+msgstr "Autorisering er påkrævet for at læse andre brugers autoriseringer"
 
 #: ../actions/org.freedesktop.policykit.policy.in.h:4
 msgid "Authentication is required to revoke authorizations other users"
-msgstr "Autentificering er påkrævet for at fjerne en autosering fra en anden bruger"
+msgstr ""
+"Autorisering er påkrævet for at fjerne en autosering fra en anden bruger"
 
 #: ../actions/org.freedesktop.policykit.policy.in.h:5
+msgid "Authentication is required to run a program as another user"
+msgstr "Autorisering er påkrævet for at afvikle et program som en anden bruger"
+
+#: ../actions/org.freedesktop.policykit.policy.in.h:6
 msgid "Grant authorizations to other users"
 msgstr "Autoriser en anden bruger"
 
-#: ../actions/org.freedesktop.policykit.policy.in.h:6
+#: ../actions/org.freedesktop.policykit.policy.in.h:7
 msgid "Modify defaults for implicit authorizations"
 msgstr "Konfigurer implicit autorisering"
 
-#: ../actions/org.freedesktop.policykit.policy.in.h:7
+#: ../actions/org.freedesktop.policykit.policy.in.h:8
 msgid "Read authorizations of other users"
 msgstr "Læs andre brugers autoriseringer"
 
-#: ../actions/org.freedesktop.policykit.policy.in.h:8
+#: ../actions/org.freedesktop.policykit.policy.in.h:9
 msgid "Revoke authorizations from other users"
 msgstr "Fjern autorisering fra en anden bruger"
 
+#: ../actions/org.freedesktop.policykit.policy.in.h:10
+msgid "Run programs as another user"
+msgstr "Kør et program som en anden bruger"
+
+#: ../src/examples/org.freedesktop.policykit.examples.pkexec.policy.in.h:1
+msgid ""
+"Authentication is required to run the PolicyKit example program Frobnicate"
+msgstr "Autorisering er påkrævet for at afvikle PolicyKit eksemplet Frobnicate"
+
+#: ../src/examples/org.freedesktop.policykit.examples.pkexec.policy.in.h:2
+msgid "Run the PolicyKit example program Frobnicate"
+msgstr "Kør PolicyKit eksemplet Frobnicate"
+
+#. Translator: %s is a fully qualified path to the executable
+#: ../src/programs/pkexec-action-lookup.c:110
+#, c-format
+msgid "Authentication is needed to run `%s' as the super user"
+msgstr "Autorisering er påkrævet for at afvikle `%s' som super bruger"
+
+#. Translator: %s is a fully qualified path to the executable
+#: ../src/programs/pkexec-action-lookup.c:115
+#, c-format
+msgid "Authentication is needed to run `%s' as another user"
+msgstr "Autorisering er påkrævet for at afvikle `%s' som en anden bruger"
+
+#: ../src/programs/pkexec-action-lookup.c:159
+msgid "Command"
+msgstr "Program"
+
+#: ../src/programs/pkexec-action-lookup.c:168
+msgid "Super User (root)"
+msgstr "Super Bruger (root)"
+
+#: ../src/programs/pkexec-action-lookup.c:170
+msgid "Run As"
+msgstr "Bruger"
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
index 1c40863..b30155b 100644
--- a/src/examples/Makefile.am
+++ b/src/examples/Makefile.am
@@ -15,7 +15,12 @@ INCLUDES =                                              	\
 	-D_REENTRANT	                                	\
 	$(NULL)
 
-noinst_PROGRAMS = cancel
+bin_PROGRAMS =
+noinst_PROGRAMS =
+
+# ----------------------------------------------------------------------------------------------------
+
+noinst_PROGRAMS += cancel
 
 cancel_SOURCES = cancel.c
 
@@ -24,9 +29,39 @@ cancel_CFLAGS =                             			\
 	$(NULL)
 
 cancel_LDADD =  	                      			\
-	$(GLIB_LDADD)						\
+	$(GLIB_LIBS)						\
 	$(top_builddir)/src/polkit/libpolkit-gobject-1.la	\
 	$(NULL)
 
+
+# ----------------------------------------------------------------------------------------------------
+
+bin_PROGRAMS += pk-example-frobnicate
+
+pk_example_frobnicate_SOURCES = frobnicate.c
+
+pk_example_frobnicate_CFLAGS =                             	\
+	$(GLIB_CFLAGS)						\
+	$(NULL)
+
+pk_example_frobnicate_LDADD =  	                      		\
+	$(GLIB_LIBS)						\
+	$(NULL)
+
+polkit_actiondir = $(datadir)/polkit-1/actions
+
+dist_polkit_action_DATA = org.freedesktop.policykit.examples.pkexec.policy
+
+ at INTLTOOL_POLICY_RULE@
+
+#check:
+#       $(top_builddir)/tools/polkit-policy-file-validate-1 $(top_srcdir)/policy/$(dist_polkit_action_DATA)
+
+DISTCLEANFILES = org.freedesktop.policykit.examples.pkexec.policy
+
+EXTRA_DIST = org.freedesktop.policykit.examples.pkexec.policy.in
+
+# ----------------------------------------------------------------------------------------------------
+
 clean-local :
 	rm -f *~
diff --git a/src/examples/frobnicate.c b/src/examples/frobnicate.c
new file mode 100644
index 0000000..6b6b8ff
--- /dev/null
+++ b/src/examples/frobnicate.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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 at redhat.com>
+ */
+
+#include <glib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+int
+main (int argc, char *argv[])
+{
+  gchar *args;
+  gchar **env;
+  guint n;
+  int ret;
+  gchar cwd[PATH_MAX];
+
+  ret = 1;
+  args = NULL;
+  env = NULL;
+
+  if (getcwd (cwd, sizeof cwd) == NULL)
+    {
+      g_printerr ("Error getting cwd: %m");
+      goto out;
+    }
+
+  args = g_strjoinv (" ", argv);
+
+  g_print ("In pk-example-frobnicate\n");
+  g_print ("uid:           %d\n", getuid ());
+  g_print ("euid:          %d\n", geteuid ());
+  g_print ("args:         `%s'\n", args);
+  g_print ("cwd:           %s\n", cwd);
+  g_print ("environment:\n");
+
+  env = g_listenv ();
+  for (n = 0; env[n] != NULL; n++)
+    {
+      g_print ("  %s=%s\n", env[n], g_getenv (env[n]));
+    }
+
+  ret = 0;
+
+ out:
+
+  g_free (args);
+  g_strfreev (env);
+
+  return ret;
+}
diff --git a/src/examples/org.freedesktop.policykit.examples.pkexec.policy.in b/src/examples/org.freedesktop.policykit.examples.pkexec.policy.in
new file mode 100644
index 0000000..b2139cf
--- /dev/null
+++ b/src/examples/org.freedesktop.policykit.examples.pkexec.policy.in
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+<policyconfig>
+
+  <vendor>Examples for the PolicyKit Project</vendor>
+  <vendor_url>http://hal.freedesktop.org/docs/PolicyKit/</vendor_url>
+
+  <action id="org.freedesktop.policykit.example.pkexec.run-frobnicate">
+    <_description>Run the PolicyKit example program Frobnicate</_description>
+    <_message>Authentication is required to run the PolicyKit example program Frobnicate</_message>
+    <icon_name>audio-x-generic</icon_name> <!-- just an example -->
+    <defaults>
+      <allow_any>no</allow_any>
+      <allow_inactive>no</allow_inactive>
+      <allow_active>auth_admin_keep</allow_active>
+    </defaults>
+    <annotate key="org.freedesktop.policykit.exec.path">/usr/bin/pk-example-frobnicate</annotate>
+  </action>
+
+</policyconfig>
diff --git a/src/polkit/polkitauthority.c b/src/polkit/polkitauthority.c
index 5505346..82c9d91 100644
--- a/src/polkit/polkitauthority.c
+++ b/src/polkit/polkitauthority.c
@@ -467,6 +467,7 @@ polkit_authority_check_authorization_finish (PolkitAuthority          *authority
   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == polkit_authority_check_authorization_async);
 
   result = NULL;
+  real_result = NULL;
 
   local_error = NULL;
   _polkit_authority_check_authorization_finish (authority->real,
diff --git a/src/polkitbackend/polkitbackendlocalauthority.c b/src/polkitbackend/polkitbackendlocalauthority.c
index f677fc3..98e5dd6 100644
--- a/src/polkitbackend/polkitbackendlocalauthority.c
+++ b/src/polkitbackend/polkitbackendlocalauthority.c
@@ -1457,6 +1457,8 @@ get_admin_auth_identities (PolkitBackendLocalAuthority *authority)
 
   priv = POLKIT_BACKEND_LOCAL_AUTHORITY_GET_PRIVATE (authority);
 
+  ret = NULL;
+
   error = NULL;
   admin_identities = polkit_backend_config_source_get_string_list (priv->config_source,
                                                                    "Configuration",
diff --git a/src/programs/Makefile.am b/src/programs/Makefile.am
index 30aae64..abb9f87 100644
--- a/src/programs/Makefile.am
+++ b/src/programs/Makefile.am
@@ -15,18 +15,62 @@ INCLUDES =                                              	\
 	-D_REENTRANT	                                	\
 	$(NULL)
 
-bin_PROGRAMS = polkit-1
+# ----------------------------------------------------------------------------------------------------
+
+bin_PROGRAMS = polkit-1 pkexec
+
+# ----------------------------------------------------------------------------------------------------
 
 polkit_1_SOURCES = polkit.c
 
-polkit_1_CFLAGS =                             			\
-	$(GLIB_CFLAGS)						\
+polkit_1_CFLAGS =                             				\
+	$(GLIB_CFLAGS)							\
+	$(NULL)
+
+polkit_1_LDADD =  	                      				\
+	$(GLIB_LDADD)							\
+	$(top_builddir)/src/polkit/libpolkit-gobject-1.la		\
+	$(NULL)
+
+# ----------------------------------------------------------------------------------------------------
+
+pkexec_SOURCES = pkexec.c
+
+pkexec_CFLAGS =                             				\
+	$(GLIB_CFLAGS)							\
 	$(NULL)
 
-polkit_1_LDADD =  	                      			\
-	$(GLIB_LDADD)						\
-	$(top_builddir)/src/polkit/libpolkit-gobject-1.la	\
+pkexec_LDADD =  	                      				\
+	$(GLIB_LDADD)							\
+	$(top_builddir)/src/polkit/libpolkit-gobject-1.la		\
 	$(NULL)
 
+polkitmodulesdir = $(libdir)/polkit-1/backends
+polkitmodules_LTLIBRARIES = libpolkit-pkexec-action-lookup.la
+
+libpolkit_pkexec_action_lookup_la_SOURCES =                    		\
+	pkexec-action-lookup.c                             		\
+        $(NULL)
+
+libpolkit_pkexec_action_lookup_la_CFLAGS =                      	\
+        -DPOLKIT_BACKEND_I_KNOW_API_IS_SUBJECT_TO_CHANGE    		\
+        -DG_LOG_DOMAIN=\"pkexec-action-lookup\"        			\
+	$(GLIB_CFLAGS)							\
+        $(NULL)
+
+libpolkit_pkexec_action_lookup_la_LDFLAGS =                  		\
+	-export_dynamic -avoid-version -module -no-undefined 		\
+	-export-symbols-regex '^g_io_module_(load|unload)' 		\
+        $(NULL)
+
+libpolkit_pkexec_action_lookup_la_LIBADD =                 		\
+	$(top_builddir)/src/polkitbackend/libpolkit-backend-1.la	\
+        $(NULL)
+
+# ----------------------------------------------------------------------------------------------------
+
 clean-local :
 	rm -f *~
+
+install-exec-hook :
+	-chmod 4755 $(DESTDIR)$(bindir)/pkexec
diff --git a/src/programs/pkexec-action-lookup.c b/src/programs/pkexec-action-lookup.c
new file mode 100644
index 0000000..69b911f
--- /dev/null
+++ b/src/programs/pkexec-action-lookup.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2009 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 at redhat.com>
+ */
+
+#include "config.h"
+
+#include <polkitbackend/polkitbackend.h>
+
+#include <glib/gi18n-lib.h>
+
+#define POLKIT_EXEC_TYPE_ACTION_LOOKUP          (polkit_exec_action_lookup_get_type())
+#define POLKIT_EXEC_ACTION_LOOKUP(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), POLKIT_EXEC_TYPE_ACTION_LOOKUP, PolkitExecActionLookup))
+#define POLKIT_EXEC_ACTION_LOOKUP_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), POLKIT_EXEC_TYPE_ACTION_LOOKUP, PolkitExecActionLookupClass))
+#define POLKIT_EXEC_ACTION_LOOKUP_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), POLKIT_EXEC_TYPE_ACTION_LOOKUP, PolkitExecActionLookupClass))
+#define POLKIT_EXEC_IS_ACTION_LOOKUP(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), POLKIT_EXEC_TYPE_ACTION_LOOKUP))
+#define POLKIT_EXEC_IS_ACTION_LOOKUP_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE ((k), POLKIT_EXEC_TYPE_ACTION_LOOKUP))
+
+typedef struct _PolkitExecActionLookup PolkitExecActionLookup;
+typedef struct _PolkitExecActionLookupClass PolkitExecActionLookupClass;
+
+struct _PolkitExecActionLookup
+{
+  GObject parent;
+};
+
+struct _PolkitExecActionLookupClass
+{
+  GObjectClass parent_class;
+};
+
+GType polkit_exec_action_lookup_get_type (void) G_GNUC_CONST;
+
+static void polkit_backend_action_lookup_iface_init (PolkitBackendActionLookupIface *iface);
+
+#define _G_IMPLEMENT_INTERFACE_DYNAMIC(TYPE_IFACE, iface_init)                                                \
+{                                                                                                             \
+  const GInterfaceInfo g_implement_interface_info = {                   \
+    (GInterfaceInitFunc) iface_init, NULL, NULL                         \
+  };                                                                    \
+  g_type_module_add_interface (type_module, g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \
+}
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (PolkitExecActionLookup,
+                                polkit_exec_action_lookup,
+                                G_TYPE_OBJECT,
+                                0,
+                                _G_IMPLEMENT_INTERFACE_DYNAMIC (POLKIT_BACKEND_TYPE_ACTION_LOOKUP,
+                                                                polkit_backend_action_lookup_iface_init))
+
+static void
+polkit_exec_action_lookup_init (PolkitExecActionLookup *lookup)
+{
+}
+
+static void
+polkit_exec_action_lookup_class_finalize (PolkitExecActionLookupClass *klass)
+{
+}
+
+static void
+polkit_exec_action_lookup_class_init (PolkitExecActionLookupClass *klass)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+polkit_exec_action_lookup_get_message   (PolkitBackendActionLookup *lookup,
+                                         const gchar               *action_id,
+                                         GHashTable                *details,
+                                         PolkitActionDescription   *action_description)
+{
+  gchar *ret;
+  const gchar *s;
+  const gchar *s2;
+
+  ret = NULL;
+
+  if (g_strcmp0 (action_id, "org.freedesktop.policykit.exec") != 0)
+    goto out;
+
+  s = g_hash_table_lookup (details, "program");
+  if (s == NULL)
+    goto out;
+
+  s2 = g_hash_table_lookup (details, "uid");
+  if (s2 == NULL)
+    goto out;
+
+  if (g_strcmp0 (s2, "0") == 0)
+    {
+      /* Translator: %s is a fully qualified path to the executable */
+      ret = g_strdup_printf (_("Authentication is needed to run `%s' as the super user"), s);
+    }
+  else
+    {
+      /* Translator: %s is a fully qualified path to the executable */
+      ret = g_strdup_printf (_("Authentication is needed to run `%s' as another user"), s);
+    }
+
+ out:
+  return ret;
+}
+
+static gchar *
+polkit_exec_action_lookup_get_icon_name (PolkitBackendActionLookup *lookup,
+                                         const gchar               *action_id,
+                                         GHashTable                *details,
+                                         PolkitActionDescription   *action_description)
+{
+  gchar *ret;
+
+  ret = NULL;
+
+  /* explicitly left blank for now */
+
+  return ret;
+}
+
+static GHashTable *
+polkit_exec_action_lookup_get_details   (PolkitBackendActionLookup *lookup,
+                                          const gchar               *action_id,
+                                          GHashTable                *details,
+                                          PolkitActionDescription   *action_desc)
+{
+  const gchar *s;
+  const gchar *s2;
+  GHashTable *ret;
+
+  ret = NULL;
+
+  if (action_desc != NULL &&
+      polkit_action_description_get_annotation (action_desc, "org.freedesktop.policykit.exec.path") == NULL)
+    goto out;
+
+  ret = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+  s = g_hash_table_lookup (details, "command-line");
+  if (s != NULL)
+    {
+      g_hash_table_insert (ret,
+                           _("Command"),
+                           g_strdup (s));
+    }
+
+  s = g_hash_table_lookup (details, "user");
+  s2 = g_hash_table_lookup (details, "uid");
+  if (s != NULL)
+    {
+      if (g_strcmp0 (s2, "0") == 0)
+        s = _("Super User (root)");
+      g_hash_table_insert (ret,
+                           _("Run As"),
+                           g_strdup (s));
+    }
+
+ out:
+  return ret;
+}
+
+static void
+polkit_backend_action_lookup_iface_init (PolkitBackendActionLookupIface *iface)
+{
+  iface->get_message   = polkit_exec_action_lookup_get_message;
+  iface->get_icon_name = polkit_exec_action_lookup_get_icon_name;
+  iface->get_details   = polkit_exec_action_lookup_get_details;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+void
+g_io_module_load (GIOModule *module)
+{
+  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+  polkit_exec_action_lookup_register_type (G_TYPE_MODULE (module));
+
+  g_io_extension_point_implement (POLKIT_BACKEND_ACTION_LOOKUP_EXTENSION_POINT_NAME,
+                                  POLKIT_EXEC_TYPE_ACTION_LOOKUP,
+                                  "pkexec action lookup extension " PACKAGE_VERSION,
+                                  0);
+}
+
+void
+g_io_module_unload (GIOModule *module)
+{
+}
diff --git a/src/programs/pkexec.c b/src/programs/pkexec.c
new file mode 100644
index 0000000..86f70a5
--- /dev/null
+++ b/src/programs/pkexec.c
@@ -0,0 +1,473 @@
+/*
+ * 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 at redhat.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
+#include <errno.h>
+
+#include <polkit/polkit.h>
+
+static void
+usage (int argc, char *argv[])
+{
+  GError *error;
+
+  error = NULL;
+  if (!g_spawn_command_line_sync ("man pkexec",
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  &error))
+    {
+      g_printerr ("Cannot show manual page: %s\n", error->message);
+      g_error_free (error);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+find_action_for_path (PolkitAuthority *authority,
+                      const gchar     *path)
+{
+  GList *l;
+  GList *actions;
+  gchar *action_id;
+  GError *error;
+
+  actions = NULL;
+  action_id = NULL;
+  error = NULL;
+
+  actions = polkit_authority_enumerate_actions_sync (authority,
+                                                     NULL,
+                                                     &error);
+  if (actions == NULL)
+    {
+      g_warning ("Error enumerating actions: %s", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  for (l = actions; l != NULL; l = l->next)
+    {
+      PolkitActionDescription *action_desc = POLKIT_ACTION_DESCRIPTION (l->data);
+      const gchar *path_for_action;
+
+      path_for_action = polkit_action_description_get_annotation (action_desc, "org.freedesktop.policykit.exec.path");
+      if (path_for_action == NULL)
+        continue;
+
+      if (g_strcmp0 (path_for_action, path) == 0)
+        {
+          action_id = g_strdup (polkit_action_description_get_action_id (action_desc));
+          goto out;
+        }
+    }
+
+ out:
+  g_list_foreach (actions, (GFunc) g_object_unref, NULL);
+  g_list_free (actions);
+
+  /* Fall back to org.freedesktop.policykit.exec */
+
+  if (action_id == NULL)
+    action_id = g_strdup ("org.freedesktop.policykit.exec");
+
+  return action_id;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  guint n;
+  guint ret;
+  gboolean opt_show_help;
+  gboolean opt_show_version;
+  PolkitAuthority *authority;
+  PolkitAuthorizationResult *result;
+  PolkitSubject *subject;
+  GHashTable *details;
+  GError *error;
+  gchar *action_id;
+  gchar *command_line;
+  gchar **exec_argv;
+  gchar *path;
+  struct passwd pwstruct;
+  struct passwd *pw;
+  gchar pwbuf[8192];
+  gchar *s;
+  const gchar *environment_variables_to_save[] = {
+    "LANG"
+    "LANGUAGE",
+    "LC_ALL",
+    "LC_MESSAGES",
+    "SHELL",
+    "TERM",
+
+    /* For now, avoiding pretend that running X11 apps as another user in the same session
+     * will ever work... See
+     *
+     *  https://bugs.freedesktop.org/show_bug.cgi?id=17970#c26
+     *
+     * and surrounding comments for a lot of discussion about this.
+     */
+#if 0
+    "DESKTOP_STARTUP_ID",
+    "DISPLAY",
+    "XAUTHORITY",
+    "DBUS_SESSION_BUS_ADDRESS",
+    "ORBIT_SOCKETDIR",
+#endif
+    NULL
+  };
+  GPtrArray *saved_env;
+  gchar *opt_user;
+  pid_t pid_of_caller;
+  struct stat statbuf;
+  gchar procbuf[32];
+
+  ret = 127;
+  authority = NULL;
+  subject = NULL;
+  details = NULL;
+  result = NULL;
+  action_id = NULL;
+  saved_env = NULL;
+  path = NULL;
+  command_line = NULL;
+  opt_user = NULL;
+
+  /* check for correct invocation */
+  if (geteuid () != 0)
+    {
+      g_print ("pkexec must be setuid root\n");
+      goto out;
+    }
+
+  /* First process options and find the command-line to invoke. Avoid using fancy library routines
+   * that depend on environtment variables since we haven't cleared the environment just yet.
+   */
+  opt_show_help = FALSE;
+  opt_show_version = FALSE;
+  for (n = 1; n < (guint) argc; n++)
+    {
+      if (strcmp (argv[n], "--help") == 0)
+        {
+          opt_show_help = TRUE;
+        }
+      else if (strcmp (argv[n], "--version") == 0)
+        {
+          opt_show_version = TRUE;
+        }
+      else if (strcmp (argv[n], "--user") == 0 || strcmp (argv[n], "-u") == 0)
+        {
+          n++;
+          if (n >= (guint) argc)
+            {
+              usage (argc, argv);
+              goto out;
+            }
+
+          opt_user = g_strdup (argv[n]);
+        }
+      else
+        {
+          break;
+        }
+    }
+
+  if (opt_show_help)
+    {
+      usage (argc, argv);
+      ret = 0;
+      goto out;
+    }
+  else if (opt_show_version)
+    {
+      g_print ("pkexec version %s\n", PACKAGE_VERSION);
+      ret = 0;
+      goto out;
+    }
+
+  if (opt_user == NULL)
+    opt_user = g_strdup ("root");
+
+  /* Now figure out the command-line to run - argv is guaranteed to be NULL-terminated, see
+   *
+   *  http://lkml.indiana.edu/hypermail/linux/kernel/0409.2/0287.html
+   *
+   * but do check this is the case.
+   *
+   * We also try to locate the program in the path if a non-absolute path is given.
+   */
+  g_assert (argv[argc] == NULL);
+  path = g_strdup (argv[n]);
+  if (path == NULL)
+    {
+      usage (argc, argv);
+      goto out;
+    }
+  if (path[0] != '/')
+    {
+      /* g_find_program_in_path() is not suspectible to attacks via the environment */
+      s = g_find_program_in_path (path);
+      if (s == NULL)
+        {
+          g_printerr ("Cannot run program %s: %s\n", path, strerror (ENOENT));
+          goto out;
+        }
+      g_free (path);
+      argv[n] = path = s;
+    }
+  if (stat (path, &statbuf) != 0)
+    {
+      g_printerr ("Error getting information about %s: %m\n", path);
+      goto out;
+    }
+  command_line = g_strjoinv (" ", argv + n);
+  exec_argv = argv + n;
+
+  /* now save the environment variables we care about */
+  saved_env = g_ptr_array_new ();
+  for (n = 0; environment_variables_to_save[n] != NULL; n++)
+    {
+      const gchar *key = environment_variables_to_save[n];
+      const gchar *value;
+
+      value = g_getenv (key);
+      if (value == NULL)
+        continue;
+
+      g_ptr_array_add (saved_env, g_strdup (key));
+      g_ptr_array_add (saved_env, g_strdup (value));
+    }
+
+  /* Nuke the environment to get a well-known and sanitized environment to avoid attacks
+   * via e.g. the DBUS_SYSTEM_BUS_ADDRESS environment variable and similar.
+   */
+  if (clearenv () != 0)
+    {
+      g_printerr ("Error clearing environment: %m\n");
+      goto out;
+    }
+
+  /* Look up information about the user we care about */
+  if (getpwnam_r (opt_user, &pwstruct, pwbuf, sizeof pwbuf, &pw) != 0)
+    {
+      g_printerr ("Error getting information for user %s: %m\n", opt_user);
+      goto out;
+    }
+
+  /* Initialize the GLib type system - this is needed to interact with the
+   * PolicyKit daemon
+   */
+  g_type_init ();
+
+  /* now check if the program that invoked us is authorized */
+  pid_of_caller = getppid ();
+  if (pid_of_caller == 1)
+    {
+      /* getppid() can return 1 if the parent died (meaning that we are reaped
+       * by /sbin/init); get process group leader instead - for example, this
+       * happens when launching via gnome-panel (alt+f2, then 'pkexec gedit').
+       */
+      pid_of_caller = getpgrp ();
+    }
+
+  /* paranoia: check that the uid of pid_of_caller matches getuid() */
+  g_snprintf (procbuf, sizeof procbuf, "/proc/%d", pid_of_caller);
+  if (stat (procbuf, &statbuf) != 0)
+    {
+      g_printerr ("Error determing pid of caller (pid %d): %m\n", (gint) pid_of_caller);
+      goto out;
+    }
+  if (statbuf.st_uid != getuid ())
+    {
+      g_printerr ("User of caller (%d) does not match our uid (%d)\n", statbuf.st_uid, getuid ());
+      goto out;
+    }
+
+  authority = polkit_authority_get ();
+  subject = polkit_unix_process_new (pid_of_caller);
+
+  details = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+  g_hash_table_insert (details, "command-line", g_strdup (command_line));
+  s = g_strdup_printf ("%s (%s)", pw->pw_gecos, pw->pw_name);
+  g_hash_table_insert (details, "user", s);
+  s = g_strdup_printf ("%d", (gint) pw->pw_uid);
+  g_hash_table_insert (details, "uid", s);
+  g_hash_table_insert (details, "program", g_strdup (path));
+
+  action_id = find_action_for_path (authority, path);
+  g_assert (action_id != NULL);
+
+  error = NULL;
+  result = polkit_authority_check_authorization_sync (authority,
+                                                      subject,
+                                                      action_id,
+                                                      details,
+                                                      POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
+                                                      NULL,
+                                                      &error);
+  if (result == NULL)
+    {
+      g_printerr ("Error checking for authorization %s: %s\n",
+                  action_id,
+                  error->message);
+      goto out;
+    }
+
+  if (polkit_authorization_result_get_is_authorized (result))
+    {
+      /* do nothing */
+    }
+  else if (polkit_authorization_result_get_is_challenge (result))
+    {
+      g_printerr ("Authorization requires authentication but no authentication was found.\n");
+      goto out;
+    }
+  else
+    {
+      g_printerr ("Not authorized.\n");
+      goto out;
+    }
+
+  /* Set PATH to a safe list */
+  g_ptr_array_add (saved_env, g_strdup ("PATH"));
+  if (pw->pw_uid != 0)
+    s = g_strdup_printf ("/usr/bin:/bin:/usr/sbin:/sbin:%s/bin", pw->pw_dir);
+  else
+    s = g_strdup_printf ("/usr/sbin:/usr/bin:/sbin:/bin:%s/bin", pw->pw_dir);
+  g_ptr_array_add (saved_env, s);
+  g_ptr_array_add (saved_env, g_strdup ("LOGNAME"));
+  g_ptr_array_add (saved_env, g_strdup (pw->pw_name));
+  g_ptr_array_add (saved_env, g_strdup ("USER"));
+  g_ptr_array_add (saved_env, g_strdup (pw->pw_name));
+  g_ptr_array_add (saved_env, g_strdup ("HOME"));
+  g_ptr_array_add (saved_env, g_strdup (pw->pw_dir));
+
+  s = g_strdup_printf ("%d", getuid ());
+  g_ptr_array_add (saved_env, g_strdup ("PKEXEC_UID"));
+  g_ptr_array_add (saved_env, s);
+
+  /* set the environment */
+  for (n = 0; n < saved_env->len - 1; n += 2)
+    {
+      const gchar *key = saved_env->pdata[n];
+      const gchar *value = saved_env->pdata[n + 1];
+
+      if (!g_setenv (key, value, TRUE))
+        {
+          g_printerr ("Error setting environment variable %s to '%s': %m\n",
+                      key,
+                      value);
+          goto out;
+        }
+    }
+
+  /* if not changing to uid 0, become uid 0 before changing to the user */
+  if (pw->pw_uid)
+    {
+      setreuid (0, 0);
+      if ((geteuid () != 0) || (getuid () != 0))
+        {
+          g_printerr ("Error becoming uid 0: %m\n");
+          goto out;
+        }
+    }
+
+  /* become the user */
+  if (setgroups (0, NULL) != 0)
+    {
+      g_printerr ("Error setting groups: %m\n");
+      goto out;
+    }
+  if (initgroups (pw->pw_name, pw->pw_gid) != 0)
+    {
+      g_printerr ("Error initializing groups for %s: %m\n", pw->pw_name);
+      goto out;
+    }
+  setregid (pw->pw_gid, pw->pw_gid);
+  setreuid (pw->pw_uid, pw->pw_uid);
+  if ((geteuid () != pw->pw_uid) || (getuid () != pw->pw_uid) ||
+      (getegid () != pw->pw_gid) || (getgid () != pw->pw_gid))
+    {
+      g_printerr ("Error becoming real+effective uid %d and gid %d: %m\n", pw->pw_uid, pw->pw_gid);
+      goto out;
+    }
+
+  /* change to home directory */
+  if (chdir (pw->pw_dir) != 0)
+    {
+      g_printerr ("Error changing to home directory %s: %m\n", pw->pw_dir);
+      goto out;
+    }
+
+  /* exec the program */
+  if (execv (path, exec_argv) != 0)
+    {
+      g_printerr ("Error executing %s: %m\n", path);
+      goto out;
+    }
+
+  /* if exec doesn't fail, it never returns... */
+  g_assert_not_reached ();
+
+ out:
+  if (result != NULL)
+    g_object_unref (result);
+
+  g_free (action_id);
+
+  if (details != NULL)
+    g_hash_table_unref (details);
+
+  if (subject != NULL)
+    g_object_unref (subject);
+
+  if (authority != NULL)
+    g_object_unref (authority);
+
+  if (saved_env != NULL)
+    {
+      g_ptr_array_foreach (saved_env, (GFunc) g_free, NULL);
+      g_ptr_array_free (saved_env, TRUE);
+    }
+
+  g_free (path);
+  g_free (command_line);
+  g_free (opt_user);
+
+  return ret;
+}
+


More information about the hal-commit mailing list