diff options
author | David Zeuthen <david@fubar.dk> | 2006-03-14 06:14:33 +0000 |
---|---|---|
committer | David Zeuthen <david@fubar.dk> | 2006-03-14 06:14:33 +0000 |
commit | 96f6daa63d428d9a16d8564b83f33b71e1cd41ca (patch) | |
tree | 6a8ec6e8928e65f5defec45ec169cdf4f6da9018 | |
parent | 4f567cd7eef1cb7fcd5777a0ba2b6df03e5ea88c (diff) | |
download | polkit-96f6daa63d428d9a16d8564b83f33b71e1cd41ca.tar.gz |
Add a bunch of code; basically a full rewrite moving all queries to the
daemon.
32 files changed, 4451 insertions, 1193 deletions
@@ -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. @@ -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; +} |