summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <david@fubar.dk>2006-03-14 06:14:33 +0000
committerDavid Zeuthen <david@fubar.dk>2006-03-14 06:14:33 +0000
commit96f6daa63d428d9a16d8564b83f33b71e1cd41ca (patch)
tree6a8ec6e8928e65f5defec45ec169cdf4f6da9018
parent4f567cd7eef1cb7fcd5777a0ba2b6df03e5ea88c (diff)
downloadpolkit-96f6daa63d428d9a16d8564b83f33b71e1cd41ca.tar.gz
Add a bunch of code; basically a full rewrite moving all queries to the
daemon.
-rw-r--r--COPYING4
-rw-r--r--ChangeLog75
-rw-r--r--Makefile.am7
-rw-r--r--configure.in156
-rw-r--r--doc/api/tmpl/libpolkit.sgml304
-rw-r--r--libpolkit/Makefile.am16
-rw-r--r--libpolkit/libpolkit.c833
-rw-r--r--libpolkit/libpolkit.h122
-rw-r--r--policy-kit.in8
-rw-r--r--polkit-interface-manager.xml36
-rw-r--r--polkit-interface-session.xml51
-rw-r--r--polkit.pc.in2
-rw-r--r--polkitd/Makefile.am94
-rwxr-xr-xpolkitd/debug-polkitd.sh9
-rw-r--r--polkitd/main.c229
-rw-r--r--polkitd/policy.c765
-rw-r--r--polkitd/policy.h76
-rw-r--r--polkitd/polkit-manager.c720
-rw-r--r--polkitd/polkit-manager.h120
-rw-r--r--polkitd/polkit-marshal.list1
-rw-r--r--polkitd/polkit-session.c1003
-rw-r--r--polkitd/polkit-session.h123
-rw-r--r--polkitd/polkitd-test.c (renamed from libpolkit/libpolkit-test.c)42
-rwxr-xr-xpolkitd/run-polkitd.sh7
-rwxr-xr-xpolkitd/valgrind-polkitd.sh4
-rw-r--r--privileges/Makefile.am7
-rw-r--r--privileges/desktop-console.privilege4
-rw-r--r--tools/Makefile.am31
-rw-r--r--tools/Makefile.in76
-rw-r--r--tools/polkit-grant-privilege.c434
-rw-r--r--tools/polkit-is-privileged.c102
-rw-r--r--tools/polkit-list-privileges.c183
32 files changed, 4451 insertions, 1193 deletions
diff --git a/COPYING b/COPYING
index df24a2f..5ca1af9 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,9 @@
+The PolicyKit daemon and associated command-line tools polkit-* is
+licensed to you under the GNU General Public License version 2.
+
libpolkit is licensed to you under your choice of the Academic Free
License version 2.1, or the GNU General Public License version 2.
+
Both licenses are included here. Some individual source code files
and/or binaries may be under the GPL only or under the LGPG.
diff --git a/ChangeLog b/ChangeLog
index 8c01b34..6e75355 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,78 @@
+2006-03-14 David Zeuthen <davidz@redhat.com>
+
+ Add a bunch of code; basically a full rewrite moving all queries
+ to the daemon.
+
+ * COPYING:
+ * Makefile.am:
+ * configure.in:
+ * libpolkit/Makefile.am:
+ * libpolkit/libpolkit-test.c:
+ * libpolkit/libpolkit.c: (libpolkit_new_context),
+ (libpolkit_free_context),
+ (libpolkit_get_allowed_resources_for_privilege_for_uid),
+ (libpolkit_is_uid_allowed_for_privilege),
+ (libpolkit_get_privilege_list):
+ * libpolkit/libpolkit.h:
+ * policy-kit.in:
+ * polkit-interface-manager.xml:
+ * polkit-interface-session.xml:
+ * polkit.pc.in:
+ * polkitd/Makefile.am:
+ * polkitd/debug-polkitd.sh:
+ * polkitd/main.c: (usage), (delete_pid), (main):
+ * polkitd/policy.c: (policy_util_set_policy_directory),
+ (policy_element_new), (policy_element_free),
+ (policy_element_free_list), (policy_element_dump),
+ (txt_backend_read_policy), (policy_get_whitelist),
+ (policy_get_blacklist), (policy_get_policies), (afp_process_elem),
+ (policy_get_allowed_resources_for_policy_for_uid_gid),
+ (policy_is_uid_gid_allowed_for_policy), (policy_util_uid_to_name),
+ (policy_util_gid_to_name), (policy_util_name_to_uid),
+ (policy_util_name_to_gid),
+ (policy_get_allowed_resources_for_policy_for_uid),
+ (policy_is_uid_allowed_for_policy), (getgrouplist):
+ * polkitd/policy.h:
+ * polkitd/polkit-manager.c: (caller_info_delete),
+ (polkit_manager_init), (polkit_manager_finalize),
+ (polkit_manager_class_init), (polkit_manager_error_quark),
+ (polkit_manager_error_get_type), (bus_name_owner_changed),
+ (session_remover), (session_finalized), (polkit_manager_new),
+ (uid_from_username), (safe_strcmp),
+ (polkit_manager_get_caller_info),
+ (polkit_manager_initiate_privilege_grant),
+ (polkit_manager_is_user_privileged),
+ (polkit_manager_get_allowed_resources_for_privilege),
+ (polkit_manager_list_privileges),
+ (polkit_manager_add_temporary_privilege),
+ (polkit_manager_remove_temporary_privilege):
+ * polkitd/polkit-manager.h:
+ * polkitd/polkit-marshal.list:
+ * polkitd/polkit-session.c: (polkit_session_init),
+ (polkit_session_finalize), (polkit_session_class_init),
+ (polkit_session_error_quark), (polkit_session_error_get_type),
+ (polkit_session_check_caller), (polkit_session_is_authenticated),
+ (polkit_session_get_auth_denied_reason), (safe_memset),
+ (my_conversation), (write_back_to_parent), (do_pam_auth),
+ (data_from_pam), (polkit_session_get_auth_details),
+ (polkit_session_initiate_auth), (polkit_session_get_questions),
+ (polkit_session_provide_answers), (polkit_session_close),
+ (polkit_session_grant_privilege_temporarily), (polkit_session_new),
+ (polkit_session_initiator_disconnected):
+ * polkitd/polkit-session.h:
+ * polkitd/polkitd-test.c: (my_exit), (do_check),
+ (write_test_policy), (do_read_tests), (main):
+ * polkitd/run-polkitd.sh:
+ * polkitd/valgrind-polkitd.sh:
+ * privileges/Makefile.am:
+ * privileges/desktop-console.privilege:
+ * tools/Makefile.am:
+ * tools/Makefile.in:
+ * tools/polkit-grant-privilege.c: (have_questions_handler),
+ (auth_done_handler), (do_grant_privilege), (usage), (main):
+ * tools/polkit-is-privileged.c: (usage), (main):
+ * tools/polkit-list-privileges.c: (usage), (main):
+
2006-03-09 David Zeuthen <davidz@redhat.com>
* polkit.pc.in (exec_prefix): Use right Cflags
diff --git a/Makefile.am b/Makefile.am
index d0478bd..3252cdd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,13 +1,16 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = libpolkit doc tools
+SUBDIRS = libpolkit polkitd doc tools privileges
+
+pamdir = $(sysconfdir)/pam.d
+pam_DATA = policy-kit
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = polkit.pc
DISTCLEANFILES = polkit.pc
-EXTRA_DIST = HACKING polkit.pc.in mkinstalldirs
+EXTRA_DIST = HACKING polkit-interface-manager.xml polkit-interface-session.xml polkit.pc.in policy-kit.in mkinstalldirs
clean-local :
rm -f *~
diff --git a/configure.in b/configure.in
index ecb3cb5..c11637e 100644
--- a/configure.in
+++ b/configure.in
@@ -26,16 +26,16 @@ AC_PROG_MAKE_SET
AC_PROG_LN_S
AC_SYS_LARGEFILE
-AC_ARG_WITH(polkit_user,[ --with-polkit-user=<user> User for PolicyKit])
+AC_ARG_WITH(polkit_user,[ --with-polkit-user=<user> user for PolicyKit])
if test -z "$with_polkit_user" ; then
POLKIT_USER=polkit
else
POLKIT_USER=$with_polkit_user
fi
AC_SUBST(POLKIT_USER)
-AC_DEFINE_UNQUOTED(POLKIT_USER,"POLKIT_USER", [User for PolicyKit])
+AC_DEFINE_UNQUOTED(POLKIT_USER, "$POLKIT_USER", [User for PolicyKit])
-AC_ARG_WITH(polkit_group,[ --with-hal-group=<grp> Group for PolicyKit])
+AC_ARG_WITH(polkit_group,[ --with-polkit-group=<grp> group for PolicyKit])
if test -z "$with_polkit_group" ; then
POLKIT_GROUP=polkit
else
@@ -137,6 +137,14 @@ PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.6.0])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
+PKG_CHECK_MODULES(DBUS, [dbus-1 >= 0.60])
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+
+PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.60])
+AC_SUBST(DBUS_GLIB_CFLAGS)
+AC_SUBST(DBUS_GLIB_LIBS)
+
AC_CHECK_FUNCS(getgrouplist)
AS_AC_EXPAND(LOCALSTATEDIR, $localstatedir)
@@ -148,7 +156,7 @@ AS_AC_EXPAND(LIBDIR, $libdir)
AS_AC_EXPAND(LIBEXECDIR, $libexecdir)
# documentation target
-AC_ARG_WITH(doc-dir, [ --with-doc-dir=[dirname] directory to install documentation])
+AC_ARG_WITH(doc-dir, [ --with-doc-dir=[dirname] directory to install documentation])
if ! test -z "$with_doc_dir"; then
DOCDIR=$with_doc_dir
else
@@ -157,13 +165,137 @@ fi
AC_SUBST(DOCDIR)
+# PAM stuff borrowed from gnome-screensaver
+
+# Determine PAM prefix
+
+withval=""
+AC_ARG_WITH(pam-prefix,
+[ --with-pam-prefix=<prefix> specify where pam files go],[
+if test x$withval != x; then
+ AC_MSG_RESULT("PAM files will be installed in prefix ${withval}.")
+fi])
+if test x$withval != x; then
+ PAM_PREFIX_UNEXPANDED="$withval"
+else
+ PAM_PREFIX_UNEXPANDED="$sysconfdir"
+fi
+PAM_PREFIX=`eval echo $PAM_PREFIX_UNEXPANDED`
+AC_SUBST(PAM_PREFIX)
+
+
+dnl ---------------------------------------------------------------------------
+dnl - Check for PAM
+dnl ---------------------------------------------------------------------------
+
+have_pam=no
+AC_CHECK_LIB(pam, pam_start, have_pam=yes)
+if test "x$have_pam" = "xyes"; then
+ AUTH_LIBS="${AUTH_LIBS} -lpam"
+ AC_DEFINE(HAVE_PAM, 1, [Define if PAM support is included])
+
+ # On Linux, sigtimedwait() is in libc; on Solaris, it's in librt.
+ have_timedwait=no
+ AC_CHECK_LIB(c, sigtimedwait, [have_timedwait=yes])
+ if test "$have_timedwait" = no ; then
+ AC_CHECK_LIB(rt, sigtimedwait, [AUTH_LIBS="${AUTH_LIBS} -lrt"])
+ fi
+
+ AC_MSG_CHECKING(how to call pam_strerror)
+ AC_CACHE_VAL(ac_cv_pam_strerror_args,
+ [AC_TRY_COMPILE([#include <stdio.h>
+ #include <stdlib.h>
+ #include <security/pam_appl.h>],
+ [pam_handle_t *pamh = 0;
+ char *s = pam_strerror(pamh, PAM_SUCCESS);],
+ [ac_pam_strerror_args=2],
+ [AC_TRY_COMPILE([#include <stdio.h>
+ #include <stdlib.h>
+ #include <security/pam_appl.h>],
+ [char *s =
+ pam_strerror(PAM_SUCCESS);],
+ [ac_pam_strerror_args=1],
+ [ac_pam_strerror_args=0])])
+ ac_cv_pam_strerror_args=$ac_pam_strerror_args])
+ ac_pam_strerror_args=$ac_cv_pam_strerror_args
+ if test "$ac_pam_strerror_args" = 1 ; then
+ AC_MSG_RESULT(one argument)
+ elif test "$ac_pam_strerror_args" = 2 ; then
+ AC_DEFINE(PAM_STRERROR_TWO_ARGS, 1, [Define if pam_strerror takes two arguments])
+ AC_MSG_RESULT(two arguments)
+ else
+ AC_MSG_RESULT(unknown)
+ fi
+
+fi
+AM_CONDITIONAL(HAVE_PAM, test x$have_pam = xyes)
+AC_SUBST(HAVE_PAM)
+AC_SUBST(AUTH_LIBS)
+
+
+AC_ARG_WITH(os-type, [ --with-os-type=<os> distribution or OS (redhat)])
+
+#### Check our operating system (distro-tweaks required)
+operating_system=unknown
+if test -f /etc/redhat-release || test -f SYSCONFDIR/redhat-release ; then
+ operating_system=redhat
+fi
+
+#### Sort out OS (distro-tweaks required)
+
+if test x$with_os_type = x; then
+ if test x$operating_system = xredhat ; then
+ with_os_type=redhat
+ else
+ with_os_type=unknown
+ fi
+fi
+
+# (distro-tweaks required)
+AM_CONDITIONAL(OS_TYPE_UNKNOWN, test x$with_os_type = xunknown, [Running on unknown OS])
+AM_CONDITIONAL(OS_TYPE_RED_HAT, test x$with_os_type = xredhat, [Running on Red Hat OS'es])
+
+AC_ARG_WITH(pid-file, [ --with-pid-file=<file> pid file for polkitd])
+
+#### Set up the pid file (distro-tweaks required)
+if ! test -z "$with_pid_file"; then
+ POLKITD_PID_FILE=$with_pid_file
+elif test x$with_os_type = xredhat ; then
+ POLKITD_PID_FILE=${LOCALSTATEDIR}/run/polkitd.pid
+else
+ POLKITD_PID_FILE=${LOCALSTATEDIR}/run/polkitd/pid
+fi
+
+AC_SUBST(POLKITD_PID_FILE)
+AC_DEFINE_UNQUOTED(POLKITD_PID_FILE, "$POLKITD_PID_FILE", [pid file])
+
+AC_ARG_WITH(pam-include, [ --with-pam-include=<file> pam file to include])
+
+#### Set up pam file to include (distro-tweaks required)
+if ! test -z "$with_pam_include"; then
+ PAM_FILE_INCLUDE=$with_pam_include
+elif test x$with_os_type = xredhat ; then
+ PAM_FILE_INCLUDE=system-auth
+else
+ PAM_FILE_INCLUDE=system-auth
+fi
+
+AC_SUBST(PAM_FILE_INCLUDE)
+AC_DEFINE_UNQUOTED(PAM_FILE_INCLUDE, "$PAM_FILE_INCLUDE", [pam file to include])
+
+
AC_OUTPUT([
+policy-kit
polkit.pc
Makefile
+polkitd/Makefile
+polkitd/PolicyKit
+polkitd/PolicyKit.conf
libpolkit/Makefile
tools/Makefile
doc/Makefile
doc/api/Makefile
+privileges/Makefile
])
dnl ==========================================================================
@@ -180,18 +312,30 @@ echo "
sysconfdir: ${SYSCONFDIR}
localstatedir: ${LOCALSTATEDIR}
docdir: ${DOCDIR}
+ PAM prefix: ${PAM_PREFIX}
compiler: ${CC}
cflags: ${CFLAGS}
cppflags: ${CPPFLAGS}
- User for PolicyKit: ${POLKIT_USER}
- Group for PolicyKit: ${POLKIT_GROUP}
+ user for PolicyKit: ${POLKIT_USER}
+ group for PolicyKit: ${POLKIT_GROUP}
+ pidfile for polkitd: ${POLKITD_PID_FILE}
+
+ PAM support: ${have_pam}
+ PAM file to include: ${PAM_FILE_INCLUDE}
Maintainer mode: ${USE_MAINTAINER_MODE}
Building verbose mode: ${enable_verbose_mode}
Building api docs: ${enable_gtk_doc}
"
+# (distro-tweaks required)
+if test x$with_os_type = xredhat; then
+ echo "NOTE: Red Hat style init scripts and pam file will be installed"
+else
+ echo "NOTE: You have to install init scripts yourself and tweak your own pam file"
+fi
+echo
echo "NOTE: Remember to create user ${POLKIT_USER} and group ${POLKIT_GROUP} before make install"
echo
diff --git a/doc/api/tmpl/libpolkit.sgml b/doc/api/tmpl/libpolkit.sgml
index 55a239a..1939dc3 100644
--- a/doc/api/tmpl/libpolkit.sgml
+++ b/doc/api/tmpl/libpolkit.sgml
@@ -9,11 +9,13 @@ libpolkit
</para>
+
<!-- ##### SECTION See_Also ##### -->
<para>
</para>
+
<!-- ##### SECTION Stability_Level ##### -->
@@ -25,8 +27,9 @@ libpolkit
@LIBPOLKIT_RESULT_OK:
@LIBPOLKIT_RESULT_ERROR:
@LIBPOLKIT_RESULT_INVALID_CONTEXT:
-@LIBPOLKIT_RESULT_PERMISSON_DENIED:
-@LIBPOLKIT_RESULT_NO_SUCH_POLICY:
+@LIBPOLKIT_RESULT_NOT_PRIVILEGED:
+@LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE:
+@LIBPOLKIT_RESULT_NO_SUCH_USER:
<!-- ##### STRUCT LibPolKitContext_s ##### -->
<para>
@@ -40,41 +43,12 @@ libpolkit
</para>
-<!-- ##### ENUM LibPolKitElementType ##### -->
-<para>
-
-</para>
-
-@LIBPOLKIT_ELEMENT_TYPE_UID:
-@LIBPOLKIT_ELEMENT_TYPE_GID:
-
-<!-- ##### STRUCT LibPolKitElement_s ##### -->
-<para>
-
-</para>
-
-
-<!-- ##### TYPEDEF LibPolKitElement ##### -->
-<para>
-
-</para>
-
-
<!-- ##### FUNCTION libpolkit_new_context ##### -->
<para>
</para>
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_context_set_txt_source ##### -->
-<para>
-
-</para>
-
-@ctx:
-@directory:
+@connection:
@Returns:
@@ -87,269 +61,3 @@ libpolkit
@Returns:
-<!-- ##### FUNCTION libpolkit_get_policies ##### -->
-<para>
-
-</para>
-
-@ctx:
-@result:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_is_uid_allowed_for_policy ##### -->
-<para>
-
-</para>
-
-@ctx:
-@uid:
-@policy:
-@resource:
-@result:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_is_uid_gid_allowed_for_policy ##### -->
-<para>
-
-</para>
-
-@ctx:
-@uid:
-@num_gids:
-@gid_list:
-@policy:
-@resource:
-@result:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_get_whitelist ##### -->
-<para>
-
-</para>
-
-@ctx:
-@policy:
-@result:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_get_blacklist ##### -->
-<para>
-
-</para>
-
-@ctx:
-@policy:
-@result:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_set_whitelist ##### -->
-<para>
-
-</para>
-
-@ctx:
-@policy:
-@whitelist:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_set_blacklist ##### -->
-<para>
-
-</para>
-
-@ctx:
-@policy:
-@blacklist:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_type ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_include_all ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_exclude_all ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_uid ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_gid ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_get_resource ##### -->
-<para>
-
-</para>
-
-@elem:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_new ##### -->
-<para>
-
-</para>
-
-@ctx:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_type ##### -->
-<para>
-
-</para>
-
-@elem:
-@type:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_include_all ##### -->
-<para>
-
-</para>
-
-@elem:
-@value:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_exclude_all ##### -->
-<para>
-
-</para>
-
-@elem:
-@value:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_uid ##### -->
-<para>
-
-</para>
-
-@elem:
-@uid:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_gid ##### -->
-<para>
-
-</para>
-
-@elem:
-@gid:
-
-
-<!-- ##### FUNCTION libpolkit_element_set_resource ##### -->
-<para>
-
-</para>
-
-@elem:
-@resource:
-
-
-<!-- ##### FUNCTION libpolkit_free_element ##### -->
-<para>
-
-</para>
-
-@elem:
-
-
-<!-- ##### FUNCTION libpolkit_free_element_list ##### -->
-<para>
-
-</para>
-
-@policy_element_list:
-
-
-<!-- ##### FUNCTION libpolkit_util_uid_to_name ##### -->
-<para>
-
-</para>
-
-@ctx:
-@uid:
-@default_gid:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_util_gid_to_name ##### -->
-<para>
-
-</para>
-
-@ctx:
-@gid:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_util_name_to_uid ##### -->
-<para>
-
-</para>
-
-@ctx:
-@username:
-@default_gid:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_util_name_to_gid ##### -->
-<para>
-
-</para>
-
-@ctx:
-@groupname:
-@Returns:
-
-
-<!-- ##### FUNCTION libpolkit_element_dump ##### -->
-<para>
-
-</para>
-
-@elem:
-@fp:
-
-
diff --git a/libpolkit/Makefile.am b/libpolkit/Makefile.am
index 135870c..a64391f 100644
--- a/libpolkit/Makefile.am
+++ b/libpolkit/Makefile.am
@@ -8,7 +8,9 @@ INCLUDES = \
-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
- @GLIB_CFLAGS@
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ @GLIB_CFLAGS@ \
+ @DBUS_GLIB_CFLAGS@
lib_LTLIBRARIES=libpolkit.la
@@ -20,20 +22,10 @@ libpolkitinclude_HEADERS = \
libpolkit_la_SOURCES = \
libpolkit.c libpolkit.h
-libpolkit_la_LIBADD = @GLIB_LIBS@
+libpolkit_la_LIBADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@
libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-check_PROGRAMS = libpolkit-test
-
-libpolkit_test_SOURCES = \
- libpolkit-test.c
-
-libpolkit_test_LDADD = @GLIB_LIBS@ libpolkit.la
-
-TESTS = libpolkit-test
-
-
clean-local :
rm -f *~
diff --git a/libpolkit/libpolkit.c b/libpolkit/libpolkit.c
index 1809bb9..7c44635 100644
--- a/libpolkit/libpolkit.c
+++ b/libpolkit/libpolkit.c
@@ -1,7 +1,6 @@
/***************************************************************************
*
- * libpolkit.c : Simple library for system software to query policy and
- * UI shells to query and modify policy
+ * libpolkit.c : Wraps a subset of methods on the PolicyKit daemon
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
@@ -37,10 +36,10 @@
#include <errno.h>
#include <glib.h>
+#include <dbus/dbus-glib.h>
#include "libpolkit.h"
-
#define LIBPOLKIT_MAGIC 0x3117beef
#ifdef __SUNPRO_C
@@ -65,46 +64,23 @@
struct LibPolKitContext_s
{
guint32 magic;
- char *txt_backend_source;
+ DBusConnection *connection;
};
-struct LibPolKitElement_s
-{
- LibPolKitContext *ctx;
- LibPolKitElementType type;
- union {
- uid_t uid;
- gid_t gid;
- } id;
- gboolean include_all;
- gboolean exclude_all;
- char *resource;
-};
-
-
/** Get a new context.
*
* @return Pointer to new context or NULL if an error occured
*/
LibPolKitContext *
-libpolkit_new_context (void)
+libpolkit_new_context (DBusConnection *connection)
{
LibPolKitContext *ctx;
ctx = g_new0 (LibPolKitContext, 1);
ctx->magic = LIBPOLKIT_MAGIC;
- ctx->txt_backend_source = g_strdup (PACKAGE_SYSCONF_DIR "/PolicyKit/policy");
- return ctx;
-}
+ ctx->connection = connection;
-gboolean
-libpolkit_context_set_txt_source (LibPolKitContext *ctx,
- const char *directory)
-{
- LIBPOLKIT_CHECK_CONTEXT (ctx, FALSE);
- g_free (ctx->txt_backend_source);
- ctx->txt_backend_source = g_strdup (directory);
- return TRUE;
+ return ctx;
}
/** Free a context
@@ -116,721 +92,216 @@ gboolean
libpolkit_free_context (LibPolKitContext *ctx)
{
LIBPOLKIT_CHECK_CONTEXT (ctx, FALSE);
+
ctx->magic = 0;
- g_free (ctx->txt_backend_source);
g_free (ctx);
return TRUE;
}
-static LibPolKitResult
-txt_backend_read_policy (LibPolKitContext *ctx,
- const char *policy,
- const char *key,
- GList **result)
-{
- int i;
- GKeyFile *keyfile;
- GError *error;
- LibPolKitResult rc;
- char *path;
- char *value = NULL;
- char **tokens = NULL;
- char *ttype = NULL;
- char *tvalue = NULL;
- char *tresource = NULL;
- LibPolKitElement *elem = NULL;
- GList *res;
- GList *l;
- char *token;
-
- error = NULL;
- rc = LIBPOLKIT_RESULT_ERROR;
- res = NULL;
- *result = NULL;
-
- keyfile = g_key_file_new ();
- path = g_strdup_printf ("%s/%s.policy", ctx->txt_backend_source, policy);
- /*g_message ("Loading %s", path);*/
- if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) {
- g_warning ("Couldn't open key-file '%s': %s", path, error->message);
- g_error_free (error);
- rc = LIBPOLKIT_RESULT_NO_SUCH_POLICY;
- goto out;
- }
-
- value = g_key_file_get_string (keyfile, "Policy", key, &error);
- if (value == NULL) {
- g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message);
- g_error_free (error);
- rc = LIBPOLKIT_RESULT_ERROR;
- goto out;
- }
-
- /*g_message ("value = '%s'", value);*/
- tokens = g_strsplit (value, " ", 0);
- for (i = 0; tokens[i] != NULL; i++) {
- char **components;
- int num_components;
-
- token = tokens[i];
- /*g_message (" token = '%s'", token);*/
-
- ttype = NULL;
- tvalue = NULL;
- tresource = NULL;
-
- elem = libpolkit_element_new (ctx);
-
- components = g_strsplit (token, ":", 3);
- num_components = g_strv_length (components);
- if (num_components == 2) {
- ttype = g_strdup (components[0]);
- tvalue = g_strdup (components[1]);
- tresource = NULL;
- } else if (num_components == 3) {
- ttype = g_strdup (components[0]);
- tvalue = g_strdup (components[1]);
- tresource = g_strdup (components[2]);
- } else {
- g_strfreev (components);
- goto malformed_token;
- }
- g_strfreev (components);
-
- /*g_message (" type='%s' value='%s' resource='%s'", ttype, tvalue, tresource != NULL ? tresource : "None");*/
-
- if (strcmp (ttype, "uid") == 0) {
- libpolkit_element_set_type (elem, LIBPOLKIT_ELEMENT_TYPE_UID);
- if (strcmp (tvalue, "__all__") == 0) {
- libpolkit_element_set_include_all (elem, TRUE);
- } else if (strcmp (tvalue, "__none__") == 0) {
- libpolkit_element_set_exclude_all (elem, TRUE);
- } else {
- uid_t uid;
- char *endp;
- uid = (uid_t) g_ascii_strtoull (tvalue, &endp, 0);
- if (endp[0] != '\0') {
- uid = libpolkit_util_name_to_uid (ctx, tvalue, NULL);
- if (uid == (uid_t) -1) {
- g_warning ("User '%s' does not exist", tvalue);
- goto malformed_token;
- }
- }
- libpolkit_element_set_uid (elem, uid);
- }
- } else if (strcmp (ttype, "gid") == 0) {
- libpolkit_element_set_type (elem, LIBPOLKIT_ELEMENT_TYPE_GID);
- if (strcmp (tvalue, "__all__") == 0) {
- libpolkit_element_set_include_all (elem, TRUE);
- } else if (strcmp (tvalue, "__none__") == 0) {
- libpolkit_element_set_exclude_all (elem, TRUE);
- } else {
- gid_t gid;
- char *endp;
- gid = (gid_t) g_ascii_strtoull (tvalue, &endp, 0);
- if (endp[0] != '\0') {
- gid = libpolkit_util_name_to_gid (ctx, tvalue);
- if (gid == (gid_t) -1) {
- g_warning ("Group '%s' does not exist", tvalue);
- goto malformed_token;
- }
- }
- libpolkit_element_set_gid (elem, gid);
- }
- } else {
- g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed",
- token, key, path);
- goto malformed_token;
- }
-
- if (tresource != NULL) {
- libpolkit_element_set_resource (elem, tresource);
- }
-
- g_free (ttype);
- g_free (tvalue);
- g_free (tresource);
-
- res = g_list_append (res, elem);
- /*libpolkit_element_dump (elem, stderr);*/
-
- }
-
- *result = res;
- rc = LIBPOLKIT_RESULT_OK;
- goto out;
-
-malformed_token:
- g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed", token, key, path);
-
- for (l = res; l != NULL; l = g_list_next (l)) {
- libpolkit_free_element ((LibPolKitElement *) l->data);
- }
- g_list_free (res);
- libpolkit_free_element (elem);
- g_free (ttype);
- g_free (tvalue);
- g_free (tresource);
-
-out:
- g_strfreev (tokens);
- g_free (value);
-
- g_key_file_free (keyfile);
- g_free (path);
-
- return rc;
-}
-
-static void
-afp_process_elem(LibPolKitElement *elem, gboolean *flag, uid_t uid, guint num_gids, gid_t *gid_list)
-{
- /*libpolkit_element_dump (elem, stderr);*/
-
- switch (elem->type) {
- case LIBPOLKIT_ELEMENT_TYPE_UID:
- if (elem->include_all) {
- *flag = TRUE;
- } else if (elem->exclude_all) {
- *flag = FALSE;
- }else {
- if (elem->id.uid == uid)
- *flag = TRUE;
- }
- break;
-
- case LIBPOLKIT_ELEMENT_TYPE_GID:
- if (elem->include_all) {
- *flag = TRUE;
- } else if (elem->exclude_all) {
- *flag = FALSE;
- }else {
- guint i;
- for (i = 0; i < num_gids; i++) {
- if (elem->id.gid == gid_list[i])
- *flag = TRUE;
- }
- }
- break;
- }
-}
-
LibPolKitResult
-libpolkit_is_uid_gid_allowed_for_policy (LibPolKitContext *ctx,
- uid_t uid,
- guint num_gids,
- gid_t *gid_list,
- const char *policy,
- const char *resource,
- gboolean *result)
+libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
+ const char *user,
+ const char *privilege,
+ GList **result)
{
- gboolean is_in_whitelist;
- gboolean is_in_blacklist;
- GList *l;
- GList *whitelist;
- GList *blacklist;
LibPolKitResult res;
+ DBusMessage *message = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+ char **resource_list;
+ int num_resources;
+ int i;
LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
- whitelist = NULL;
- blacklist = NULL;
res = LIBPOLKIT_RESULT_ERROR;
+ *result = NULL;
- res = libpolkit_get_whitelist (ctx, policy, &whitelist);
- if (res != LIBPOLKIT_RESULT_OK)
+ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit",
+ "/org/freedesktop/PolicyKit/Manager",
+ "org.freedesktop.PolicyKit.Manager",
+ "GetAllowedResourcesForPrivilege");
+ if (message == NULL) {
+ g_warning ("Could not allocate D-BUS message");
goto out;
+ }
- res = libpolkit_get_blacklist (ctx, policy, &blacklist);
- if (res != LIBPOLKIT_RESULT_OK)
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &privilege,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not append args to D-BUS message");
goto out;
+ }
- is_in_whitelist = FALSE;
- is_in_blacklist = FALSE;
-
- /* Algorithm: To succeed.. we must be in the whitelist.. and not in the blacklist */
-
- for (l = whitelist; l != NULL; l = g_list_next (l)) {
- LibPolKitElement *elem;
- elem = (LibPolKitElement *) l->data;
- if ((elem->resource == NULL) ||
- ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
- afp_process_elem (elem, &is_in_whitelist, uid, num_gids, gid_list);
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &error);
+ if (dbus_error_is_set (&error)) {
+ if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.NotPrivileged") == 0) {
+ res = LIBPOLKIT_RESULT_NOT_PRIVILEGED;
+ } else if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.Error") == 0) {
+ res = LIBPOLKIT_RESULT_ERROR;
}
+ dbus_error_free (&error);
+ goto out;
}
- for (l = blacklist; l != NULL; l = g_list_next (l)) {
- LibPolKitElement *elem;
- elem = (LibPolKitElement *) l->data;
- if ((elem->resource == NULL) ||
- ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
- afp_process_elem (elem, &is_in_blacklist, uid, num_gids, gid_list);
- }
+ if (!dbus_message_get_args (reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &resource_list, &num_resources,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message);
+ dbus_error_free (&error);
+ goto out;
}
- *result = is_in_whitelist && (!is_in_blacklist);
+ for (i = 0; i < num_resources; i++) {
+ *result = g_list_append (*result, g_strdup (resource_list[i]));
+ }
+ dbus_free_string_array (resource_list);
res = LIBPOLKIT_RESULT_OK;
out:
- if (whitelist != NULL)
- libpolkit_free_element_list (whitelist);
- if (blacklist != NULL)
- libpolkit_free_element_list (blacklist);
-
- return res;
+ if (reply != NULL)
+ dbus_message_unref (reply);
+ if (message != NULL)
+ dbus_message_unref (message);
+ return res;
}
-char *
-libpolkit_util_uid_to_name (LibPolKitContext *ctx, uid_t uid, gid_t *default_gid)
+LibPolKitResult
+libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
+ pid_t pid,
+ const char *user,
+ const char *privilege,
+ const char *resource,
+ gboolean *result)
{
- int rc;
- char *res;
- char *buf = NULL;
- unsigned int bufsize;
- struct passwd pwd;
- struct passwd *pwdp;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, NULL);
-
- res = NULL;
+ LibPolKitResult res;
+ DBusMessage *message = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+ const char *myresource = "";
- bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
- buf = g_new0 (char, bufsize);
+ LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
- rc = getpwuid_r (uid, &pwd, buf, bufsize, &pwdp);
- if (rc != 0 || pwdp == NULL) {
- /*g_warning ("getpwuid_r() returned %d", rc);*/
+ res = LIBPOLKIT_RESULT_ERROR;
+ *result = FALSE;
+
+ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit",
+ "/org/freedesktop/PolicyKit/Manager",
+ "org.freedesktop.PolicyKit.Manager",
+ "IsUserPrivileged");
+ if (message == NULL) {
+ g_warning ("Could not allocate D-BUS message");
goto out;
}
- res = g_strdup (pwdp->pw_name);
- if (default_gid != NULL)
- *default_gid = pwdp->pw_gid;
+ if (resource != NULL)
+ myresource = resource;
-out:
- g_free (buf);
- return res;
-}
-
-char *
-libpolkit_util_gid_to_name (LibPolKitContext *ctx, gid_t gid)
-{
- int rc;
- char *res;
- char *buf = NULL;
- unsigned int bufsize;
- struct group gbuf;
- struct group *gbufp;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, NULL);
-
- res = NULL;
-
- bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
- buf = g_new0 (char, bufsize);
-
- rc = getgrgid_r (gid, &gbuf, buf, bufsize, &gbufp);
- if (rc != 0 || gbufp == NULL) {
- /*g_warning ("getgrgid_r() returned %d", rc);*/
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_INT32, &pid,
+ DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &privilege,
+ DBUS_TYPE_STRING, &myresource,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not append args to D-BUS message");
goto out;
}
- res = g_strdup (gbufp->gr_name);
-
-out:
- g_free (buf);
- return res;
-}
-
-
-
-uid_t
-libpolkit_util_name_to_uid (LibPolKitContext *ctx, const char *username, gid_t *default_gid)
-{
- int rc;
- uid_t res;
- char *buf = NULL;
- unsigned int bufsize;
- struct passwd pwd;
- struct passwd *pwdp;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, (uid_t) -1);
-
- res = (uid_t) -1;
-
- bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
- buf = g_new0 (char, bufsize);
-
- rc = getpwnam_r (username, &pwd, buf, bufsize, &pwdp);
- if (rc != 0 || pwdp == NULL) {
- /*g_warning ("getpwnam_r() returned %d", rc);*/
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &error);
+ if (dbus_error_is_set (&error)) {
+ if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.NoSuchUser") == 0) {
+ res = LIBPOLKIT_RESULT_NO_SUCH_USER;
+ } else if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.NoSuchPrivilege") == 0) {
+ res = LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE;
+ } else if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.NotPrivileged") == 0) {
+ res = LIBPOLKIT_RESULT_NOT_PRIVILEGED;
+ } else if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.Error") == 0) {
+ res = LIBPOLKIT_RESULT_ERROR;
+ }
+ dbus_error_free (&error);
goto out;
}
- res = pwdp->pw_uid;
- if (default_gid != NULL)
- *default_gid = pwdp->pw_gid;
-out:
- g_free (buf);
- return res;
-}
-
-gid_t
-libpolkit_util_name_to_gid (LibPolKitContext *ctx, const char *groupname)
-{
- int rc;
- gid_t res;
- char *buf = NULL;
- unsigned int bufsize;
- struct group gbuf;
- struct group *gbufp;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, (gid_t) -1);
-
- res = (gid_t) -1;
-
- bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
- buf = g_new0 (char, bufsize);
-
- rc = getgrnam_r (groupname, &gbuf, buf, bufsize, &gbufp);
- if (rc != 0 || gbufp == NULL) {
- /*g_warning ("getgrnam_r() returned %d", rc);*/
+ if (!dbus_message_get_args (reply, &error,
+ DBUS_TYPE_BOOLEAN, result,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message);
+ dbus_error_free (&error);
goto out;
}
- res = gbufp->gr_gid;
+ res = LIBPOLKIT_RESULT_OK;
out:
- g_free (buf);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+ if (message != NULL)
+ dbus_message_unref (message);
return res;
}
-
-LibPolKitResult
-libpolkit_is_uid_allowed_for_policy (LibPolKitContext *ctx,
- uid_t uid,
- const char *policy,
- const char *resource,
- gboolean *result)
-{
- int num_groups = 0;
- gid_t *groups = NULL;
- char *username;
- gid_t default_gid;
- LibPolKitResult r;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
-
- r = LIBPOLKIT_RESULT_ERROR;
-
- if ((username = libpolkit_util_uid_to_name (ctx, uid, &default_gid)) == NULL)
- goto out;
-
- /* TODO: this is glibc only at the moment... */
- if (getgrouplist(username, default_gid, NULL, &num_groups) < 0) {
- groups = (gid_t *) g_new0 (gid_t, num_groups);
- if (getgrouplist(username, default_gid, groups, &num_groups) < 0) {
- g_warning ("getgrouplist() failed");
- goto out;
- }
- }
-
- /*
- {
- int i;
- g_debug ("uid %d (%s)", uid, username);
- for (i = 0; i < num_groups; i++) {
- char *group_name;
- group_name = libpolkit_util_gid_to_name (groups[i]);
- g_debug (" gid %d (%s)", groups[i], group_name);
- g_free (group_name);
- }
- }
- */
-
- r = libpolkit_is_uid_gid_allowed_for_policy (ctx,
- uid,
- num_groups,
- groups,
- policy,
- resource,
- result);
-
-out:
- g_free (username);
- g_free (groups);
- return r;
-}
-
-
-/** Return all elements in the white-list for a policy
- *
- * @param ctx The context obtained from libpolkit_new_context
- * @param policy Name of policy
- * @param results On success set to a list of dynamically allocated LibPolKitElement structures.
- * Must be freed by the caller
- * @return Whether the operation succeeded
- */
-LibPolKitResult
-libpolkit_get_whitelist (LibPolKitContext *ctx,
- const char *policy,
- GList **result)
-{
- LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
-
- return txt_backend_read_policy (ctx, policy, "Allow", result);
-}
-
-/** Return all elements in the black-list for a policy
- *
- * @param ctx The context obtained from libpolkit_new_context
- * @param policy Name of policy
- * @param results On success set to a list of dynamically allocated LibPolKitElement structures.
- * Must be freed by the caller
- * @return Whether the operation succeeded
- */
LibPolKitResult
-libpolkit_get_blacklist (LibPolKitContext *ctx,
- const char *policy,
- GList **result)
+libpolkit_get_privilege_list (LibPolKitContext *ctx,
+ GList **result)
{
- LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
-
- return txt_backend_read_policy (ctx, policy, "Deny", result);
-}
-
-/** Return all elements in the white-list for a policy
- *
- * @param ctx The context obtained from libpolkit_new_context
- * @param result On success set to a list of dynamically allocated strings.
- * Must be freed by the caller.
- * @return Whether the operation succeeded
- */
-LibPolKitResult
-libpolkit_get_policies (LibPolKitContext *ctx,
- GList **result)
-{
- GDir *dir;
- GError *error;
- const char *f;
+ LibPolKitResult res;
+ DBusMessage *message = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+ char **privilege_list;
+ int num_privileges;
+ int i;
LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT);
- error = NULL;
+ res = LIBPOLKIT_RESULT_ERROR;
*result = NULL;
- if ((dir = g_dir_open (ctx->txt_backend_source, 0, &error)) == NULL) {
- g_critical ("Unable to open %s: %s", ctx->txt_backend_source, error->message);
- g_error_free (error);
- goto error;
- }
- while ((f = g_dir_read_name (dir)) != NULL) {
- if (g_str_has_suffix (f, ".policy")) {
- char *s;
- int pos;
-
- s = g_strdup (f);
- pos = strlen (s) - 7;
- if (pos > 0)
- s[pos] = '\0';
-
- *result = g_list_append (*result, s);
- }
- }
-
- g_dir_close (dir);
-
- return LIBPOLKIT_RESULT_OK;
-
-error:
- return LIBPOLKIT_RESULT_ERROR;
-}
-
-
-LibPolKitElement *
-libpolkit_element_new (LibPolKitContext *ctx)
-{
- LibPolKitElement *elem;
-
- LIBPOLKIT_CHECK_CONTEXT (ctx, NULL);
-
- elem = g_new0 (LibPolKitElement, 1);
- elem->ctx = ctx;
- return elem;
-}
-
-void
-libpolkit_element_set_type (LibPolKitElement *elem,
- LibPolKitElementType type)
-{
- elem->type = type;
-}
-
-void
-libpolkit_element_set_include_all (LibPolKitElement *elem,
- gboolean value)
-{
- elem->include_all = value;
-}
-
-void
-libpolkit_element_set_exclude_all (LibPolKitElement *elem,
- gboolean value)
-{
- elem->exclude_all = value;
-}
-
-void
-libpolkit_element_set_uid (LibPolKitElement *elem,
- uid_t uid)
-{
- elem->id.uid = uid;
-}
-
-void
-libpolkit_element_set_gid (LibPolKitElement *elem,
- gid_t gid)
-{
- elem->id.gid = gid;
-}
-
-void
-libpolkit_element_set_resource (LibPolKitElement *elem,
- const char *resource)
-{
- g_free (elem->resource);
- elem->resource = g_strdup (resource);
-}
-
-
-
-void
-libpolkit_free_element (LibPolKitElement *elem)
-{
- g_free (elem->resource);
- g_free (elem);
-}
-
-void
-libpolkit_free_element_list (GList *policy_element_list)
-{
- GList *l;
-
- for (l = policy_element_list; l != NULL; l = g_list_next (l)) {
- LibPolKitElement *elem = (LibPolKitElement *) l->data;
- libpolkit_free_element (elem);
+ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit",
+ "/org/freedesktop/PolicyKit/Manager",
+ "org.freedesktop.PolicyKit.Manager",
+ "ListPrivileges");
+ if (message == NULL) {
+ g_warning ("Could not allocate D-BUS message");
+ goto out;
}
- g_list_free (policy_element_list);
-}
-
-LibPolKitElementType
-libpolkit_element_get_type (LibPolKitElement *elem)
-{
- return elem->type;
-}
-
-gboolean
-libpolkit_element_get_include_all (LibPolKitElement *elem)
-{
- return elem->include_all;
-}
-
-gboolean
-libpolkit_element_get_exclude_all (LibPolKitElement *elem)
-{
- return elem->exclude_all;
-}
-
-uid_t
-libpolkit_element_get_uid (LibPolKitElement *elem)
-{
- return elem->id.uid;
-}
-
-gid_t
-libpolkit_element_get_gid (LibPolKitElement *elem)
-{
- return elem->id.gid;
-}
-
-const char *
-libpolkit_element_get_resource (LibPolKitElement *elem)
-{
- return elem->resource;
-}
-
-void
-libpolkit_element_dump (LibPolKitElement *elem, FILE* fp)
-{
- char *t;
-
- if (elem->type == LIBPOLKIT_ELEMENT_TYPE_UID)
- t = "uid";
- else if (elem->type == LIBPOLKIT_ELEMENT_TYPE_GID)
- t = "gid";
- else
- t = "(Unknown)";
-
- fprintf (fp, "type: %s\n", t);
- if (elem->type == LIBPOLKIT_ELEMENT_TYPE_UID) {
- if (elem->include_all) {
- fprintf (fp, "uid: all\n");
- } else if (elem->exclude_all) {
- fprintf (fp, "uid: none\n");
- } else {
- fprintf (fp, "uid: %d\n", (int) elem->id.uid);
- }
- } else if (elem->type == LIBPOLKIT_ELEMENT_TYPE_GID) {
- if (elem->include_all) {
- fprintf (fp, "gid: all\n");
- } else if (elem->exclude_all) {
- fprintf (fp, "gid: none\n");
- } else {
- fprintf (fp, "gid: %d\n", (int) elem->id.gid);
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (ctx->connection, message, -1, &error);
+ if (dbus_error_is_set (&error)) {
+ if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.NotPrivileged") == 0) {
+ res = LIBPOLKIT_RESULT_NOT_PRIVILEGED;
+ } else if (strcmp (error.name, "org.freedesktop.PolicyKit.Manager.Error") == 0) {
+ res = LIBPOLKIT_RESULT_ERROR;
}
+ dbus_error_free (&error);
+ goto out;
}
- fprintf (fp, "resource: %s\n", elem->resource != NULL ? elem->resource : "(None)");
-}
-
-#ifndef HAVE_GETGROUPLIST
-/* Get group list for the named user.
- * Return up to ngroups in the groups array.
- * Return actual number of groups in ngroups.
- * Return -1 if more groups found than requested.
- */
-int
-getgrouplist (const char *name, int baseid, int *groups, int *ngroups)
-{
- struct group *g;
- int n = 0;
- int i;
- int ret;
- if (*ngroups <= 0) {
- return (-1);
+ if (!dbus_message_get_args (reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &privilege_list, &num_privileges,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message);
+ dbus_error_free (&error);
+ goto out;
}
- *groups++ = baseid;
- n++;
-
- setgrent ();
- while ((g = getgrent ()) != NULL) {
- for (i = 0; g->gr_mem[i]; i++) {
- if (strcmp (name, g->gr_mem[0]) == 0) {
- *groups++ = g->gr_gid;
- if (++n > *ngroups) {
- break;
- }
- }
- }
+ for (i = 0; i < num_privileges; i++) {
+ *result = g_list_append (*result, g_strdup (privilege_list[i]));
}
- endgrent ();
+ dbus_free_string_array (privilege_list);
+
+ res = LIBPOLKIT_RESULT_OK;
- ret = (n > *ngroups) ? -1 : n;
- *ngroups = n;
- return (ret);
+out:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+ if (message != NULL)
+ dbus_message_unref (message);
+ return res;
}
-#endif
diff --git a/libpolkit/libpolkit.h b/libpolkit/libpolkit.h
index e430b3c..0db6de8 100644
--- a/libpolkit/libpolkit.h
+++ b/libpolkit/libpolkit.h
@@ -1,7 +1,6 @@
/***************************************************************************
*
- * libpolkit.h : Simple library for system software to query policy and
- * UI shells to query and modify policy
+ * libpolkit.h : Wraps a subset of methods on the PolicyKit daemon
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
@@ -30,121 +29,38 @@
#include <unistd.h>
#include <sys/types.h>
#include <glib.h>
+#include <dbus/dbus.h>
typedef enum {
LIBPOLKIT_RESULT_OK,
LIBPOLKIT_RESULT_ERROR,
LIBPOLKIT_RESULT_INVALID_CONTEXT,
- LIBPOLKIT_RESULT_PERMISSON_DENIED,
- LIBPOLKIT_RESULT_NO_SUCH_POLICY
+ LIBPOLKIT_RESULT_NOT_PRIVILEGED,
+ LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE,
+ LIBPOLKIT_RESULT_NO_SUCH_USER
} LibPolKitResult;
struct LibPolKitContext_s;
typedef struct LibPolKitContext_s LibPolKitContext;
+LibPolKitContext *libpolkit_new_context (DBusConnection *connection);
-typedef enum {
- LIBPOLKIT_ELEMENT_TYPE_UID,
- LIBPOLKIT_ELEMENT_TYPE_GID
-} LibPolKitElementType;
-
-struct LibPolKitElement_s;
-typedef struct LibPolKitElement_s LibPolKitElement;
-
-
-LibPolKitContext *libpolkit_new_context (void);
-
-gboolean libpolkit_context_set_txt_source (LibPolKitContext *ctx,
- const char *directory);
-
-gboolean libpolkit_free_context (LibPolKitContext *ctx);
-
-LibPolKitResult libpolkit_get_policies (LibPolKitContext *ctx,
- GList **result);
-
-LibPolKitResult libpolkit_is_uid_allowed_for_policy (LibPolKitContext *ctx,
- uid_t uid,
- const char *policy,
- const char *resource,
- gboolean *result);
-
-
-LibPolKitResult libpolkit_is_uid_gid_allowed_for_policy (LibPolKitContext *ctx,
- uid_t uid,
- guint num_gids,
- gid_t *gid_list,
- const char *policy,
- const char *resource,
- gboolean *result);
-
-
-
-LibPolKitResult libpolkit_get_whitelist (LibPolKitContext *ctx,
- const char *policy,
- GList **result);
-
-LibPolKitResult libpolkit_get_blacklist (LibPolKitContext *ctx,
- const char *policy,
- GList **result);
-
-LibPolKitResult libpolkit_set_whitelist (LibPolKitContext *ctx,
- const char *policy,
- GList *whitelist);
-
-LibPolKitResult libpolkit_set_blacklist (LibPolKitContext *ctx,
- const char *policy,
- GList *blacklist);
-
-
-LibPolKitElementType libpolkit_element_get_type (LibPolKitElement *elem);
-
-gboolean libpolkit_element_get_include_all (LibPolKitElement *elem);
-
-gboolean libpolkit_element_get_exclude_all (LibPolKitElement *elem);
-
-uid_t libpolkit_element_get_uid (LibPolKitElement *elem);
-
-gid_t libpolkit_element_get_gid (LibPolKitElement *elem);
-
-const char *libpolkit_element_get_resource (LibPolKitElement *elem);
-
-
-
-LibPolKitElement *libpolkit_element_new (LibPolKitContext *ctx);
-
-void libpolkit_element_set_type (LibPolKitElement *elem,
- LibPolKitElementType type);
-
-void libpolkit_element_set_include_all (LibPolKitElement *elem,
- gboolean value);
-
-void libpolkit_element_set_exclude_all (LibPolKitElement *elem,
- gboolean value);
-
-void libpolkit_element_set_uid (LibPolKitElement *elem,
- uid_t uid);
-
-void libpolkit_element_set_gid (LibPolKitElement *elem,
- gid_t gid);
-
-void libpolkit_element_set_resource (LibPolKitElement *elem,
- const char *resource);
-
-
-
-void libpolkit_free_element (LibPolKitElement *elem);
-
-void libpolkit_free_element_list (GList *policy_element_list);
-
-
+gboolean libpolkit_free_context (LibPolKitContext *ctx);
-char *libpolkit_util_uid_to_name (LibPolKitContext *ctx, uid_t uid, gid_t *default_gid);
-char *libpolkit_util_gid_to_name (LibPolKitContext *ctx, gid_t gid);
+LibPolKitResult libpolkit_get_privilege_list (LibPolKitContext *ctx,
+ GList **result);
-uid_t libpolkit_util_name_to_uid (LibPolKitContext *ctx, const char *username, gid_t *default_gid);
-gid_t libpolkit_util_name_to_gid (LibPolKitContext *ctx, const char *groupname);
+LibPolKitResult libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
+ pid_t pid,
+ const char *user,
+ const char *privilege,
+ const char *resource,
+ gboolean *result);
-void libpolkit_element_dump (LibPolKitElement *elem, FILE* fp);
+LibPolKitResult libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx,
+ const char *user,
+ const char *privilege,
+ GList **result);
#endif /* LIBPOLKIT_H */
diff --git a/policy-kit.in b/policy-kit.in
new file mode 100644
index 0000000..fc82666
--- /dev/null
+++ b/policy-kit.in
@@ -0,0 +1,8 @@
+#%PAM-1.0
+
+auth include @PAM_FILE_INCLUDE@
+account include @PAM_FILE_INCLUDE@
+password include @PAM_FILE_INCLUDE@
+session include @PAM_FILE_INCLUDE@
+
+
diff --git a/polkit-interface-manager.xml b/polkit-interface-manager.xml
new file mode 100644
index 0000000..b3a3801
--- /dev/null
+++ b/polkit-interface-manager.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/org/freedesktop/PolicyKit/Manager">
+ <interface name="org.freedesktop.PolicyKit.Manager">
+
+ <method name="InitiatePrivilegeGrant">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="user" type="s" direction="in"/>
+ <arg name="privilege" type="s" direction="in"/>
+ <arg name="resource" type="s" direction="in"/>
+ <arg name="session_objpath" type="o" direction="out"/>
+ </method>
+
+ <method name="IsUserPrivileged">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="pid" type="i" direction="in"/>
+ <arg name="user" type="s" direction="in"/>
+ <arg name="privilege" type="s" direction="in"/>
+ <arg name="resource" type="s" direction="in"/>
+ <arg name="is_privileged" type="b" direction="out"/>
+ </method>
+
+ <method name="GetAllowedResourcesForPrivilege">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="user" type="s" direction="in"/>
+ <arg name="privilege" type="s" direction="in"/>
+ <arg name="resource_list" type="as" direction="out"/>
+ </method>
+
+ <method name="ListPrivileges">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="privilege_list" type="as" direction="out"/>
+ </method>
+
+ </interface>
+</node>
diff --git a/polkit-interface-session.xml b/polkit-interface-session.xml
new file mode 100644
index 0000000..ff51bff
--- /dev/null
+++ b/polkit-interface-session.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node>
+ <interface name="org.freedesktop.PolicyKit.Session">
+
+ <method name="InitiateAuth">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+
+ <method name="GetQuestions">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="question_list" type="as" direction="out"/>
+ </method>
+
+ <method name="GetAuthDetails">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="user" type="s" direction="out"/>
+ <arg name="pam_service_name" type="s" direction="out"/>
+ </method>
+
+ <method name="ProvideAnswers">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="answer_list" type="as" direction="in"/>
+ </method>
+
+ <method name="IsAuthenticated">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="is_authenticated" type="b" direction="out"/>
+ </method>
+
+ <method name="GetAuthDeniedReason">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="reason" type="s" direction="out"/>
+ </method>
+
+ <method name="Close">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="do_not_revoke_privileges" type="b" direction="in"/>
+ </method>
+
+ <method name="GrantPrivilegeTemporarily">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="restrict_to_callers_pid" type="b" direction="in"/>
+ </method>
+
+ <signal name="HaveQuestions"/>
+
+ <signal name="AuthenticationDone"/>
+
+ </interface>
+</node>
diff --git a/polkit.pc.in b/polkit.pc.in
index 659941e..8fbc889 100644
--- a/polkit.pc.in
+++ b/polkit.pc.in
@@ -5,7 +5,7 @@ includedir=@includedir@
user=@POLKIT_USER@
group=@POLKIT_GROUP@
-txtsrc=@sysconfdir@/PolicyKit/policy
+txtsrc=@sysconfdir@/PolicyKit/privilege.d
Name: libpolkit
Description: library for querying and setting system-wide policy
diff --git a/polkitd/Makefile.am b/polkitd/Makefile.am
new file mode 100644
index 0000000..a5423ab
--- /dev/null
+++ b/polkitd/Makefile.am
@@ -0,0 +1,94 @@
+
+INCLUDES = \
+ -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
+ -I$(top_srcdir) \
+ @GLIB_CFLAGS@ \
+ @DBUS_GLIB_CFLAGS@
+
+# polkitd
+#
+
+sbin_PROGRAMS = polkitd
+
+polkitd_SOURCES = \
+ polkit-marshal.c polkit-marshal.h \
+ polkit-session.c polkit-session.h \
+ polkit-manager.c polkit-manager.h \
+ polkit-interface-manager-glue.h \
+ polkit-interface-session-glue.h \
+ policy.c policy.h \
+ main.c
+
+polkitd_CFLAGS = -fno-strict-aliasing
+polkitd_LDADD = @GLIB_LIBS@ @DBUS_GLIB_LIBS@ @AUTH_LIBS@
+
+#### Init scripts fun
+SCRIPT_IN_FILES=PolicyKit.in
+
+## Red Hat start
+if OS_TYPE_RED_HAT
+
+initddir=$(sysconfdir)/rc.d/init.d
+
+initd_SCRIPTS= \
+ PolicyKit
+
+endif
+## Red Hat end
+
+# D-BUS configuration file
+#
+
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dist_dbus_DATA = PolicyKit.conf
+
+# D-BUS glue
+#
+
+polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_manager --mode=glib-server --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml
+
+polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_session --mode=glib-server --output=polkit-interface-session-glue.h ../polkit-interface-session.xml
+
+BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h
+
+# Marshallers
+#
+
+polkit-marshal.c: Makefile polkit-marshal.list
+ glib-genmarshal --prefix=polkit_marshal $(srcdir)/polkit-marshal.list --header --body > $@.tmp && mv $@.tmp $@
+
+polkit-marshal.h: Makefile polkit-marshal.list
+ glib-genmarshal --prefix=polkit_marshal $(srcdir)/polkit-marshal.list --header > $@.tmp && mv $@.tmp $@
+
+BUILT_SOURCES += polkit-marshal.c polkit-marshal.h
+
+
+# Test harness
+#
+
+check_PROGRAMS = polkitd-test
+
+polkitd_test_SOURCES = \
+ policy.c policy.h \
+ polkitd-test.c
+
+polkitd_test_LDADD = @GLIB_LIBS@
+
+TESTS = polkitd-test
+
+
+
+EXTRA_DIST = polkit-marshal.list
+
+# Clean
+#
+
+clean-local:
+ rm -f *~ $(BUILT_SOURCES) PolicyKit.conf
diff --git a/polkitd/debug-polkitd.sh b/polkitd/debug-polkitd.sh
new file mode 100755
index 0000000..f331ec8
--- /dev/null
+++ b/polkitd/debug-polkitd.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo ========================================
+echo Just type \'run\' to start debugging polkitd
+echo ========================================
+gdb run --args ./polkitd --no-daemon --verbose
+
+
+
diff --git a/polkitd/main.c b/polkitd/main.c
new file mode 100644
index 0000000..49e2810
--- /dev/null
+++ b/polkitd/main.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * main.c : Main for polkitd
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "polkit-session.h"
+#include "polkit-manager.h"
+
+#include "polkit-interface-session-glue.h"
+#include "polkit-interface-manager-glue.h"
+
+/** Print out program usage.
+ *
+ */
+static void
+usage (int argc, char *argv[])
+{
+ fprintf (stderr, "\n" "usage : polkitd [--no-daemon] [--verbose]\n");
+ fprintf (stderr,
+ "\n"
+ " -n, --no-daemon Do not daemonize\n"
+ " -v, --verbose Print out debug\n"
+ " -h, --help Show this information and exit\n"
+ " -V, --version Output version information and exit"
+ "\n"
+ "The PolicyKit daemon maintains a list of privileges and\n"
+ "provides interfaces for changing it.\n"
+ "\n"
+ "For more information visit http://freedesktop.org/Software/hal\n"
+ "\n");
+}
+
+static void
+delete_pid (void)
+{
+ unlink (POLKITD_PID_FILE);
+}
+
+int
+main (int argc, char *argv[])
+{
+ DBusGConnection *bus;
+ DBusGProxy *bus_proxy;
+ GError *error = NULL;
+ PolicyKitManager *manager;
+ GMainLoop *mainloop;
+ guint request_name_result;
+ int ret;
+ gboolean no_daemon = FALSE;
+ gboolean is_verbose = FALSE;
+ static const struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"no-daemon", no_argument, NULL, 'n'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+ };
+
+
+ ret = 1;
+
+ g_type_init ();
+
+ while (TRUE) {
+ int c;
+
+ c = getopt_long (argc, argv, "nhVv", long_options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'n':
+ no_daemon = TRUE;
+ break;
+
+ case 'v':
+ is_verbose = TRUE;
+ break;
+
+ case 'h':
+ usage (argc, argv);
+ ret = 0;
+ goto out;
+
+ case 'V':
+ printf (PACKAGE_NAME " version " PACKAGE_VERSION "\n");
+ ret = 0;
+ goto out;
+
+ default:
+ usage (argc, argv);
+ goto out;
+ }
+ }
+
+
+ if (!no_daemon) {
+ int child_pid;
+ int dev_null_fd;
+ int pf;
+ ssize_t written;
+ char pid[9];
+
+
+ if (chdir ("/") < 0) {
+ g_warning ("Could not chdir to /: %s", strerror (errno));
+ goto out;
+ }
+
+ child_pid = fork ();
+ switch (child_pid) {
+ case -1:
+ g_warning ("Cannot fork(): %s", strerror (errno));
+ goto out;
+
+ case 0:
+ /* child */
+ dev_null_fd = open ("/dev/null", O_RDWR);
+ /* ignore if we can't open /dev/null */
+ if (dev_null_fd >= 0) {
+ /* attach /dev/null to stdout, stdin, stderr */
+ dup2 (dev_null_fd, 0);
+ dup2 (dev_null_fd, 1);
+ dup2 (dev_null_fd, 2);
+ close (dev_null_fd);
+ }
+
+ umask (022);
+ break;
+
+ default:
+ /* parent exits */
+ exit (0);
+ break;
+ }
+
+ /* create session */
+ setsid ();
+
+ /* remove old pid file */
+ unlink (POLKITD_PID_FILE);
+
+ /* make a new pid file */
+ if ((pf = open (POLKITD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
+ snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
+ written = write (pf, pid, strlen(pid));
+ close (pf);
+ g_atexit (delete_pid);
+ }
+ } else {
+ g_debug (("not becoming a daemon"));
+ }
+
+ g_type_init ();
+
+ dbus_g_object_type_install_info (POLKIT_TYPE_MANAGER, &dbus_glib_polkit_manager_object_info);
+ dbus_g_object_type_install_info (POLKIT_TYPE_SESSION, &dbus_glib_polkit_session_object_info);
+ dbus_g_error_domain_register (POLKIT_MANAGER_ERROR, NULL, POLKIT_MANAGER_TYPE_ERROR);
+ dbus_g_error_domain_register (POLKIT_SESSION_ERROR, NULL, POLKIT_SESSION_TYPE_ERROR);
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (bus == NULL) {
+ g_warning ("Couldn't connect to system bus: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus");
+ if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
+ G_TYPE_STRING, "org.freedesktop.PolicyKit",
+ G_TYPE_UINT, 0,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &request_name_result,
+ G_TYPE_INVALID)) {
+ g_warning ("Failed to acquire org.freedesktop.PolicyKit: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+
+
+ manager = polkit_manager_new (bus, bus_proxy);
+
+ g_debug ("service running");
+
+ g_main_loop_run (mainloop);
+
+ ret = 0;
+out:
+ return ret;
+}
diff --git a/polkitd/policy.c b/polkitd/policy.c
new file mode 100644
index 0000000..95032ec
--- /dev/null
+++ b/polkitd/policy.c
@@ -0,0 +1,765 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * policy.c : Wraps policy
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "policy.h"
+
+#ifdef __SUNPRO_C
+#define __FUNCTION__ __func__
+#endif
+
+static char *policy_directory = PACKAGE_SYSCONF_DIR "/PolicyKit/privilege.d";
+
+void
+policy_util_set_policy_directory (const char *directory)
+{
+ policy_directory = g_strdup (directory);
+}
+
+
+typedef enum {
+ POLICY_ELEMENT_TYPE_UID,
+ POLICY_ELEMENT_TYPE_GID
+} PolicyElementType;
+
+
+struct PolicyElement_s
+{
+ PolicyElementType type;
+ union {
+ uid_t uid;
+ gid_t gid;
+ } id;
+ gboolean include_all;
+ gboolean exclude_all;
+ char *resource;
+};
+
+typedef struct PolicyElement_s PolicyElement;
+
+static PolicyElement *
+policy_element_new (void)
+{
+ PolicyElement *elem;
+
+ elem = g_new0 (PolicyElement, 1);
+ return elem;
+}
+
+static void
+policy_element_free (PolicyElement *elem)
+{
+ g_free (elem->resource);
+ g_free (elem);
+}
+
+static void
+policy_element_free_list (GList *policy_element_list)
+{
+ GList *l;
+
+ for (l = policy_element_list; l != NULL; l = g_list_next (l)) {
+ PolicyElement *elem = (PolicyElement *) l->data;
+ policy_element_free (elem);
+ }
+
+ g_list_free (policy_element_list);
+}
+
+#if 0
+static void
+policy_element_dump (PolicyElement *elem, FILE* fp)
+{
+ char *t;
+
+ if (elem->type == POLICY_ELEMENT_TYPE_UID)
+ t = "uid";
+ else if (elem->type == POLICY_ELEMENT_TYPE_GID)
+ t = "gid";
+ else
+ t = "(Unknown)";
+
+ fprintf (fp, "type: %s\n", t);
+ if (elem->type == POLICY_ELEMENT_TYPE_UID) {
+ if (elem->include_all) {
+ fprintf (fp, "uid: all\n");
+ } else if (elem->exclude_all) {
+ fprintf (fp, "uid: none\n");
+ } else {
+ fprintf (fp, "uid: %d\n", (int) elem->id.uid);
+ }
+ } else if (elem->type == POLICY_ELEMENT_TYPE_GID) {
+ if (elem->include_all) {
+ fprintf (fp, "gid: all\n");
+ } else if (elem->exclude_all) {
+ fprintf (fp, "gid: none\n");
+ } else {
+ fprintf (fp, "gid: %d\n", (int) elem->id.gid);
+ }
+ }
+ fprintf (fp, "resource: %s\n", elem->resource != NULL ? elem->resource : "(None)");
+}
+#endif
+
+
+static PolicyResult
+txt_backend_read_policy (const char *policy,
+ const char *key,
+ GList **result)
+{
+ int i;
+ GKeyFile *keyfile;
+ GError *error;
+ PolicyResult rc;
+ char *path;
+ char *value = NULL;
+ char **tokens = NULL;
+ char *ttype = NULL;
+ char *tvalue = NULL;
+ char *tresource = NULL;
+ PolicyElement *elem = NULL;
+ GList *res;
+ GList *l;
+ char *token;
+
+ error = NULL;
+ rc = POLICY_RESULT_ERROR;
+ res = NULL;
+ *result = NULL;
+
+ keyfile = g_key_file_new ();
+ path = g_strdup_printf ("%s/%s.privilege", policy_directory, policy);
+ /*g_message ("Loading %s", path);*/
+ if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) {
+ g_warning ("Couldn't open key-file '%s': %s", path, error->message);
+ g_error_free (error);
+ rc = POLICY_RESULT_NO_SUCH_POLICY;
+ goto out;
+ }
+
+ value = g_key_file_get_string (keyfile, "Policy", key, &error);
+ if (value == NULL) {
+ g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message);
+ g_error_free (error);
+ rc = POLICY_RESULT_ERROR;
+ goto out;
+ }
+
+ /*g_message ("value = '%s'", value);*/
+ tokens = g_strsplit (value, " ", 0);
+ for (i = 0; tokens[i] != NULL; i++) {
+ char **components;
+ int num_components;
+
+ token = tokens[i];
+ /*g_message (" token = '%s'", token);*/
+
+ ttype = NULL;
+ tvalue = NULL;
+ tresource = NULL;
+
+ elem = policy_element_new ();
+
+ components = g_strsplit (token, ":", 3);
+ num_components = g_strv_length (components);
+ if (num_components == 2) {
+ ttype = g_strdup (components[0]);
+ tvalue = g_strdup (components[1]);
+ tresource = NULL;
+ } else if (num_components == 3) {
+ ttype = g_strdup (components[0]);
+ tvalue = g_strdup (components[1]);
+ tresource = g_strdup (components[2]);
+ } else {
+ g_strfreev (components);
+ goto malformed_token;
+ }
+ g_strfreev (components);
+
+ /*g_message (" type='%s' value='%s' resource='%s'", ttype, tvalue, tresource != NULL ? tresource : "None");*/
+
+ if (strcmp (ttype, "uid") == 0) {
+ elem->type = POLICY_ELEMENT_TYPE_UID;
+ if (strcmp (tvalue, "__all__") == 0) {
+ elem->include_all = TRUE;
+ } else if (strcmp (tvalue, "__none__") == 0) {
+ elem->exclude_all = TRUE;
+ } else {
+ uid_t uid;
+ char *endp;
+ uid = (uid_t) g_ascii_strtoull (tvalue, &endp, 0);
+ if (endp[0] != '\0') {
+ uid = policy_util_name_to_uid (tvalue, NULL);
+ if (uid == (uid_t) -1) {
+ g_warning ("User '%s' does not exist", tvalue);
+ goto malformed_token;
+ }
+ }
+ elem->id.uid = uid;
+ }
+ } else if (strcmp (ttype, "gid") == 0) {
+ elem->type = POLICY_ELEMENT_TYPE_GID;
+ if (strcmp (tvalue, "__all__") == 0) {
+ elem->include_all = TRUE;
+ } else if (strcmp (tvalue, "__none__") == 0) {
+ elem->exclude_all = TRUE;
+ } else {
+ gid_t gid;
+ char *endp;
+ gid = (gid_t) g_ascii_strtoull (tvalue, &endp, 0);
+ if (endp[0] != '\0') {
+ gid = policy_util_name_to_gid (tvalue);
+ if (gid == (gid_t) -1) {
+ g_warning ("Group '%s' does not exist", tvalue);
+ goto malformed_token;
+ }
+ }
+ elem->id.gid = gid;
+ }
+ } else {
+ g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed",
+ token, key, path);
+ goto malformed_token;
+ }
+
+ if (tresource != NULL) {
+ elem->resource = g_strdup (tresource);
+ }
+
+ g_free (ttype);
+ g_free (tvalue);
+ g_free (tresource);
+
+ res = g_list_append (res, elem);
+ /*policy_element_dump (elem, stderr);*/
+
+ }
+
+ *result = res;
+ rc = POLICY_RESULT_OK;
+ goto out;
+
+malformed_token:
+ g_warning ("Token '%s' in key '%s' in group 'Policy' in file '%s' malformed", token, key, path);
+
+ for (l = res; l != NULL; l = g_list_next (l)) {
+ policy_element_free ((PolicyElement *) l->data);
+ }
+ g_list_free (res);
+ policy_element_free (elem);
+ g_free (ttype);
+ g_free (tvalue);
+ g_free (tresource);
+
+out:
+ g_strfreev (tokens);
+ g_free (value);
+
+ g_key_file_free (keyfile);
+ g_free (path);
+
+ return rc;
+}
+
+static PolicyResult
+policy_get_whitelist (const char *policy,
+ GList **result)
+{
+ return txt_backend_read_policy (policy, "Allow", result);
+}
+
+static PolicyResult
+policy_get_blacklist (const char *policy,
+ GList **result)
+{
+ return txt_backend_read_policy (policy, "Deny", result);
+}
+
+/** Return all elements in the white-list for a policy
+ *
+ * @param result On success set to a list of dynamically allocated strings.
+ * Must be freed by the caller.
+ * @return Whether the operation succeeded
+ */
+PolicyResult
+policy_get_policies (GList **result)
+{
+ GDir *dir;
+ GError *error;
+ const char *f;
+
+ error = NULL;
+ *result = NULL;
+
+ if ((dir = g_dir_open (policy_directory, 0, &error)) == NULL) {
+ g_critical ("Unable to open %s: %s", policy_directory, error->message);
+ g_error_free (error);
+ goto error;
+ }
+ while ((f = g_dir_read_name (dir)) != NULL) {
+ if (g_str_has_suffix (f, ".privilege")) {
+ char *s;
+ int pos;
+
+ s = g_strdup (f);
+ pos = strlen (s) - 10; /* .privilege - 10 chars */
+ if (pos > 0)
+ s[pos] = '\0';
+
+ *result = g_list_append (*result, s);
+ }
+ }
+
+ g_dir_close (dir);
+
+ return POLICY_RESULT_OK;
+
+error:
+ return POLICY_RESULT_ERROR;
+}
+
+
+static void
+afp_process_elem(PolicyElement *elem, gboolean *flag, uid_t uid, guint num_gids, gid_t *gid_list)
+{
+ /*policy_element_dump (elem, stderr);*/
+
+ switch (elem->type) {
+ case POLICY_ELEMENT_TYPE_UID:
+ if (elem->include_all) {
+ *flag = TRUE;
+ } else if (elem->exclude_all) {
+ *flag = FALSE;
+ }else {
+ if (elem->id.uid == uid)
+ *flag = TRUE;
+ }
+ break;
+
+ case POLICY_ELEMENT_TYPE_GID:
+ if (elem->include_all) {
+ *flag = TRUE;
+ } else if (elem->exclude_all) {
+ *flag = FALSE;
+ }else {
+ guint i;
+ for (i = 0; i < num_gids; i++) {
+ if (elem->id.gid == gid_list[i])
+ *flag = TRUE;
+ }
+ }
+ break;
+ }
+}
+
+PolicyResult
+policy_get_allowed_resources_for_policy_for_uid_gid (uid_t uid,
+ guint num_gids,
+ gid_t *gid_list,
+ const char *policy,
+ GList **result)
+{
+ GList *l;
+ GList *whitelist;
+ GList *blacklist;
+ gboolean is_in_whitelist;
+ gboolean is_in_blacklist;
+ PolicyResult res;
+
+ whitelist = NULL;
+ blacklist = NULL;
+ *result = NULL;
+ res = POLICY_RESULT_ERROR;
+
+ res = policy_get_whitelist (policy, &whitelist);
+ if (res != POLICY_RESULT_OK)
+ goto out;
+
+ res = policy_get_blacklist (policy, &blacklist);
+ if (res != POLICY_RESULT_OK)
+ goto out;
+
+ is_in_whitelist = FALSE;
+ is_in_blacklist = FALSE;
+
+ /* Algorithm: check each resource in whitelist;
+ * if allowed, check against blacklist..
+ * if not in blacklist, push to results
+ */
+
+ for (l = whitelist; l != NULL; l = g_list_next (l)) {
+ PolicyElement *elem;
+ gboolean in_whitelist;
+ elem = (PolicyElement *) l->data;
+
+ if (elem->resource != NULL) {
+ /* check if we're allowed for this resource */
+ afp_process_elem (elem, &in_whitelist, uid, num_gids, gid_list);
+ if (in_whitelist) {
+ GList *j;
+ gboolean in_blacklist;
+
+ /* in whitelist.. yes.. now check if this resource is in the black list*/
+
+ in_blacklist = FALSE;
+
+ for (j = blacklist; j != NULL; j = g_list_next (j)) {
+ PolicyElement *elem2;
+ elem2 = (PolicyElement *) j->data;
+
+ if (elem2->resource != NULL &&
+ strcmp (elem->resource, elem2->resource) == 0) {
+ afp_process_elem (elem2, &in_blacklist, uid, num_gids, gid_list);
+ if (in_blacklist)
+ break;
+ }
+ }
+
+ if (in_whitelist && !in_blacklist)
+ *result = g_list_append (*result, g_strdup (elem->resource));
+ }
+ }
+ }
+
+
+ res = POLICY_RESULT_OK;
+
+out:
+ if (whitelist != NULL)
+ policy_element_free_list (whitelist);
+ if (blacklist != NULL)
+ policy_element_free_list (blacklist);
+
+ return res;
+}
+
+PolicyResult
+policy_is_uid_gid_allowed_for_policy (uid_t uid,
+ guint num_gids,
+ gid_t *gid_list,
+ const char *policy,
+ const char *resource,
+ gboolean *result)
+{
+ gboolean is_in_whitelist;
+ gboolean is_in_blacklist;
+ GList *l;
+ GList *whitelist;
+ GList *blacklist;
+ PolicyResult res;
+
+ whitelist = NULL;
+ blacklist = NULL;
+ res = POLICY_RESULT_ERROR;
+
+ res = policy_get_whitelist (policy, &whitelist);
+ if (res != POLICY_RESULT_OK)
+ goto out;
+
+ res = policy_get_blacklist (policy, &blacklist);
+ if (res != POLICY_RESULT_OK)
+ goto out;
+
+ is_in_whitelist = FALSE;
+ is_in_blacklist = FALSE;
+
+ /* Algorithm: To succeed.. we must be in the whitelist.. and not in the blacklist */
+
+ for (l = whitelist; l != NULL; l = g_list_next (l)) {
+ PolicyElement *elem;
+ elem = (PolicyElement *) l->data;
+ if ((elem->resource == NULL) ||
+ ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
+ afp_process_elem (elem, &is_in_whitelist, uid, num_gids, gid_list);
+ }
+ }
+
+ for (l = blacklist; l != NULL; l = g_list_next (l)) {
+ PolicyElement *elem;
+ elem = (PolicyElement *) l->data;
+ if ((elem->resource == NULL) ||
+ ((resource != NULL) && (strcmp (elem->resource, resource) == 0))) {
+ afp_process_elem (elem, &is_in_blacklist, uid, num_gids, gid_list);
+ }
+ }
+
+ *result = is_in_whitelist && (!is_in_blacklist);
+
+ res = POLICY_RESULT_OK;
+
+out:
+ if (whitelist != NULL)
+ policy_element_free_list (whitelist);
+ if (blacklist != NULL)
+ policy_element_free_list (blacklist);
+
+ return res;
+}
+
+char *
+policy_util_uid_to_name (uid_t uid,
+ gid_t *default_gid)
+{
+ int rc;
+ char *res;
+ char *buf = NULL;
+ unsigned int bufsize;
+ struct passwd pwd;
+ struct passwd *pwdp;
+
+ res = NULL;
+
+ bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
+ buf = g_new0 (char, bufsize);
+
+ rc = getpwuid_r (uid, &pwd, buf, bufsize, &pwdp);
+ if (rc != 0 || pwdp == NULL) {
+ /*g_warning ("getpwuid_r() returned %d", rc);*/
+ goto out;
+ }
+
+ res = g_strdup (pwdp->pw_name);
+ if (default_gid != NULL)
+ *default_gid = pwdp->pw_gid;
+
+out:
+ g_free (buf);
+ return res;
+}
+
+char *
+policy_util_gid_to_name (gid_t gid)
+{
+ int rc;
+ char *res;
+ char *buf = NULL;
+ unsigned int bufsize;
+ struct group gbuf;
+ struct group *gbufp;
+
+ res = NULL;
+
+ bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
+ buf = g_new0 (char, bufsize);
+
+ rc = getgrgid_r (gid, &gbuf, buf, bufsize, &gbufp);
+ if (rc != 0 || gbufp == NULL) {
+ /*g_warning ("getgrgid_r() returned %d", rc);*/
+ goto out;
+ }
+
+ res = g_strdup (gbufp->gr_name);
+
+out:
+ g_free (buf);
+ return res;
+}
+
+
+
+uid_t
+policy_util_name_to_uid (const char *username, gid_t *default_gid)
+{
+ int rc;
+ uid_t res;
+ char *buf = NULL;
+ unsigned int bufsize;
+ struct passwd pwd;
+ struct passwd *pwdp;
+
+ res = (uid_t) -1;
+
+ bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
+ buf = g_new0 (char, bufsize);
+
+ rc = getpwnam_r (username, &pwd, buf, bufsize, &pwdp);
+ if (rc != 0 || pwdp == NULL) {
+ /*g_warning ("getpwnam_r() returned %d", rc);*/
+ goto out;
+ }
+
+ res = pwdp->pw_uid;
+ if (default_gid != NULL)
+ *default_gid = pwdp->pw_gid;
+
+out:
+ g_free (buf);
+ return res;
+}
+
+gid_t
+policy_util_name_to_gid (const char *groupname)
+{
+ int rc;
+ gid_t res;
+ char *buf = NULL;
+ unsigned int bufsize;
+ struct group gbuf;
+ struct group *gbufp;
+
+ res = (gid_t) -1;
+
+ bufsize = sysconf (_SC_GETGR_R_SIZE_MAX);
+ buf = g_new0 (char, bufsize);
+
+ rc = getgrnam_r (groupname, &gbuf, buf, bufsize, &gbufp);
+ if (rc != 0 || gbufp == NULL) {
+ /*g_warning ("getgrnam_r() returned %d", rc);*/
+ goto out;
+ }
+
+ res = gbufp->gr_gid;
+
+out:
+ g_free (buf);
+ return res;
+}
+
+PolicyResult
+policy_get_allowed_resources_for_policy_for_uid (uid_t uid,
+ const char *policy,
+ GList **result)
+{
+ int num_groups = 0;
+ gid_t *groups = NULL;
+ char *username;
+ gid_t default_gid;
+ PolicyResult r;
+
+ r = POLICY_RESULT_ERROR;
+
+ if ((username = policy_util_uid_to_name (uid, &default_gid)) == NULL)
+ goto out;
+
+ if (getgrouplist(username, default_gid, NULL, &num_groups) < 0) {
+ groups = (gid_t *) g_new0 (gid_t, num_groups);
+ if (getgrouplist(username, default_gid, groups, &num_groups) < 0) {
+ g_warning ("getgrouplist() failed");
+ goto out;
+ }
+ }
+
+ r = policy_get_allowed_resources_for_policy_for_uid_gid (uid,
+ num_groups,
+ groups,
+ policy,
+ result);
+
+out:
+ g_free (username);
+ g_free (groups);
+ return r;
+}
+
+PolicyResult
+policy_is_uid_allowed_for_policy (uid_t uid,
+ const char *policy,
+ const char *resource,
+ gboolean *result)
+{
+ int num_groups = 0;
+ gid_t *groups = NULL;
+ char *username;
+ gid_t default_gid;
+ PolicyResult r;
+
+ r = POLICY_RESULT_ERROR;
+
+ if ((username = policy_util_uid_to_name (uid, &default_gid)) == NULL)
+ goto out;
+
+ if (getgrouplist(username, default_gid, NULL, &num_groups) < 0) {
+ groups = (gid_t *) g_new0 (gid_t, num_groups);
+ if (getgrouplist(username, default_gid, groups, &num_groups) < 0) {
+ g_warning ("getgrouplist() failed");
+ goto out;
+ }
+ }
+
+ r = policy_is_uid_gid_allowed_for_policy (uid,
+ num_groups,
+ groups,
+ policy,
+ resource,
+ result);
+
+out:
+ g_free (username);
+ g_free (groups);
+ return r;
+}
+
+
+#ifndef HAVE_GETGROUPLIST
+/* Get group list for the named user.
+ * Return up to ngroups in the groups array.
+ * Return actual number of groups in ngroups.
+ * Return -1 if more groups found than requested.
+ */
+int
+getgrouplist (const char *name, int baseid, int *groups, int *ngroups)
+{
+ struct group *g;
+ int n = 0;
+ int i;
+ int ret;
+
+ if (*ngroups <= 0) {
+ return (-1);
+ }
+
+ *groups++ = baseid;
+ n++;
+
+ setgrent ();
+ while ((g = getgrent ()) != NULL) {
+ for (i = 0; g->gr_mem[i]; i++) {
+ if (strcmp (name, g->gr_mem[0]) == 0) {
+ *groups++ = g->gr_gid;
+ if (++n > *ngroups) {
+ break;
+ }
+ }
+ }
+ }
+ endgrent ();
+
+ ret = (n > *ngroups) ? -1 : n;
+ *ngroups = n;
+ return (ret);
+}
+#endif
diff --git a/polkitd/policy.h b/polkitd/policy.h
new file mode 100644
index 0000000..11865ea
--- /dev/null
+++ b/polkitd/policy.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * policy.h : Wraps policy
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef POLICY_H
+#define POLICY_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib.h>
+
+typedef enum {
+ POLICY_RESULT_OK,
+ POLICY_RESULT_ERROR,
+ POLICY_RESULT_NO_SUCH_POLICY
+} PolicyResult;
+
+PolicyResult policy_get_policies (GList **result);
+
+PolicyResult policy_is_uid_allowed_for_policy (uid_t uid,
+ const char *policy,
+ const char *resource,
+ gboolean *result);
+
+PolicyResult policy_get_allowed_resources_for_policy_for_uid (uid_t uid,
+ const char *policy,
+ GList **result);
+
+PolicyResult policy_get_allowed_resources_for_policy_for_uid_gid (uid_t uid,
+ guint num_gids,
+ gid_t *gid_list,
+ const char *policy,
+ GList **result);
+
+PolicyResult policy_is_uid_gid_allowed_for_policy (uid_t uid,
+ guint num_gids,
+ gid_t *gid_list,
+ const char *policy,
+ const char *resource,
+ gboolean *result);
+
+char *policy_util_uid_to_name (uid_t uid,
+ gid_t *default_gid);
+
+char *policy_util_gid_to_name (gid_t gid);
+
+uid_t policy_util_name_to_uid (const char *username,
+ gid_t *default_gid);
+
+gid_t policy_util_name_to_gid (const char *groupname);
+
+void policy_util_set_policy_directory (const char *directory);
+
+#endif /* POLICY_H */
+
+
diff --git a/polkitd/polkit-manager.c b/polkitd/polkit-manager.c
new file mode 100644
index 0000000..733f89e
--- /dev/null
+++ b/polkitd/polkit-manager.c
@@ -0,0 +1,720 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-manager.c : Manager object
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <string.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "polkit-marshal.h"
+#include "polkit-manager.h"
+#include "polkit-session.h"
+
+#include "policy.h"
+
+typedef struct
+{
+ uid_t user;
+ char *privilege;
+ char *resource;
+ pid_t pid_restriction;
+} TemporaryPrivilege;
+
+struct PolicyKitManagerPrivate
+{
+ DBusGConnection *connection;
+ DBusGProxy *bus_proxy;
+
+ GList *temporary_privileges;
+
+ GHashTable *connection_name_to_caller_info;
+
+ GHashTable *connection_name_to_session_object;
+};
+
+G_DEFINE_TYPE(PolicyKitManager, polkit_manager, G_TYPE_OBJECT)
+
+static GObjectClass *parent_class = NULL;
+
+
+typedef struct {
+ uid_t uid;
+ pid_t pid;
+} CallerInfo;
+
+static void
+caller_info_delete (gpointer data)
+{
+ CallerInfo *caller_info = (CallerInfo *) data;
+ g_free (caller_info);
+}
+
+static void
+polkit_manager_init (PolicyKitManager *manager)
+{
+ manager->priv = g_new0 (PolicyKitManagerPrivate, 1);
+ manager->priv->connection = NULL;
+ manager->priv->temporary_privileges = NULL;
+
+ manager->priv->connection_name_to_caller_info = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ caller_info_delete);
+
+ manager->priv->connection_name_to_session_object = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+}
+
+static void
+polkit_manager_finalize (PolicyKitManager *manager)
+{
+ dbus_g_connection_unref (manager->priv->connection);
+
+ g_hash_table_destroy (manager->priv->connection_name_to_caller_info);
+
+ g_free (manager->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (manager));
+}
+
+static void
+polkit_manager_class_init (PolicyKitManagerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = (GObjectFinalizeFunc) polkit_manager_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+GQuark
+polkit_manager_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0)
+ ret = g_quark_from_static_string ("PolkitManagerObjectErrorQuark");
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+polkit_manager_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_USER, "NoSuchUser"),
+ ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE, "NoSuchPrivilege"),
+ ENUM_ENTRY (POLKIT_MANAGER_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
+ ENUM_ENTRY (POLKIT_MANAGER_ERROR_ERROR, "Error"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (POLKIT_MANAGER_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("PolkitManagerError", values);
+ }
+
+ return etype;
+}
+
+
+static void
+bus_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *service_name,
+ const char *old_service_name,
+ const char *new_service_name,
+ gpointer user_data)
+{
+ PolicyKitManager *manager = POLKIT_MANAGER (user_data);
+
+ /* track disconnects of clients */
+
+ if (strlen (new_service_name) == 0) {
+ CallerInfo *caller_info;
+ PolicyKitSession *session;
+
+ /* evict CallerInfo from cache */
+ caller_info = (CallerInfo *) g_hash_table_lookup (manager->priv->connection_name_to_caller_info,
+ old_service_name);
+ if (caller_info != NULL) {
+ g_hash_table_remove (manager->priv->connection_name_to_caller_info, old_service_name);
+ }
+
+ /* session object */
+ session = POLKIT_SESSION (g_hash_table_lookup (manager->priv->connection_name_to_session_object,
+ old_service_name));
+ if (session != NULL) {
+ /* possibly revoke temporary privileges granted */
+ polkit_session_initiator_disconnected (session);
+
+ /* end the session */
+ g_object_unref (session);
+
+ g_hash_table_remove (manager->priv->connection_name_to_session_object, old_service_name);
+ }
+ }
+
+ /*g_message ("NameOwnerChanged: service_name='%s', old_service_name='%s' new_service_name='%s'",
+ service_name, old_service_name, new_service_name);*/
+
+}
+
+
+static gboolean
+session_remover (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ if (value == user_data) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+session_finalized (gpointer data,
+ GObject *where_the_object_was)
+{
+ PolicyKitManager *manager = POLKIT_MANAGER (data);
+
+ g_hash_table_foreach_remove (manager->priv->connection_name_to_session_object,
+ session_remover,
+ where_the_object_was);
+}
+
+PolicyKitManager *
+polkit_manager_new (DBusGConnection *connection, DBusGProxy *bus_proxy)
+{
+ PolicyKitManager *manager;
+
+ manager = g_object_new (POLKIT_TYPE_MANAGER, NULL);
+ manager->priv->connection = dbus_g_connection_ref (connection);
+ dbus_g_connection_register_g_object (manager->priv->connection,
+ "/org/freedesktop/PolicyKit/Manager",
+ G_OBJECT (manager));
+
+ manager->priv->bus_proxy = bus_proxy;
+
+ dbus_g_object_register_marshaller (polkit_marshal_VOID__STRING_STRING_STRING,
+ G_TYPE_NONE,
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (bus_proxy, "NameOwnerChanged", G_CALLBACK (bus_name_owner_changed),
+ manager, NULL);
+
+ return manager;
+}
+
+
+static uid_t
+uid_from_username (const char *user)
+{
+ uid_t uid;
+
+ if (g_ascii_isdigit (user[0])) {
+ char *endp;
+ uid = (uid_t) g_ascii_strtoull (user, &endp, 0);
+ if (endp[0] != '\0') {
+ uid = (uid_t) -1;
+ }
+ } else {
+ uid = policy_util_name_to_uid (user, NULL);
+ }
+
+ return uid;
+}
+
+/* remote methods */
+
+static int
+safe_strcmp (const char *s1, const char *s2)
+{
+ if (s1 == NULL || s2 == NULL)
+ return 0;
+ else
+ return strcmp (s1, s2);
+}
+
+gboolean
+polkit_manager_get_caller_info (PolicyKitManager *manager,
+ const char *sender,
+ uid_t *calling_uid,
+ pid_t *calling_pid)
+{
+ gboolean res;
+ CallerInfo *caller_info;
+ GError *error = NULL;
+
+ res = FALSE;
+
+ if (sender == NULL)
+ goto out;
+
+ caller_info = g_hash_table_lookup (manager->priv->connection_name_to_caller_info,
+ sender);
+ if (caller_info != NULL) {
+
+ res = TRUE;
+ *calling_uid = caller_info->uid;
+ *calling_pid = caller_info->pid;
+ /*g_message ("uid = %d (cached)", *calling_uid);
+ g_message ("pid = %d (cached)", *calling_pid);*/
+ goto out;
+ }
+
+ if (!dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixUser", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_uid,
+ G_TYPE_INVALID)) {
+ g_warning ("GetConnectionUnixUser() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (!dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionUnixProcessID", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_pid,
+ G_TYPE_INVALID)) {
+ g_warning ("GetConnectionUnixProcessID() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ caller_info = g_new0 (CallerInfo, 1);
+ caller_info->uid = *calling_uid;
+ caller_info->pid = *calling_pid;
+
+ g_hash_table_insert (manager->priv->connection_name_to_caller_info,
+ g_strdup (sender),
+ caller_info);
+
+ res = TRUE;
+
+ /*g_message ("uid = %d", *calling_uid);
+ g_message ("pid = %d", *calling_pid);*/
+
+out:
+ return res;
+}
+
+gboolean
+polkit_manager_initiate_privilege_grant (PolicyKitManager *manager,
+ char *user,
+ char *privilege,
+ char *resource,
+ DBusGMethodInvocation *context)
+{
+ uid_t calling_uid;
+ pid_t calling_pid;
+ uid_t uid;
+ PolicyKitSession *session;
+ char *sender;
+
+ /* TODO: need to handle limit number of session to prevent DOS.
+ * Or is dbus-daemon sufficient for that; I think so..
+ */
+
+ if (!polkit_manager_get_caller_info (manager,
+ dbus_g_method_get_sender (context),
+ &calling_uid,
+ &calling_pid)) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ sender = dbus_g_method_get_sender (context);
+
+ uid = uid_from_username (user);
+
+ if (uid == (uid_t) -1) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NO_SUCH_USER,
+ "There is no user '%s'.",
+ user));
+ return FALSE;
+ }
+
+ session = polkit_session_new (manager->priv->connection,
+ manager,
+ calling_uid,
+ calling_pid,
+ sender,
+ uid,
+ privilege,
+ strlen (resource) > 0 ? resource : NULL);
+
+ g_object_weak_ref (G_OBJECT (session),
+ session_finalized,
+ manager);
+
+ g_hash_table_insert (manager->priv->connection_name_to_session_object,
+ sender,
+ session);
+
+ //g_timeout_add (5 * 1000, destroy_session_after_timeout, session);
+
+ dbus_g_method_return (context,
+ g_strdup (((char *) g_object_get_data (G_OBJECT (session), "dbus_glib_object_path"))));
+ return TRUE;
+}
+
+gboolean
+polkit_manager_is_user_privileged (PolicyKitManager *manager,
+ int pid,
+ char *user,
+ char *privilege,
+ char *resource,
+ DBusGMethodInvocation *context)
+{
+ uid_t calling_uid;
+ pid_t calling_pid;
+ uid_t uid;
+ PolicyResult res;
+ gboolean is_privileged;
+
+
+ if (!polkit_manager_get_caller_info (manager,
+ dbus_g_method_get_sender (context),
+ &calling_uid,
+ &calling_pid)) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ is_privileged = FALSE;
+
+ uid = uid_from_username (user);
+
+ if (uid == (uid_t) -1) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NO_SUCH_USER,
+ "There is no user '%s'.",
+ user));
+ return FALSE;
+ }
+
+ /* TODO: check if given uid is privileged to ask for this */
+ if (FALSE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
+ "You are not authorized to know this."));
+ return FALSE;
+ }
+
+ res = policy_is_uid_allowed_for_policy (uid,
+ privilege,
+ strlen (resource) > 0 ? resource : NULL,
+ &is_privileged);
+ switch (res) {
+ case POLICY_RESULT_OK:
+ break;
+
+ case POLICY_RESULT_NO_SUCH_POLICY:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE,
+ "There is no such privilege '%s'.",
+ privilege));
+ return FALSE;
+
+ default: /* explicit fallthrough */
+ case POLICY_RESULT_ERROR:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ /* check temporary lists */
+ if (!is_privileged) {
+ GList *i;
+ TemporaryPrivilege *p;
+
+ for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
+ p = (TemporaryPrivilege *) i->data;
+ gboolean res_match;
+
+ if (strlen (resource) == 0)
+ res_match = (p->resource == NULL);
+ else
+ res_match = (safe_strcmp (p->resource, resource) == 0);
+
+ if ((strcmp (p->privilege, privilege) == 0) &&
+ res_match &&
+ (p->user == uid) &&
+ ((p->pid_restriction == -1) || (p->pid_restriction == pid))) {
+
+ is_privileged = TRUE;
+ break;
+ }
+ }
+ }
+
+ dbus_g_method_return (context, is_privileged);
+
+ return TRUE;
+}
+
+
+gboolean
+polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager *manager,
+ char *user,
+ char *privilege,
+ DBusGMethodInvocation *context)
+{
+ uid_t calling_uid;
+ pid_t calling_pid;
+ int n;
+ GList *i;
+ GList *resources;
+ uid_t uid;
+ PolicyResult res;
+ TemporaryPrivilege *p;
+ char **resource_list;
+
+ if (!polkit_manager_get_caller_info (manager,
+ dbus_g_method_get_sender (context),
+ &calling_uid,
+ &calling_pid)) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ uid = uid_from_username (user);
+
+ if (uid == (uid_t) -1) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NO_SUCH_USER,
+ "There is no user '%s'.",
+ user));
+ return FALSE;
+ }
+
+ /* TODO: check if given uid is privileged to ask for this */
+ if (FALSE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
+ "You are not authorized to know this."));
+ return FALSE;
+ }
+
+
+ res = policy_get_allowed_resources_for_policy_for_uid (uid,
+ privilege,
+ &resources);
+ switch (res) {
+ case POLICY_RESULT_OK:
+ break;
+
+ case POLICY_RESULT_NO_SUCH_POLICY:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE,
+ "There is no such privilege '%s'.",
+ privilege));
+ return FALSE;
+
+ default: /* explicit fallthrough */
+ case POLICY_RESULT_ERROR:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ /* check temporary list */
+ for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
+ p = (TemporaryPrivilege *) i->data;
+
+ if ((strcmp (p->privilege, privilege) == 0) &&
+ (p->resource != NULL) &&
+ (p->user == uid) &&
+ (p->pid_restriction == -1)) {
+ resources = g_list_append (resources, g_strdup (p->resource));
+ }
+ }
+
+ resource_list = g_new0 (char *, g_list_length (resources) + 1);
+ for (i = resources, n = 0; i != NULL; i = g_list_next (i)) {
+ char *resource = (char *) i->data;
+ resource_list[n++] = g_strdup (resource);
+ }
+ resource_list[n] = NULL;
+
+ g_list_foreach (resources, (GFunc) g_free, NULL);
+ g_list_free (resources);
+
+ dbus_g_method_return (context, resource_list);
+
+ return TRUE;
+}
+
+gboolean
+polkit_manager_list_privileges (PolicyKitManager *manager,
+ DBusGMethodInvocation *context)
+{
+ uid_t calling_uid;
+ pid_t calling_pid;
+ int n;
+ GList *i;
+ GList *privileges;
+ PolicyResult res;
+ char **privilege_list;
+
+
+ if (!polkit_manager_get_caller_info (manager,
+ dbus_g_method_get_sender (context),
+ &calling_uid,
+ &calling_pid)) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ /* TODO: check if given uid is privileged to ask for this */
+ if (FALSE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_NOT_PRIVILEGED,
+ "You are not authorized to know this."));
+ return FALSE;
+ }
+
+ res = policy_get_policies (&privileges);
+ switch (res) {
+ case POLICY_RESULT_OK:
+ break;
+
+ default: /* explicit fallthrough */
+ case POLICY_RESULT_ERROR:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_MANAGER_ERROR,
+ POLKIT_MANAGER_ERROR_ERROR,
+ "An error occured."));
+ return FALSE;
+ }
+
+ privilege_list = g_new0 (char *, g_list_length (privileges) + 1);
+ for (i = privileges, n = 0; i != NULL; i = g_list_next (i)) {
+ char *privilege = (char *) i->data;
+ privilege_list[n++] = g_strdup (privilege);
+ }
+ privilege_list[n] = NULL;
+
+ g_list_foreach (privileges, (GFunc) g_free, NULL);
+ g_list_free (privileges);
+
+ dbus_g_method_return (context, privilege_list);
+
+ return TRUE;
+}
+
+/* local methods */
+
+
+gboolean
+polkit_manager_add_temporary_privilege (PolicyKitManager *manager,
+ uid_t user,
+ const char *privilege,
+ const char *resource,
+ pid_t pid_restriction)
+{
+ GList *i;
+ TemporaryPrivilege *p;
+
+ for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
+ p = (TemporaryPrivilege *) i->data;
+
+ if ((strcmp (p->privilege, privilege) == 0) &&
+ (safe_strcmp (p->resource, resource) == 0) &&
+ (p->user == user) &&
+ (p->pid_restriction == pid_restriction))
+ return FALSE;
+ }
+
+ p = g_new0 (TemporaryPrivilege, 1);
+ p->user = user;
+ p->privilege = g_strdup (privilege);
+ p->resource = g_strdup (resource);
+ p->pid_restriction = pid_restriction;
+
+ manager->priv->temporary_privileges = g_list_append (manager->priv->temporary_privileges, p);
+
+ return TRUE;
+}
+
+gboolean
+polkit_manager_remove_temporary_privilege (PolicyKitManager *manager,
+ uid_t user,
+ const char *privilege,
+ const char *resource,
+ pid_t pid_restriction)
+{
+ GList *i;
+ TemporaryPrivilege *p;
+
+ for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) {
+ p = (TemporaryPrivilege *) i->data;
+
+ if ((strcmp (p->privilege, privilege) == 0) &&
+ (safe_strcmp (p->resource, resource) == 0) &&
+ (p->user == user) &&
+ (p->pid_restriction == pid_restriction)) {
+
+ g_free (p->privilege);
+ g_free (p->resource);
+
+ manager->priv->temporary_privileges = g_list_remove (
+ manager->priv->temporary_privileges, p);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/polkitd/polkit-manager.h b/polkitd/polkit-manager.h
new file mode 100644
index 0000000..51dd6d6
--- /dev/null
+++ b/polkitd/polkit-manager.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-manager.h : Manager object
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef _POLKIT_MANAGER_H
+#define _POLKIT_MANAGER_H
+
+#include <unistd.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+GQuark polkit_manager_error_quark (void);
+
+#define POLKIT_MANAGER_ERROR (polkit_manager_error_quark ())
+
+typedef enum
+{
+ POLKIT_MANAGER_ERROR_NO_SUCH_USER = 0,
+ POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE = 1,
+ POLKIT_MANAGER_ERROR_NOT_PRIVILEGED = 2,
+ POLKIT_MANAGER_ERROR_ERROR = 3,
+ POLKIT_MANAGER_NUM_ERRORS
+} PolkitManagerError;
+
+GType polkit_manager_error_get_type (void);
+#define POLKIT_MANAGER_TYPE_ERROR (polkit_manager_error_get_type ())
+
+typedef struct PolicyKitManager PolicyKitManager;
+typedef struct PolicyKitManagerClass PolicyKitManagerClass;
+
+GType polkit_manager_get_type (void);
+
+typedef struct PolicyKitManagerPrivate PolicyKitManagerPrivate;
+
+struct PolicyKitManager
+{
+ GObject parent;
+
+ PolicyKitManagerPrivate *priv;
+};
+
+struct PolicyKitManagerClass
+{
+ GObjectClass parent;
+};
+
+#define POLKIT_TYPE_MANAGER (polkit_manager_get_type ())
+#define POLKIT_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), POLKIT_TYPE_MANAGER, PolicyKitManager))
+#define POLKIT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POLKIT_TYPE_MANAGER, PolicyKitManagerClass))
+#define POLKIT_IS_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), POLKIT_TYPE_MANAGER))
+#define POLKIT_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POLKIT_TYPE_MANAGER))
+#define POLKIT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), POLKIT_TYPE_MANAGER, PolicyKitManagerClass))
+
+PolicyKitManager *polkit_manager_new (DBusGConnection *connection,
+ DBusGProxy *bus_proxy);
+
+/* remote methods */
+
+gboolean polkit_manager_initiate_privilege_grant (PolicyKitManager *manager,
+ char *user,
+ char *privilege,
+ char *resource,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_manager_is_user_privileged (PolicyKitManager *manager,
+ int pid,
+ char *user,
+ char *privilege,
+ char *resource,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager *manager,
+ char *user,
+ char *privilege,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_manager_list_privileges (PolicyKitManager *manager,
+ DBusGMethodInvocation *context);
+
+/* local methods */
+
+gboolean polkit_manager_get_caller_info (PolicyKitManager *manager,
+ const char *sender,
+ uid_t *calling_uid,
+ pid_t *calling_pid);
+
+
+gboolean polkit_manager_add_temporary_privilege (PolicyKitManager *manager,
+ uid_t user,
+ const char *privilege,
+ const char *resource,
+ pid_t pid_restriction);
+
+gboolean polkit_manager_remove_temporary_privilege (PolicyKitManager *manager,
+ uid_t user,
+ const char *privilege,
+ const char *resource,
+ pid_t pid_restriction);
+
+#endif /* _POLKIT_MANAGER_H */
diff --git a/polkitd/polkit-marshal.list b/polkitd/polkit-marshal.list
new file mode 100644
index 0000000..41e4027
--- /dev/null
+++ b/polkitd/polkit-marshal.list
@@ -0,0 +1 @@
+VOID:STRING,STRING,STRING
diff --git a/polkitd/polkit-session.c b/polkitd/polkit-session.c
new file mode 100644
index 0000000..2356bdf
--- /dev/null
+++ b/polkitd/polkit-session.c
@@ -0,0 +1,1003 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-session.c : Session object
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <security/pam_appl.h>
+
+#include "polkit-session.h"
+
+enum
+{
+ AUTH_STATE_NOT_STARTED,
+ AUTH_STATE_IN_PROGRESS,
+ AUTH_STATE_HAVE_QUESTIONS,
+ AUTH_STATE_NEED_ANSWERS,
+ AUTH_STATE_DONE
+};
+
+struct PolicyKitSessionPrivate
+{
+ int session_number;
+ DBusGConnection *connection;
+ DBusGProxy *proxy;
+ PolicyKitManager *manager;
+
+ char *auth_as_user;
+ char *auth_with_pam_service;
+
+ uid_t calling_uid;
+ pid_t calling_pid;
+ char *calling_dbus_name;
+
+ uid_t grant_to_uid;
+ char *grant_privilege;
+ char *grant_resource;
+ pid_t grant_pid_restriction;
+
+ gboolean have_granted_temp_privileges;
+
+ int auth_state;
+ gboolean is_authenticated;
+ char *auth_denied_reason;
+ GSList *auth_questions;
+
+ GPid child_pid;
+ GIOChannel *pam_channel;
+ GIOChannel *pam_channel_write;
+};
+
+enum
+{
+ HAVE_QUESTIONS,
+ AUTHENTICATION_DONE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE(PolicyKitSession, polkit_session, G_TYPE_OBJECT)
+
+static GObjectClass *parent_class = NULL;
+
+static void
+polkit_session_init (PolicyKitSession *session)
+{
+ session->priv = g_new0 (PolicyKitSessionPrivate, 1);
+ session->priv->session_number = 42;
+ session->priv->is_authenticated = FALSE;
+ session->priv->auth_state = AUTH_STATE_NOT_STARTED;
+}
+
+static void
+polkit_session_finalize (PolicyKitSession *session)
+{
+ g_io_channel_unref (session->priv->pam_channel);
+ g_io_channel_unref (session->priv->pam_channel_write);
+ dbus_g_connection_unref (session->priv->connection);
+
+ g_free (session->priv->auth_as_user);
+ g_free (session->priv->auth_with_pam_service);
+
+ g_free (session->priv->calling_dbus_name);
+
+ g_free (session->priv->grant_privilege);
+ g_free (session->priv->grant_resource);
+
+ g_free (session->priv->auth_denied_reason);
+ if (session->priv->auth_questions != NULL) {
+ //g_slist_foreach (session->priv->auth_questions, (GFunc) g_free, NULL);
+ //g_free (session->priv->auth_questions);
+ }
+ g_free (session->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (session));
+}
+
+static void
+polkit_session_class_init (PolicyKitSessionClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ signals[HAVE_QUESTIONS] =
+ g_signal_new ("have_questions",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[AUTHENTICATION_DONE] =
+ g_signal_new ("authentication_done",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+
+ gobject_class->finalize = (GObjectFinalizeFunc) polkit_session_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+
+GQuark
+polkit_session_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0)
+ ret = g_quark_from_static_string ("PolkitSessionObjectErrorQuark");
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+polkit_session_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_AUTHENTICATION_IN_PROGRESS, "AuthenticationInProgress"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_AUTHENTICATION_ALREADY_INITIATED, "AuthenticationAlreadyInitiated"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_NO_QUESTIONS, "AuthenticationNoQuestions"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_AUTHENTICATION_WAS_NOT_DENIED, "AuthenticationWasNotDenied"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_NO_RESOURCES, "NoResources"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_AUTHENTICATION_NOT_DONE, "AuthenticationNotDone"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_AUTHENTICATION_FAILED, "AuthenticationFailed"),
+ ENUM_ENTRY (POLKIT_SESSION_ERROR_NOT_INITIATOR, "NotInitiator"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (POLKIT_SESSION_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("PolkitSessionError", values);
+ }
+
+ return etype;
+}
+
+
+static gboolean
+polkit_session_check_caller (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ char *sender;
+ gboolean same_caller;
+
+ same_caller = FALSE;
+
+ sender = dbus_g_method_get_sender (context);
+ if (sender != NULL) {
+ if (strcmp (session->priv->calling_dbus_name, sender) == 0) {
+ same_caller = TRUE;
+ }
+ }
+
+ if (!same_caller) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_NOT_INITIATOR,
+ "Only the session initiator can invoke methods on this interface. This incident will be reported."));
+ /* TODO: log this attack to syslog */
+ }
+
+ return same_caller;
+}
+
+gboolean
+polkit_session_is_authenticated (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ /*g_debug ("is_authenticated");*/
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (session->priv->auth_state != AUTH_STATE_DONE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_IN_PROGRESS,
+ "This method cannot be invoked before the AuthenticationDone signal is emitted."));
+ return FALSE;
+ }
+
+ dbus_g_method_return (context, session->priv->is_authenticated);
+ return TRUE;
+}
+
+gboolean
+polkit_session_get_auth_denied_reason (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ /*g_debug ("get_auth_denied_reason");*/
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (session->priv->auth_state != AUTH_STATE_DONE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_IN_PROGRESS,
+ "This method cannot be invoked before the AuthenticationDone signal is emitted."));
+ return FALSE;
+ }
+
+ if (session->priv->is_authenticated) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_WAS_NOT_DENIED,
+ "The authentication was not denied."));
+ return FALSE;
+ }
+
+ dbus_g_method_return (context, session->priv->auth_denied_reason);
+ return TRUE;
+}
+
+
+/*
+ * Interaction diagram
+ * -------------------
+ *
+ * some app polkitd
+ * ======== =======
+ *
+ * -> manager.InitiatePrivilegeGrant(user, privilege, resource) ->
+ * <- Returns session object <-
+ *
+ * -> session.GetAuthDetails() ->
+ * <- Returns {<username we auth as>, <service_name used> ...} <- # can we include what pam module? prolly not
+ *
+ * -> session.InitiateAuth() ->
+ * <- Returns TRUE <-
+ *
+ * # app now waits for the AuthenticationDone()
+ * # or HaveQuestions() signals
+ * .....
+ *
+ * <- signal: HaveQuestions() <-
+ *
+ * -> session.GetQuestions() ->
+ * <- Returns {question_1, question_2, ...} <-
+ *
+ * -> session.ProvideAnswers({answer_1, answer_2, ...}) ->
+ * <- Returns TRUE <-
+ *
+ * .....
+ *
+ * <- signal: AuthenticationDone() <-
+ *
+ * .....
+ *
+ * -> session.IsAuthenticated() ->
+ * <- Returns TRUE or FALSE <-
+ *
+ * .....
+ *
+ * -> session.GetAuthFailureReason() -> # Only if IsAuthenticated() returns FALSE
+ * <- Returns <reason as string> <-
+ *
+ * .....
+ *
+ * Assume now IsAuthenticated() returned TRUE. There are a few different
+ * scenarios.
+ *
+ *
+ * SCENARIO 1: App needs the privilege only temporarily; e.g. not persistent
+ * across reboots. The app may even restrict users of the privilege
+ * to his own process id. The app may ask for the privilege to
+ * not be revoked when it ends the session - if the app should
+ * disconnect from the bus before session.Close() the privilege
+ * is revoked though.
+ *
+ * Example: gnome-mount needs privs to do work, restricts the
+ * privs to it's own PID and asks for revocation when
+ * it's done with it's work.
+ *
+ * Example: g-d-m temporarily gives the privilege 'local-console-user'
+ * when a new desktop session starts. It manually revokes
+ * this when the session ends.
+ *
+ * -> session.GrantPrivilegeTemporary(bool restrictToCallersPID) -> # add uid, pid of client to the
+ * <- Returns TRUE <- # temp_allow_list
+ *
+ * .....
+ *
+ * (the app is now doing something useful with the privilege obtained)
+ *
+ * .....
+ *
+ * -> session.Close(bool doNotRevokePrivilege) ->
+ * <- Returns TRUE <- # Remove uid, pid of client from the
+ * # temp_allow_list IFF revokePrivile is true
+ */
+
+typedef struct {
+ int fd;
+ int fdread;
+} ConversationData;
+
+
+/* TODO: is this a secure way of clearing memory? */
+static void *
+safe_memset (void *buf, int c, size_t len)
+{
+ return memset (buf, c, len);
+}
+
+
+static int
+my_conversation (int n,
+ const struct pam_message **msg,
+ struct pam_response **resp,
+ void *data)
+{
+ GString *str;
+ ConversationData *cd = (ConversationData *) data;
+ struct pam_response *aresp;
+ int i;
+ int j;
+ int num_real_questions = 0;
+ int strl;
+ char *cstr;
+ int num_bytes_read;
+ char *p;
+ char readbuf[1024];
+ char **answers = NULL;
+ int num_answers;
+
+ /*g_debug ("in my_conv");*/
+
+ if (n <= 0 || n > PAM_MAX_NUM_MSG) {
+ return PAM_CONV_ERR;
+ }
+
+ if ((aresp = calloc (n, sizeof (struct pam_response))) == NULL) {
+ return PAM_BUF_ERR;
+ }
+
+ str = g_string_new ("Q");
+
+ for (i = 0; i < n; ++i) {
+ g_string_append_c (str, '\0');
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ g_string_append (str, "PamPromptEchoOff");
+ num_real_questions++;
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ g_string_append (str, "PamPromptEchoOn");
+ num_real_questions++;
+ break;
+ case PAM_ERROR_MSG:
+ g_string_append (str, "PamErrorMsg");
+ break;
+ case PAM_TEXT_INFO:
+ g_string_append (str, "PamTextInfo");
+ break;
+
+ default:
+ /* TODO */
+ break;
+ }
+ g_string_append_c (str, '\0');
+ g_string_append_printf (str, "%s", msg[i]->msg);
+ }
+
+ strl = str->len;
+ cstr = g_string_free (str, FALSE);
+ /*g_debug ("strlen = %d", strl);*/
+ write (cd->fd, (void *) cstr, (size_t) strl);
+ g_free (cstr);
+
+ answers = g_new0 (char *, num_real_questions + 1);
+
+ /* now wait for parent to write answers */
+ num_bytes_read = read (cd->fdread, readbuf, sizeof (readbuf));
+ /*g_debug ("actually read = %d", num_bytes_read);*/
+ p = readbuf;
+ num_answers = 0;
+ do {
+ if (num_answers > num_real_questions) {
+ g_warning ("num_answers > num_real_questions");
+ goto error;
+ }
+
+ answers [num_answers++] = g_strdup (p);
+ /*g_debug ("answer -> '%s'", p);*/
+
+ p = p + strlen(p) + 1;
+
+ } while (p < readbuf + num_bytes_read);
+ answers[num_answers] = NULL;
+
+ if (num_answers != num_real_questions) {
+ g_warning ("num_answers != num_real_questions");
+ goto error;
+ }
+
+ /*g_debug ("giving answers back to PAM");*/
+
+ j = 0;
+ for (i = 0; i < n; ++i) {
+ aresp[i].resp_retcode = 0;
+ aresp[i].resp = NULL;
+
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF: /* explicit fallthrough */
+ case PAM_PROMPT_ECHO_ON:
+ aresp[i].resp = strdup (answers[j++]);
+ break;
+
+ default:
+ /* explicitly left blank */
+ break;
+ }
+ }
+
+ /* zero out the secrets */
+ safe_memset (readbuf, 0, sizeof (readbuf));
+ if (answers != NULL) {
+ for (i = 0; answers[i] != NULL; i++) {
+ safe_memset (answers[i], 0, strlen (answers[i]));
+ }
+ g_strfreev (answers);
+ }
+
+ *resp = aresp;
+ return PAM_SUCCESS;
+
+error:
+ /* zero out the secrets */
+ safe_memset (readbuf, 0, sizeof (readbuf));
+ if (answers != NULL) {
+ for (i = 0; answers[i] != NULL; i++) {
+ safe_memset (answers[i], 0, strlen (answers[i]));
+ }
+ g_strfreev (answers);
+ }
+
+ /* prepare reply to PAM */
+ for (i = 0; i < n; ++i) {
+ if (aresp[i].resp != NULL) {
+ safe_memset (aresp[i].resp, 0, strlen(aresp[i].resp));
+ free (aresp[i].resp);
+ }
+ }
+ safe_memset (aresp, 0, n * sizeof (struct pam_response));
+ *resp = NULL;
+
+ return PAM_CONV_ERR;
+}
+
+static void
+write_back_to_parent (int fd, char code, const char *message)
+{
+ GString *str;
+ gsize strl;
+ char *cstr;
+
+ str = g_string_new ("");
+ g_string_append_c (str, code);
+ g_string_append_c (str, '\0');
+
+ if (message != NULL) {
+ g_string_append (str, message);
+ g_string_append_c (str, '\0');
+ }
+
+ strl = str->len;
+ cstr = g_string_free (str, FALSE);
+ write (fd, cstr, strl);
+ g_free (cstr);
+}
+
+static void
+do_pam_auth (int fd, int fdread, const PolicyKitSessionPrivate *priv)
+{
+ int rc;
+ struct pam_conv pam_conversation;
+ pam_handle_t *pam_h;
+ ConversationData d;
+ char *authed_user;
+
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ pam_conversation.conv = my_conversation;
+ pam_conversation.appdata_ptr = (void *) &d;
+ d.fd = fd;
+ d.fdread = fdread;
+
+ rc = pam_start (priv->auth_with_pam_service,
+ priv->auth_as_user,
+ &pam_conversation,
+ &pam_h);
+ if (rc != PAM_SUCCESS) {
+ g_warning ("pam_start failed: %s", pam_strerror (pam_h, rc));
+ write_back_to_parent (fd, 'F', pam_strerror (pam_h, rc));
+ goto out;
+ }
+
+
+ /*g_debug ("invoking pam_authenticate");*/
+
+ /* is user really user? */
+ rc = pam_authenticate (pam_h, 0);
+ if (rc != PAM_SUCCESS) {
+ g_warning ("pam_authenticated failed: %s", pam_strerror (pam_h, rc));
+ write_back_to_parent (fd, 'N', pam_strerror (pam_h, rc));
+ goto out;
+ }
+
+ /*g_debug ("invoking pam_acct_mgmt");*/
+
+ /* permitted access? */
+ rc = pam_acct_mgmt (pam_h, 0);
+ if (rc != PAM_SUCCESS) {
+ g_warning ("pam_acct_mgmt failed: %s", pam_strerror (pam_h, rc));
+ write_back_to_parent (fd, 'N', pam_strerror (pam_h, rc));
+ goto out;
+ }
+
+ /*g_debug ("checking we authed the right user");*/
+
+ rc = pam_get_item (pam_h, PAM_USER, (const void **) &authed_user);
+ if (rc != PAM_SUCCESS) {
+ g_warning ("pam_get_item failed: %s", pam_strerror (pam_h, rc));
+ write_back_to_parent (fd, 'N', pam_strerror (pam_h, rc));
+ goto out;
+ }
+
+ /*g_debug ("Authed user '%s'", authed_user);*/
+
+ if (strcmp (authed_user, priv->auth_as_user) != 0) {
+ char *err;
+ err = g_strdup_printf ("Tried to auth user '%s' but we got auth for user '%s' instead",
+ priv->auth_as_user, authed_user);
+ g_warning (err);
+ write_back_to_parent (fd, 'N', err);
+ g_free (err);
+ goto out;
+ }
+
+ /*g_debug ("user authenticated, exiting");*/
+ write_back_to_parent (fd, 'S', NULL);
+
+out:
+ exit (0);
+}
+
+static gboolean
+data_from_pam (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ PolicyKitSession *session = POLKIT_SESSION (data);
+
+ if (condition & G_IO_IN) {
+ char buf[1024];
+ gsize num_bytes_read;
+
+ /*g_debug ("in %s - data", __FUNCTION__);*/
+
+ g_io_channel_read (source,
+ buf,
+ sizeof (buf) - 1,
+ &num_bytes_read);
+ /*g_debug ("read %d bytes, first one is '%c' = %d", num_bytes_read, buf[0], buf[0]);*/
+ buf[num_bytes_read] = '\0';
+
+ switch (buf[0]) {
+ case 'F':
+ g_warning ("PAM failed: '%s'", buf + 2);
+ session->priv->auth_denied_reason = g_strdup (buf + 2);
+ session->priv->auth_state = AUTH_STATE_DONE;
+ g_signal_emit (session, signals[AUTHENTICATION_DONE], 0);
+ break;
+
+ case 'N':
+ g_warning ("Not authenticated: '%s'", buf + 2);
+ session->priv->auth_denied_reason = g_strdup (buf + 2);
+ session->priv->auth_state = AUTH_STATE_DONE;
+ g_signal_emit (session, signals[AUTHENTICATION_DONE], 0);
+ break;
+
+ case 'S':
+ /*g_debug ("Success, user authenticated");*/
+ session->priv->is_authenticated = TRUE;
+ session->priv->auth_state = AUTH_STATE_DONE;
+ g_signal_emit (session, signals[AUTHENTICATION_DONE], 0);
+ break;
+
+ case 'Q':
+ g_slist_foreach (session->priv->auth_questions, (GFunc) g_free, NULL);
+ g_slist_free (session->priv->auth_questions);
+ session->priv->auth_questions = NULL;
+
+ char *p = buf + 2;
+ do {
+ session->priv->auth_questions = g_slist_append (session->priv->auth_questions,
+ g_strdup (p));
+ /*g_debug ("p -> '%s'", p);*/
+ p = p + strlen(p) + 1;
+
+ } while (p < buf + num_bytes_read);
+
+ /*g_debug ("Put %d questions on list", g_slist_length (session->priv->auth_questions));*/
+
+ if ((g_slist_length (session->priv->auth_questions) & 1) != 0) {
+ g_warning ("Uneven number of question items from PAM; aborting conversation");
+ kill (session->priv->child_pid, SIGTERM);
+ session->priv->auth_state = AUTH_STATE_DONE;
+ session->priv->auth_denied_reason = g_strdup ("Unexpected internal PAM error");
+ g_signal_emit (session, signals[AUTHENTICATION_DONE], 0);
+ } else {
+ session->priv->auth_state = AUTH_STATE_HAVE_QUESTIONS;
+ g_signal_emit (session, signals[HAVE_QUESTIONS], 0);
+ }
+ break;
+
+ default:
+ /* left intentionally blank */
+ break;
+ }
+
+ }
+
+
+ if (condition & G_IO_HUP) {
+ /*g_debug ("in %s - hangup", __FUNCTION__);*/
+ if (session->priv->child_pid != 0) {
+ int status;
+ /*g_debug (" reaping child with pid %d", session->priv->child_pid);*/
+ session->priv->child_pid = 0;
+ waitpid (session->priv->child_pid, &status, 0);
+ }
+ /* remove the source */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+polkit_session_get_auth_details (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (session->priv->auth_state != AUTH_STATE_NOT_STARTED) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_ALREADY_INITIATED,
+ "This method cannot be invoked after InitiateAuth() is invoked."));
+ return FALSE;
+ }
+
+ dbus_g_method_return (context,
+ g_strdup (session->priv->auth_as_user),
+ g_strdup (session->priv->auth_with_pam_service));
+ return TRUE;
+}
+
+gboolean
+polkit_session_initiate_auth (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ int fds[2];
+ int fdsb[2];
+ pid_t pid;
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (session->priv->auth_state != AUTH_STATE_NOT_STARTED) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_ALREADY_INITIATED,
+ "Authentication already initiated."));
+ return FALSE;
+ }
+
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ /* pipe for parent reading from child */
+ if (pipe(fds) != 0) {
+ g_warning ("pipe() failed: %s", strerror (errno));
+ goto fail;
+ }
+
+ /* pipe for parent writing to child */
+ if (pipe(fdsb) != 0) {
+ g_warning ("pipe() failed: %s", strerror (errno));
+ goto fail;
+ }
+
+ switch (pid = fork()) {
+ case -1:
+ g_warning ("fork() failed: %s", strerror (errno));
+ goto fail;
+
+ case 0:
+ /* child; close unused ends */
+ close (fds[0]);
+ close (fdsb[1]);
+
+ do_pam_auth (fds[1], fdsb[0], session->priv);
+ break;
+
+ default:
+ session->priv->auth_state = AUTH_STATE_IN_PROGRESS;
+
+ /* parent; close unused ends */
+ close (fds[1]);
+ close (fdsb[0]);
+
+ session->priv->child_pid = (GPid) pid;
+ session->priv->pam_channel_write = g_io_channel_unix_new (fdsb[1]);
+ session->priv->pam_channel = g_io_channel_unix_new (fds[0]);
+
+ g_io_add_watch (session->priv->pam_channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ data_from_pam,
+ session);
+
+ break;
+ }
+
+ dbus_g_method_return (context);
+ return TRUE;
+
+fail:
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_NO_RESOURCES,
+ "InitiateAuth() failed due to lack of resources. Try again later."));
+
+ return FALSE;
+}
+
+gboolean
+polkit_session_get_questions (PolicyKitSession *session,
+ DBusGMethodInvocation *context)
+{
+ int n;
+ GSList *i;
+ char **questions;
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ if (session->priv->auth_state != AUTH_STATE_HAVE_QUESTIONS) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_NO_QUESTIONS,
+ "There are currently no questions available."));
+ return FALSE;
+ }
+
+ session->priv->auth_state = AUTH_STATE_NEED_ANSWERS;
+
+ questions = g_new0 (char *, g_slist_length (session->priv->auth_questions) + 1);
+ for (i = session->priv->auth_questions, n = 0; i != NULL; i = g_slist_next (i)) {
+ char *question = (char *) i->data;
+ questions[n++] = g_strdup (question);
+ }
+ questions[n] = NULL;
+
+ dbus_g_method_return (context, questions);
+ return TRUE;
+}
+
+gboolean
+polkit_session_provide_answers (PolicyKitSession *session,
+ char **answers,
+ DBusGMethodInvocation *context)
+{
+ int i;
+ GString *str;
+ char *cstr;
+ gsize strl;
+ gsize num_bytes_written;
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ if (session->priv->auth_state != AUTH_STATE_NEED_ANSWERS) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_NO_QUESTIONS,
+ "There are currently no questions pending answers."));
+ return FALSE;
+ }
+
+ session->priv->auth_state = AUTH_STATE_IN_PROGRESS;
+
+ str = g_string_new ("");
+ for (i = 0; answers[i] != NULL; i++) {
+ /*g_debug ("answer %d: %s", i, answers[i]);*/
+ g_string_append (str, answers[i]);
+ g_string_append_c (str, '\0');
+ }
+ strl = str->len;
+ cstr = g_string_free (str, FALSE);
+ g_io_channel_write (session->priv->pam_channel_write, cstr, strl, &num_bytes_written);
+ g_free (cstr);
+
+ /*g_debug ("wanted to write %d bytes, wrote %d bytes", strl, num_bytes_written);*/
+
+ dbus_g_method_return (context);
+ return TRUE;
+}
+
+gboolean
+polkit_session_close (PolicyKitSession *session,
+ gboolean do_not_revoke_privilege,
+ DBusGMethodInvocation *context)
+{
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (!do_not_revoke_privilege && session->priv->have_granted_temp_privileges) {
+
+ if (!polkit_manager_remove_temporary_privilege (session->priv->manager,
+ session->priv->grant_to_uid,
+ session->priv->grant_privilege,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction)) {
+ g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on pid %d",
+ session->priv->grant_privilege,
+ session->priv->grant_to_uid,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction);
+ }
+ }
+
+ g_object_unref (session);
+
+ dbus_g_method_return (context);
+ return TRUE;
+}
+
+gboolean
+polkit_session_grant_privilege_temporarily (PolicyKitSession *session,
+ gboolean restrict_to_callers_pid,
+ DBusGMethodInvocation *context)
+{
+ if (!polkit_session_check_caller (session, context))
+ return FALSE;
+
+ if (session->priv->auth_state != AUTH_STATE_DONE) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_NOT_DONE,
+ "Authentication is not done."));
+ return FALSE;
+ }
+
+ if (!session->priv->is_authenticated) {
+ dbus_g_method_return_error (context,
+ g_error_new (POLKIT_SESSION_ERROR,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_FAILED,
+ "User failed authentication."));
+ return FALSE;
+ }
+
+ session->priv->grant_pid_restriction = restrict_to_callers_pid ? session->priv->calling_pid : (pid_t) -1;
+ if (!polkit_manager_add_temporary_privilege (session->priv->manager,
+ session->priv->grant_to_uid,
+ session->priv->grant_privilege,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction)) {
+ g_warning ("Could not add tmp priv '%s' to uid %d for resource '%s' on pid %d",
+ session->priv->grant_privilege,
+ session->priv->grant_to_uid,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction);
+ }
+
+ session->priv->have_granted_temp_privileges = TRUE;
+
+ dbus_g_method_return (context);
+ return TRUE;
+}
+
+PolicyKitSession *
+polkit_session_new (DBusGConnection *connection,
+ PolicyKitManager *manager,
+ uid_t calling_uid,
+ pid_t calling_pid,
+ const char *calling_dbus_name,
+ uid_t uid,
+ const char *privilege,
+ const char *resource)
+{
+ char *objpath;
+ PolicyKitSession *session;
+ static int session_number_base = 0;
+
+ session = POLKIT_SESSION (g_object_new (POLKIT_TYPE_SESSION, NULL));
+ session->priv->connection = dbus_g_connection_ref (connection);
+ session->priv->session_number = session_number_base++;
+ session->priv->manager = manager;
+ objpath = g_strdup_printf ("/org/freedesktop/PolicyKit/sessions/%d", session->priv->session_number);
+ dbus_g_connection_register_g_object (connection, objpath, G_OBJECT (session));
+ g_free (objpath);
+
+ session->priv->calling_uid = calling_uid;
+ session->priv->calling_pid = calling_pid;
+ session->priv->calling_dbus_name = g_strdup (calling_dbus_name);
+
+ session->priv->grant_to_uid = uid;
+ session->priv->grant_privilege = g_strdup (privilege);
+ session->priv->grant_resource = g_strdup (resource);
+
+ /* TODO: look up auth_as_user, auth_with_pam_service from privilege configuration files */
+ session->priv->auth_as_user = g_strdup ("root");
+ session->priv->auth_with_pam_service = g_strdup ("policy-kit");
+
+ return session;
+}
+
+
+void
+polkit_session_initiator_disconnected (PolicyKitSession *session)
+{
+ /*g_debug ("initiator disconnected");*/
+
+ if (session->priv->have_granted_temp_privileges) {
+ if (!polkit_manager_remove_temporary_privilege (session->priv->manager,
+ session->priv->grant_to_uid,
+ session->priv->grant_privilege,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction)) {
+ g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on pid %d",
+ session->priv->grant_privilege,
+ session->priv->grant_to_uid,
+ session->priv->grant_resource,
+ session->priv->grant_pid_restriction);
+ }
+ }
+}
diff --git a/polkitd/polkit-session.h b/polkitd/polkit-session.h
new file mode 100644
index 0000000..c02bd22
--- /dev/null
+++ b/polkitd/polkit-session.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-session.h : Session object
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef _POLKIT_SESSION_H
+#define _POLKIT_SESSION_H
+
+#include <unistd.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "polkit-manager.h"
+
+GQuark polkit_session_error_quark (void);
+
+#define POLKIT_SESSION_ERROR (polkit_session_error_quark ())
+
+typedef enum
+{
+ POLKIT_SESSION_ERROR_AUTHENTICATION_IN_PROGRESS = 0,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_ALREADY_INITIATED = 1,
+ POLKIT_SESSION_ERROR_NO_QUESTIONS = 2,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_WAS_NOT_DENIED = 3,
+ POLKIT_SESSION_ERROR_NO_RESOURCES = 4,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_NOT_DONE = 5,
+ POLKIT_SESSION_ERROR_AUTHENTICATION_FAILED = 6,
+ POLKIT_SESSION_ERROR_NOT_INITIATOR = 7,
+ POLKIT_SESSION_NUM_ERRORS
+} PolkitSessionError;
+
+GType polkit_session_error_get_type (void);
+#define POLKIT_SESSION_TYPE_ERROR (polkit_session_error_get_type ())
+
+typedef struct PolicyKitSession PolicyKitSession;
+typedef struct PolicyKitSessionClass PolicyKitSessionClass;
+
+GType polkit_session_get_type (void);
+
+typedef struct PolicyKitSessionPrivate PolicyKitSessionPrivate;
+
+struct PolicyKitSession
+{
+ GObject parent;
+
+ PolicyKitSessionPrivate *priv;
+};
+
+struct PolicyKitSessionClass
+{
+ GObjectClass parent;
+};
+
+#define POLKIT_TYPE_SESSION (polkit_session_get_type ())
+#define POLKIT_SESSION(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), POLKIT_TYPE_SESSION, PolicyKitSession))
+#define POLKIT_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), POLKIT_TYPE_SESSION, PolicyKitSessionClass))
+#define POLKIT_IS_SESSION(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), POLKIT_TYPE_SESSION))
+#define POLKIT_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), POLKIT_TYPE_SESSION))
+#define POLKIT_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), POLKIT_TYPE_SESSION, PolicyKitSessionClass))
+
+PolicyKitSession *polkit_session_new (DBusGConnection *connection,
+ PolicyKitManager *manager,
+ uid_t calling_uid,
+ pid_t calling_pid,
+ const char *calling_dbus_name,
+ uid_t uid,
+ const char *privilege,
+ const char *resource);
+
+/* remote methods */
+
+gboolean polkit_session_is_authenticated (PolicyKitSession *session,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_initiate_auth (PolicyKitSession *session,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_get_questions (PolicyKitSession *session,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_provide_answers (PolicyKitSession *session,
+ char **answers,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_close (PolicyKitSession *session,
+ gboolean do_not_revoke_privilege,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_get_auth_details (PolicyKitSession *session,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_get_auth_denied_reason (PolicyKitSession *session,
+ DBusGMethodInvocation *context);
+
+gboolean polkit_session_grant_privilege_temporarily (PolicyKitSession *session,
+ gboolean restrict_to_callers_pid,
+ DBusGMethodInvocation *context);
+
+/* local methods */
+
+void polkit_session_initiator_disconnected (PolicyKitSession *session);
+
+
+#endif /* _POLKIT_SESSION_H */
diff --git a/libpolkit/libpolkit-test.c b/polkitd/polkitd-test.c
index 42be6ba..13efa68 100644
--- a/libpolkit/libpolkit-test.c
+++ b/polkitd/polkitd-test.c
@@ -1,11 +1,10 @@
/***************************************************************************
+ * CVSID: $Id$
*
- * libpolkit-test.c : Test harness for libpolkit
+ * polkitd-test.c : Test harness for PolicyKit daemon
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
- * Licensed under the Academic Free License version 2.1
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -29,9 +28,7 @@
#include <glib/gstdio.h>
-#include "libpolkit.h"
-
-static LibPolKitContext *ctx;
+#include "policy.h"
static char *testdir;
@@ -96,14 +93,14 @@ do_check (const char *policy,
}
gidstring = g_string_free (str, FALSE);
- if (LIBPOLKIT_RESULT_OK != libpolkit_is_uid_gid_allowed_for_policy (
- ctx, uid, num_gids, gids, policy, resource, &allowed)) {
+ if (POLICY_RESULT_OK != policy_is_uid_gid_allowed_for_policy (
+ uid, num_gids, gids, policy, resource, &allowed)) {
g_warning ("fail: no policy %s", policy);
my_exit (1);
}
if (allowed != expected) {
- g_warning ("fail: for uid %d (gids %s) expected %s on policy '%s' for resource '%s' but got %s",
+ g_warning ("fail: for uid %d (gids %s) expected %s on privilege '%s' for resource '%s' but got %s",
uid, gidstring,
expected ? "TRUE" : "FALSE",
policy,
@@ -112,7 +109,7 @@ do_check (const char *policy,
my_exit (1);
}
- g_print ("pass: uid %d (gids %s) got %s on policy '%s' for resource '%s'\n",
+ g_print ("pass: uid %d (gids %s) got %s on privilege '%s' for resource '%s'\n",
uid, gidstring,
expected ? "TRUE " : "FALSE",
policy,
@@ -127,7 +124,7 @@ write_test_policy (const char *policy, const char *allow_rule, const char *deny_
char *file;
FILE *f;
- file = g_strdup_printf ("%s/%s.policy", testdir, policy);
+ file = g_strdup_printf ("%s/%s.privilege", testdir, policy);
f = fopen (file, "w");
if (f == NULL) {
g_warning ("Cannot created test policy '%s'", file);
@@ -230,7 +227,7 @@ main (int argc, char *argv[])
GList *l;
GList *policies;
- testdir = g_strdup ("/tmp/libpolkit-test-XXXXXX");
+ testdir = g_strdup ("/tmp/policy-test-XXXXXX");
testdir = mkdtemp (testdir);
if (testdir == NULL) {
g_warning ("Cannot create tmpdir, errno %d (%s)", errno, strerror (errno));
@@ -238,21 +235,13 @@ main (int argc, char *argv[])
exit (1);
}
- g_message ("libpolkit-test started; using tmpdir=%s", testdir);
+ g_message ("policy-test started; using tmpdir=%s", testdir);
- ctx = libpolkit_new_context ();
- if (ctx == NULL) {
- g_message ("Cannot create context");
- my_exit (1);
- }
- if (!libpolkit_context_set_txt_source (ctx, testdir)) {
- g_message ("Cannot set text source to '%s'", testdir);
- my_exit (1);
- }
+ policy_util_set_policy_directory (testdir);
do_read_tests ();
- if (libpolkit_get_policies (ctx, &policies) != LIBPOLKIT_RESULT_OK) {
+ if (policy_get_policies (&policies) != POLICY_RESULT_OK) {
g_message ("Cannot get policies");
goto fail;
}
@@ -265,12 +254,7 @@ main (int argc, char *argv[])
g_list_foreach (policies, (GFunc) g_free, NULL);
g_list_free (policies);
- if (!libpolkit_free_context (ctx)) {
- g_warning ("Cannot free context");
- goto fail;
- }
-
- g_print ("libpolkit-test completed\n");
+ g_print ("policy-test completed\n");
my_exit (0);
diff --git a/polkitd/run-polkitd.sh b/polkitd/run-polkitd.sh
new file mode 100755
index 0000000..c8ce52f
--- /dev/null
+++ b/polkitd/run-polkitd.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+./polkitd --no-daemon --verbose
+
+
+
+
diff --git a/polkitd/valgrind-polkitd.sh b/polkitd/valgrind-polkitd.sh
new file mode 100755
index 0000000..208d38a
--- /dev/null
+++ b/polkitd/valgrind-polkitd.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./polkitd --no-daemon --verbose
+
diff --git a/privileges/Makefile.am b/privileges/Makefile.am
new file mode 100644
index 0000000..ba9463c
--- /dev/null
+++ b/privileges/Makefile.am
@@ -0,0 +1,7 @@
+
+privilegedir = $(sysconfdir)/PolicyKit/privilege.d
+
+dist_privilege_DATA = desktop-console.privilege
+
+clean-local :
+ rm -f *~
diff --git a/privileges/desktop-console.privilege b/privileges/desktop-console.privilege
new file mode 100644
index 0000000..112951b
--- /dev/null
+++ b/privileges/desktop-console.privilege
@@ -0,0 +1,4 @@
+
+[Policy]
+Allow=
+Deny=
diff --git a/tools/Makefile.am b/tools/Makefile.am
index e3ce830..2dca3a0 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -8,13 +8,36 @@ INCLUDES = \
-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-I$(top_srcdir) \
- @GLIB_CFLAGS@
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ @GLIB_CFLAGS@ \
+ @DBUS_CFLAGS@
bin_PROGRAMS = \
- polkit-is-privileged
+ polkit-is-privileged \
+ polkit-list-privileges \
+ polkit-grant-privilege
polkit_is_privileged_SOURCES = polkit-is-privileged.c
-polkit_is_privileged_LDADD = @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+polkit_is_privileged_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+
+polkit_list_privileges_SOURCES = polkit-list-privileges.c
+polkit_list_privileges_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+
+polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_manager --mode=glib-client --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml
+
+polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_session --mode=glib-client --output=polkit-interface-session-glue.h ../polkit-interface-session.xml
+
+polkit_grant_privilege_SOURCES= \
+ polkit-grant-privilege.c \
+ polkit-interface-manager-glue.h \
+ polkit-interface-session-glue.h
+
+polkit_grant_privilege_LDADD= @DBUS_GLIB_LIBS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+
+BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h
clean-local :
- rm -f *~
+ rm -f *~ $(BUILT_SOURCES)
+
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 382720b..961ad21 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -36,7 +36,9 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-bin_PROGRAMS = polkit-is-privileged$(EXEEXT)
+bin_PROGRAMS = polkit-is-privileged$(EXEEXT) \
+ polkit-list-privileges$(EXEEXT) \
+ polkit-grant-privilege$(EXEEXT)
subdir = tools
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -50,10 +52,18 @@ CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
+am_polkit_grant_privilege_OBJECTS = polkit-grant-privilege.$(OBJEXT)
+polkit_grant_privilege_OBJECTS = $(am_polkit_grant_privilege_OBJECTS)
+polkit_grant_privilege_DEPENDENCIES = \
+ $(top_builddir)/libpolkit/libpolkit.la
am_polkit_is_privileged_OBJECTS = polkit-is-privileged.$(OBJEXT)
polkit_is_privileged_OBJECTS = $(am_polkit_is_privileged_OBJECTS)
polkit_is_privileged_DEPENDENCIES = \
$(top_builddir)/libpolkit/libpolkit.la
+am_polkit_list_privileges_OBJECTS = polkit-list-privileges.$(OBJEXT)
+polkit_list_privileges_OBJECTS = $(am_polkit_list_privileges_OBJECTS)
+polkit_list_privileges_DEPENDENCIES = \
+ $(top_builddir)/libpolkit/libpolkit.la
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -65,8 +75,12 @@ LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
-SOURCES = $(polkit_is_privileged_SOURCES)
-DIST_SOURCES = $(polkit_is_privileged_SOURCES)
+SOURCES = $(polkit_grant_privilege_SOURCES) \
+ $(polkit_is_privileged_SOURCES) \
+ $(polkit_list_privileges_SOURCES)
+DIST_SOURCES = $(polkit_grant_privilege_SOURCES) \
+ $(polkit_is_privileged_SOURCES) \
+ $(polkit_list_privileges_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -75,6 +89,7 @@ AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
+AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
@@ -91,6 +106,10 @@ CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIR = @DATADIR@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_CFLAGS = @DBUS_GLIB_CFLAGS@
+DBUS_GLIB_LIBS = @DBUS_GLIB_LIBS@
+DBUS_LIBS = @DBUS_LIBS@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DOCDIR = @DOCDIR@
@@ -110,6 +129,9 @@ GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_LIBS = @GLIB_LIBS@
GTK_DOC_USE_LIBTOOL_FALSE = @GTK_DOC_USE_LIBTOOL_FALSE@
GTK_DOC_USE_LIBTOOL_TRUE = @GTK_DOC_USE_LIBTOOL_TRUE@
+HAVE_PAM = @HAVE_PAM@
+HAVE_PAM_FALSE = @HAVE_PAM_FALSE@
+HAVE_PAM_TRUE = @HAVE_PAM_TRUE@
HTML_DIR = @HTML_DIR@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -132,14 +154,21 @@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
OBJEXT = @OBJEXT@
+OS_TYPE_RED_HAT_FALSE = @OS_TYPE_RED_HAT_FALSE@
+OS_TYPE_RED_HAT_TRUE = @OS_TYPE_RED_HAT_TRUE@
+OS_TYPE_UNKNOWN_FALSE = @OS_TYPE_UNKNOWN_FALSE@
+OS_TYPE_UNKNOWN_TRUE = @OS_TYPE_UNKNOWN_TRUE@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
+PAM_FILE_INCLUDE = @PAM_FILE_INCLUDE@
+PAM_PREFIX = @PAM_PREFIX@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
+POLKITD_PID_FILE = @POLKITD_PID_FILE@
POLKIT_GROUP = @POLKIT_GROUP@
POLKIT_USER = @POLKIT_USER@
RANLIB = @RANLIB@
@@ -201,11 +230,23 @@ INCLUDES = \
-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-I$(top_srcdir) \
- @GLIB_CFLAGS@
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ @GLIB_CFLAGS@ \
+ @DBUS_CFLAGS@
polkit_is_privileged_SOURCES = polkit-is-privileged.c
-polkit_is_privileged_LDADD = @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
-all: all-am
+polkit_is_privileged_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+polkit_list_privileges_SOURCES = polkit-list-privileges.c
+polkit_list_privileges_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+polkit_grant_privilege_SOURCES = \
+ polkit-grant-privilege.c \
+ polkit-interface-manager-glue.h \
+ polkit-interface-session-glue.h
+
+polkit_grant_privilege_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la
+BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
@@ -266,9 +307,15 @@ clean-binPROGRAMS:
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
done
+polkit-grant-privilege$(EXEEXT): $(polkit_grant_privilege_OBJECTS) $(polkit_grant_privilege_DEPENDENCIES)
+ @rm -f polkit-grant-privilege$(EXEEXT)
+ $(LINK) $(polkit_grant_privilege_LDFLAGS) $(polkit_grant_privilege_OBJECTS) $(polkit_grant_privilege_LDADD) $(LIBS)
polkit-is-privileged$(EXEEXT): $(polkit_is_privileged_OBJECTS) $(polkit_is_privileged_DEPENDENCIES)
@rm -f polkit-is-privileged$(EXEEXT)
$(LINK) $(polkit_is_privileged_LDFLAGS) $(polkit_is_privileged_OBJECTS) $(polkit_is_privileged_LDADD) $(LIBS)
+polkit-list-privileges$(EXEEXT): $(polkit_list_privileges_OBJECTS) $(polkit_list_privileges_DEPENDENCIES)
+ @rm -f polkit-list-privileges$(EXEEXT)
+ $(LINK) $(polkit_list_privileges_LDFLAGS) $(polkit_list_privileges_OBJECTS) $(polkit_list_privileges_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -276,7 +323,9 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polkit-grant-privilege.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polkit-is-privileged.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/polkit-list-privileges.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@@ -385,13 +434,15 @@ distdir: $(DISTFILES)
fi; \
done
check-am: all-am
-check: check-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
-install: install-am
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
@@ -415,6 +466,7 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \
@@ -480,8 +532,14 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am
uninstall-info-am
+polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_manager --mode=glib-client --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml
+
+polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am
+ dbus-binding-tool --prefix=polkit_session --mode=glib-client --output=polkit-interface-session-glue.h ../polkit-interface-session.xml
+
clean-local :
- rm -f *~
+ rm -f *~ $(BUILT_SOURCES)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/tools/polkit-grant-privilege.c b/tools/polkit-grant-privilege.c
new file mode 100644
index 0000000..0a2d58c
--- /dev/null
+++ b/tools/polkit-grant-privilege.c
@@ -0,0 +1,434 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-grant-privilege.c : Grant privileges
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib/gstdio.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <libpolkit/libpolkit.h>
+
+#include "polkit-interface-manager-glue.h"
+#include "polkit-interface-session-glue.h"
+
+static char *grant_user = NULL;
+static char *grant_privilege = NULL;
+static char *grant_resource = NULL;
+static char *auth_user = NULL;
+static char *auth_pam_service_name = NULL;
+
+static void
+have_questions_handler (DBusGProxy *session, gpointer user_data)
+{
+ int i;
+ char **questions;
+ char **answers;
+ int num_a;
+ GError *error = NULL;
+
+ if (auth_user != NULL) {
+ if (grant_resource != NULL)
+ g_print ("\n"
+ "Authentication needed for user '%s' in order to grant the\n"
+ "privilege '%s' to user '%s' for the \n"
+ "resource '%s'.\n"
+ "\n"
+ "The privilege is configured to use PAM service '%s'.\n"
+ "\n",
+ auth_user,
+ grant_privilege, grant_user,
+ grant_resource,
+ auth_pam_service_name);
+ else
+ g_print ("\n"
+ "Authentication needed for user '%s' in order to grant the\n"
+ "privilege '%s' to user '%s'.\n"
+ "\n"
+ "The privilege is configured to use PAM service '%s'.\n"
+ "\n",
+ auth_user,
+ grant_privilege, grant_user,
+ auth_pam_service_name);
+ g_free (auth_user);
+ g_free (auth_pam_service_name);
+ auth_user = NULL;
+ auth_pam_service_name = NULL;
+ }
+
+ if (!org_freedesktop_PolicyKit_Session_get_questions (session,
+ &questions,
+ &error)) {
+ g_warning ("GetQuestions: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ answers = g_new0 (char *, g_strv_length (questions) + 1);
+ num_a = 0;
+
+ for (i = 0; questions[i] != NULL && questions[i+1] != NULL; i++) {
+ char *answer;
+ char *question = questions[i+1];
+ char *qtype = questions[i];
+
+ /*g_debug ("Question 1: '%s' (pamtype %s)\n(warning; secret will be echoed to stdout)", question, qtype);*/
+
+ if (strcmp (qtype, "PamPromptEchoOff") == 0) {
+ answer = getpass (question);
+ answers[num_a++] = g_strdup (answer);
+
+ /*g_debug ("Provding answer: '%s'", answer);*/
+
+ } else if (strcmp (qtype, "PamPromptEchoOn") == 0) {
+ char buf[1024];
+
+ fputs (question, stderr);
+ answer = fgets (question, sizeof (buf), stdin);
+ answers[num_a++] = g_strdup (answer);
+
+ /*g_debug ("Provding answer: '%s'", answer);*/
+
+ } else if (strcmp (qtype, "PamErrorMsg") == 0) {
+ /*g_debug ("Not providing answer");*/
+ ;
+ } else if (strcmp (qtype, "PamTextInfo") == 0) {
+ /*g_debug ("Not providing answer");*/
+ ;
+ }
+ }
+ answers[num_a] = NULL;
+
+ g_strfreev (questions);
+
+ if (!org_freedesktop_PolicyKit_Session_provide_answers (session,
+ (const char **) answers,
+ &error)) {
+ g_warning ("ProvideAnswers: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_strfreev (answers);
+
+out:
+ ;
+}
+
+static void
+auth_done_handler (DBusGProxy *session, gpointer user_data)
+{
+ gboolean auth_result;
+ GError *error = NULL;
+
+ /*g_debug ("in %s", __FUNCTION__);*/
+
+ if (!org_freedesktop_PolicyKit_Session_is_authenticated (session,
+ &auth_result,
+ &error)) {
+ g_warning ("IsAuthenticated: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /*g_message ("Authentication done. %s", auth_result);*/
+
+ if (!auth_result) {
+ char *auth_denied_reason;
+
+ if (!org_freedesktop_PolicyKit_Session_get_auth_denied_reason (session,
+ &auth_denied_reason,
+ &error)) {
+ g_warning ("GetAuthDeniedReason: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_print ("\n"
+ "Authentication failed (reason: '%s').\n", auth_denied_reason);
+ g_free (auth_denied_reason);
+ } else {
+ g_print ("\n"
+ "Authentication succeeded.\n");
+
+ /* don't restrict privilege to callers PID */
+ if (!org_freedesktop_PolicyKit_Session_grant_privilege_temporarily (session,
+ FALSE,
+ &error)) {
+ g_warning ("GrantPrivilegeTemporarily: %s", error->message);
+ g_error_free (error);
+ }
+ }
+
+out:
+
+ /* don't revoke privilege when we close the session */
+ if (!org_freedesktop_PolicyKit_Session_close (session,
+ TRUE,
+ &error)) {
+ g_warning ("Close: %s", error->message);
+ g_error_free (error);
+ }
+
+ exit (0);
+}
+
+static void
+do_grant_privilege (DBusGConnection *conn, const char *user, const char *privilege, const char *resource)
+{
+ GError *error = NULL;
+ DBusGProxy *manager;
+ DBusGProxy *session;
+ char *session_objpath;
+ GMainLoop *mainloop;
+
+ grant_user = g_strdup (user);
+ grant_privilege = g_strdup (privilege);
+ grant_resource = g_strdup (resource);
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+
+ manager = dbus_g_proxy_new_for_name (conn,
+ "org.freedesktop.PolicyKit",
+ "/org/freedesktop/PolicyKit/Manager",
+ "org.freedesktop.PolicyKit.Manager");
+ if (manager == NULL) {
+ goto out;
+ }
+
+ if (!org_freedesktop_PolicyKit_Manager_initiate_privilege_grant (manager,
+ user,
+ privilege,
+ resource,
+ &session_objpath,
+ &error)) {
+ g_warning ("GrantPrivilege: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /*g_debug ("session_objpath = %s", session_objpath);*/
+
+ session = dbus_g_proxy_new_for_name (conn,
+ "org.freedesktop.PolicyKit",
+ session_objpath,
+ "org.freedesktop.PolicyKit.Session");
+ if (session == NULL) {
+ goto out;
+ }
+
+ dbus_g_proxy_add_signal (session, "HaveQuestions", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (session, "HaveQuestions", G_CALLBACK (have_questions_handler),
+ NULL, NULL);
+
+ dbus_g_proxy_add_signal (session, "AuthenticationDone", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (session, "AuthenticationDone", G_CALLBACK (auth_done_handler),
+ NULL, NULL);
+
+ if (!org_freedesktop_PolicyKit_Session_get_auth_details (session,
+ &auth_user,
+ &auth_pam_service_name,
+ &error)) {
+ g_warning ("GetAuthDetails: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (!org_freedesktop_PolicyKit_Session_initiate_auth (session,
+ &error)) {
+ g_warning ("InitiateAuth: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_main_loop_run (mainloop);
+
+
+ g_free (session_objpath);
+out:
+ ;
+}
+
+static void
+usage (int argc, char *argv[])
+{
+ fprintf (stderr, "polkit-grant-privilege version " PACKAGE_VERSION "\n");
+
+ fprintf (stderr, "\n" "usage : %s -p <privilege> [-u user] [-r <resource>]\n", argv[0]);
+ fprintf (stderr,
+ "\n"
+ "Options:\n"
+ " -u, --user User to grant privilege to\n"
+ " -p, --privilege Privilege to grant\n"
+ " -r, --resource Resource\n"
+ " -h, --help Show this information and exit\n"
+ " -v, --verbose Verbose operation\n"
+ " -V, --version Print version number\n"
+ "\n"
+ "Grant a privilege for accessing a resource. The resource may\n"
+ "be omitted.\n");
+}
+
+static gboolean is_verbose = FALSE;
+
+int
+main (int argc, char **argv)
+{
+ int rc;
+ GError *error = NULL;
+ DBusGConnection *bus;
+ LibPolKitContext *ctx;
+ char *user = NULL;
+ char *resource = NULL;
+ char *privilege = NULL;
+ static const struct option long_options[] = {
+ {"user", required_argument, NULL, 'u'},
+ {"resource", required_argument, NULL, 'r'},
+ {"privilege", required_argument, NULL, 'p'},
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+ };
+
+ g_type_init ();
+
+ rc = 1;
+
+ while (TRUE) {
+ int c;
+
+ c = getopt_long (argc, argv, "u:r:p:hVv", long_options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'u':
+ user = g_strdup (optarg);
+ break;
+
+ case 'r':
+ resource = g_strdup (optarg);
+ break;
+
+ case 'p':
+ privilege = g_strdup (optarg);
+ break;
+
+ case 'v':
+ is_verbose = TRUE;
+ break;
+
+ case 'h':
+ usage (argc, argv);
+ rc = 0;
+ goto out;
+
+ case 'V':
+ printf ("polkit-grant-privilege version " PACKAGE_VERSION "\n");
+ rc = 0;
+ goto out;
+
+ default:
+ usage (argc, argv);
+ goto out;
+ }
+ }
+
+ if (privilege == NULL) {
+ usage (argc, argv);
+ return 1;
+ }
+
+ if (user == NULL) {
+ user = g_strdup (g_get_user_name ());
+ }
+
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (bus == NULL) {
+ g_warning ("dbus_g_bus_get: %s", error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ ctx = libpolkit_new_context (dbus_g_connection_get_connection (bus));
+
+ gboolean is_privileged = FALSE;
+ LibPolKitResult result;
+
+ result = libpolkit_is_uid_allowed_for_privilege (ctx,
+ -1,
+ user,
+ privilege,
+ resource,
+ &is_privileged);
+ switch (result) {
+ case LIBPOLKIT_RESULT_OK:
+ if (is_privileged) {
+ if (resource == NULL) {
+ g_print ("User '%s' already has privilege '%s'.\n", user, privilege);
+ } else {
+ g_print ("User '%s' already has privilege '%s' for accessing\n"
+ "resource '%s'.\n",
+ user, privilege, resource);
+ }
+ rc = 0;
+ goto out;
+ }
+ break;
+
+ case LIBPOLKIT_RESULT_ERROR:
+ g_print ("Error granting resource.\n");
+ goto out;
+
+ case LIBPOLKIT_RESULT_INVALID_CONTEXT:
+ g_print ("Invalid context.\n");
+ goto out;
+
+ case LIBPOLKIT_RESULT_NOT_PRIVILEGED:
+ g_print ("Not privileged.\n");
+ goto out;
+
+ case LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE:
+ g_print ("No such privilege '%s'.\n", privilege);
+ goto out;
+
+ case LIBPOLKIT_RESULT_NO_SUCH_USER:
+ g_print ("No such user '%s'.\n", user);
+ goto out;
+ }
+
+ do_grant_privilege (bus, user, privilege, resource);
+
+out:
+ return rc;
+}
diff --git a/tools/polkit-is-privileged.c b/tools/polkit-is-privileged.c
index 803d57e..cd4b1d6 100644
--- a/tools/polkit-is-privileged.c
+++ b/tools/polkit-is-privileged.c
@@ -1,12 +1,10 @@
/***************************************************************************
* CVSID: $Id$
*
- * polkit-is-privileged.c : Small command line wrapper for libpolkit
+ * polkit-is-privileged.c : Determine if a user has privileges
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
- * Licensed under the Academic Free License version 2.1
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -31,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
+#include <dbus/dbus.h>
#include <libpolkit/libpolkit.h>
@@ -39,21 +38,23 @@ usage (int argc, char *argv[])
{
fprintf (stderr, "polkit-is-privileged version " PACKAGE_VERSION "\n");
- fprintf (stderr, "\n" "usage : %s -u <uid> -p <policy> [-r <resource>]\n", argv[0]);
+ fprintf (stderr,
+ "\n"
+ "usage : %s -u <uid> -p <privilege> [-r <resource>]\n"
+ " [-i <pid>]", argv[0]);
fprintf (stderr,
"\n"
"Options:\n"
- " -u, --uid Username or user id\n"
+ " -u, --user Username or user id\n"
+ " -i, --pid Pid of process privilege may be restricted to\n"
" -r, --resource Resource\n"
- " -p, --policy policy to test for\n"
+ " -p, --privilege Privilege to test for\n"
" -h, --help Show this information and exit\n"
" -v, --verbose Verbose operation\n"
" -V, --version Print version number\n"
"\n"
"Queries system policy whether a given user is allowed for a given\n"
- "policy for a given resource. The resource may be omitted.\n"
- "\n"
- "System policies are defined in the " PACKAGE_SYSCONF_DIR "/PolicyKit/policy directory.\n"
+ "privilege for a given resource. The resource may be omitted.\n"
"\n");
}
@@ -61,36 +62,42 @@ int
main (int argc, char *argv[])
{
int rc;
- uid_t uid;
char *user = NULL;
- char *policy = NULL;
+ char *privilege = NULL;
char *resource = NULL;
+ pid_t pid = (pid_t) -1;
static const struct option long_options[] = {
- {"uid", required_argument, NULL, 'u'},
+ {"user", required_argument, NULL, 'u'},
+ {"pid", required_argument, NULL, 'i'},
{"resource", required_argument, NULL, 'r'},
- {"policy", required_argument, NULL, 'p'},
+ {"privilege", required_argument, NULL, 'p'},
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
LibPolKitContext *ctx = NULL;
- char *endp;
gboolean is_allowed;
LibPolKitResult result;
gboolean is_verbose = FALSE;
+ DBusError error;
+ DBusConnection *connection;
rc = 1;
while (TRUE) {
int c;
- c = getopt_long (argc, argv, "u:r:p:UhVv", long_options, NULL);
+ c = getopt_long (argc, argv, "u:r:p:i:hVv", long_options, NULL);
if (c == -1)
break;
switch (c) {
+ case 'i':
+ pid = atoi (optarg);
+ break;
+
case 'u':
user = g_strdup (optarg);
break;
@@ -100,7 +107,7 @@ main (int argc, char *argv[])
break;
case 'p':
- policy = g_strdup (optarg);
+ privilege = g_strdup (optarg);
break;
case 'v':
@@ -123,61 +130,60 @@ main (int argc, char *argv[])
}
}
- if (user == NULL || policy == NULL) {
+ if (user == NULL || privilege == NULL) {
usage (argc, argv);
return 1;
}
if (is_verbose) {
- printf ("user = '%s'\n", user);
- printf ("policy = '%s'\n", policy);
- printf ("resource = '%s'\n", resource);
+ printf ("user = '%s'\n", user);
+ printf ("privilege = '%s'\n", privilege);
+ printf ("resource = '%s'\n", resource);
}
- ctx = libpolkit_new_context ();
- if (ctx == NULL) {
- g_warning ("Cannot get policy context");
- goto out;
+ dbus_error_init (&error);
+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (connection == NULL) {
+ g_warning ("Cannot connect to system message bus");
+ return 1;
}
- uid = (uid_t) g_ascii_strtoull (user, &endp, 0);
- if (endp[0] != '\0') {
- uid = libpolkit_util_name_to_uid (ctx, user, NULL);
- if (uid == (uid_t) -1) {
- g_warning ("User '%s' does not exist", user);
- goto out;
- }
- }
- if (is_verbose) {
- printf ("user '%s' is uid %d\n", user, (int) uid);
+ ctx = libpolkit_new_context (connection);
+ if (ctx == NULL) {
+ g_warning ("Cannot get libpolkit context");
+ goto out;
}
- result = libpolkit_is_uid_allowed_for_policy (ctx,
- uid,
- policy,
- resource,
- &is_allowed);
+ result = libpolkit_is_uid_allowed_for_privilege (ctx,
+ pid,
+ user,
+ privilege,
+ resource,
+ &is_allowed);
switch (result) {
case LIBPOLKIT_RESULT_OK:
rc = is_allowed ? 0 : 1;
break;
case LIBPOLKIT_RESULT_ERROR:
- g_warning ("error retrieving policy");
+ g_warning ("Error determing whether user is privileged.");
break;
case LIBPOLKIT_RESULT_INVALID_CONTEXT:
- g_warning ("invalid context");
- break;
+ g_print ("Invalid context.\n");
+ goto out;
- case LIBPOLKIT_RESULT_PERMISSON_DENIED:
- g_warning ("permission denied");
- break;
+ case LIBPOLKIT_RESULT_NOT_PRIVILEGED:
+ g_print ("Not privileged.\n");
- case LIBPOLKIT_RESULT_NO_SUCH_POLICY:
- g_warning ("no such policy '%s'", policy);
- break;
+ case LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE:
+ g_print ("No such privilege '%s'.\n", privilege);
+ goto out;
+
+ case LIBPOLKIT_RESULT_NO_SUCH_USER:
+ g_print ("No such user '%s'.\n", user);
+ goto out;
}
if (is_verbose) {
diff --git a/tools/polkit-list-privileges.c b/tools/polkit-list-privileges.c
new file mode 100644
index 0000000..f58e623
--- /dev/null
+++ b/tools/polkit-list-privileges.c
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * polkit-list-privileges.c : List privileges possesed by a user
+ *
+ * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <dbus/dbus.h>
+
+#include <libpolkit/libpolkit.h>
+
+static void
+usage (int argc, char *argv[])
+{
+ fprintf (stderr, "polkit-list-privileges version " PACKAGE_VERSION "\n");
+
+ fprintf (stderr, "\n" "usage : %s [-u <user>]\n", argv[0]);
+ fprintf (stderr,
+ "\n"
+ "Options:\n"
+ " -u, --user Username or user id\n"
+ " -h, --help Show this information and exit\n"
+ " -v, --verbose Verbose operation\n"
+ " -V, --version Print version number\n"
+ "\n"
+ "Lists privileges for a given user.\n"
+ "\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+ int rc;
+ char *user = NULL;
+ static const struct option long_options[] = {
+ {"user", required_argument, NULL, 'u'},
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+ };
+ LibPolKitContext *ctx = NULL;
+ gboolean is_verbose = FALSE;
+ DBusError error;
+ DBusConnection *connection;
+ int i;
+ GList *l;
+ GList *privilege_list;
+
+ rc = 1;
+
+ while (TRUE) {
+ int c;
+
+ c = getopt_long (argc, argv, "u:p:hVv", long_options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'u':
+ user = g_strdup (optarg);
+ break;
+
+ case 'v':
+ is_verbose = TRUE;
+ break;
+
+ case 'h':
+ usage (argc, argv);
+ rc = 0;
+ goto out;
+
+ case 'V':
+ printf ("polkit-list-privileges version " PACKAGE_VERSION "\n");
+ rc = 0;
+ goto out;
+
+ default:
+ usage (argc, argv);
+ goto out;
+ }
+ }
+
+ if (user == NULL) {
+ user = g_strdup (g_get_user_name ());
+ }
+
+ if (is_verbose) {
+ printf ("user = '%s'\n", user);
+ }
+
+ dbus_error_init (&error);
+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (connection == NULL) {
+ g_warning ("Cannot connect to system message bus");
+ return 1;
+ }
+
+
+ ctx = libpolkit_new_context (connection);
+ if (ctx == NULL) {
+ g_warning ("Cannot get libpolkit context");
+ goto out;
+ }
+
+ if (libpolkit_get_privilege_list (ctx, &privilege_list) != LIBPOLKIT_RESULT_OK) {
+ g_warning ("Cannot get privilege_list");
+ goto out;
+ }
+ for (l = privilege_list, i = 0; l != NULL; l = g_list_next (l), i++) {
+ const char *privilege;
+ gboolean is_allowed;
+ GList *j;
+ GList *resources;
+
+ privilege = (const char *) l->data;
+ if (is_verbose) {
+ g_print ("testing user %s for privilege '%s'\n", user, privilege);
+ }
+
+ if (libpolkit_is_uid_allowed_for_privilege (ctx,
+ -1,
+ user,
+ privilege,
+ NULL,
+ &is_allowed) == LIBPOLKIT_RESULT_OK) {
+ if (is_allowed) {
+ g_print ("privilege %s\n", privilege);
+ } else {
+ if (libpolkit_get_allowed_resources_for_privilege_for_uid (ctx,
+ user,
+ privilege,
+ &resources) == LIBPOLKIT_RESULT_OK) {
+ for (j = resources; j != NULL; j = g_list_next (j)) {
+ const char *resource;
+ resource = (const char *) j->data;
+ g_print ("resource %s privilege %s\n", resource, privilege);
+ }
+ g_list_foreach (resources, (GFunc) g_free, NULL);
+ g_list_free (resources);
+ }
+ }
+ }
+
+
+
+ }
+ g_list_foreach (privilege_list, (GFunc) g_free, NULL);
+ g_list_free (privilege_list);
+
+ rc = 0;
+
+out:
+ if (ctx != NULL)
+ libpolkit_free_context (ctx);
+
+ return rc;
+}