Commit 41692189 authored by David Zeuthen's avatar David Zeuthen

add two tools polkit-check-caller and polkit-check-session

parent 5dabca21
......@@ -121,6 +121,10 @@ PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.6.0])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.0])
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
AC_CHECK_FUNCS(getgrouplist)
# DocBook Documentation
......@@ -187,6 +191,8 @@ doc/api/libpolkit/version.xml
doc/spec/Makefile
doc/spec/polkit-spec.xml.in
doc/man/Makefile
doc/man/polkit-check-caller.1
doc/man/polkit-check-session.1
])
dnl ==========================================================================
......
......@@ -64,9 +64,7 @@
PolicyKit library.
</para>
</partintro>
<title>
<xi:include href="xml/libpolkit.xml"/>
</title>
<xi:include href="xml/libpolkit-context.xml"/>
<xi:include href="xml/libpolkit-privilege.xml"/>
<xi:include href="xml/libpolkit-resource.xml"/>
......
if MAN_PAGES_ENABLED
MAN_IN_FILES =
MAN_IN_FILES = polkit-check-caller.1.in polkit-check-session.1.in
man_MANS =
man_MANS = polkit-check-caller.1 polkit-check-session.1
endif # MAN_PAGES_ENABLED
......
.\"
.\" polkit-check-caller manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-CHECK-CALLER 1
.SH NAME
polkit-check-caller \- check access
.SH SYNOPSIS
.PP
.B polkit-check-caller
[options]
.SH DESCRIPTION
\fIpolkit-check-caller\fP can be used to determine if a given caller
can access a given resource in a given way. For more information about
the big picture refer to the \fIPolicyKit spec\fP which can be found
in
.I "/usr/share/doc/PolicyKit-@VERSION@/spec/polkit-spec.html"
depending on the distribution.
.SH OPTIONS
The following options are supported:
.TP
.I "--resource-type"
Type of resource.
.TP
.I "--resource"
Identifier of resource.
.TP
.I "--privilege"
The privilege to check.
.TP
.I "--caller"
The caller to check for. Must be the callers unique name on the D-Bus
system message bus.
.TP
.I "--help"
Print out usage.
.TP
.I "--version"
Print the version.
.SH RETURN VALUE
.PP
If access is allowed, this
program exits with exit code 0. If no access is allowed or an error
occurs, the program exits with a non-zero exit code.
.SH BUGS
.PP
Please send bug reports to either the distribution or the HAL
mailing list, see
.I "http://lists.freedesktop.org/mailman/listinfo/hal"
on how to subscribe.
.SH SEE ALSO
.PP
\&\fIdbus-daemon\fR\|(1),
\&\fIpolkit-check-session\fR\|(1)
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
.\"
.\" polkit-check-session manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-CHECK-SESSION 1
.SH NAME
polkit-check-session \- check access
.SH SYNOPSIS
.PP
.B polkit-check-session
[options]
.SH DESCRIPTION
\fIpolkit-check-session\fP can be used to determine if a given session
can access a given resource in a given way. For more information about
the big picture refer to the \fIPolicyKit spec\fP which can be found
in
.I "/usr/share/doc/PolicyKit-@VERSION@/spec/polkit-spec.html"
depending on the distribution.
.SH OPTIONS
The following options are supported:
.TP
.I "--resource-type"
Type of resource.
.TP
.I "--resource"
Identifier of resource.
.TP
.I "--privilege"
The privilege to check.
.TP
.I "--session"
The session to check for. Must be a ConsoleKit object path. If
ommitted the current session is used.
.TP
.I "--help"
Print out usage.
.TP
.I "--version"
Print the version.
.SH RETURN VALUE
.PP
If access is allowed, this
program exits with exit code 0. If no access is allowed or an error
occurs, the program exits with a non-zero exit code.
.SH BUGS
.PP
Please send bug reports to either the distribution or the HAL
mailing list, see
.I "http://lists.freedesktop.org/mailman/listinfo/hal"
on how to subscribe.
.SH SEE ALSO
.PP
\&\fIdbus-daemon\fR\|(1),
\&\fIpolkit-check-caller\fR\|(1)
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
......@@ -6,6 +6,6 @@ includedir=@includedir@
Name: libpolkit
Description: library for querying system-wide policy
Version: @VERSION@
Requires: glib-2.0
Requires: glib-2.0 dbus-1
Libs: -L${libdir} -lpolkit
Cflags: -I${includedir}/PolicyKit
......@@ -8,7 +8,7 @@ INCLUDES = \
-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
@GLIB_CFLAGS@
@GLIB_CFLAGS@ @DBUS_CFLAGS@
lib_LTLIBRARIES=libpolkit.la
......@@ -32,7 +32,7 @@ libpolkit_la_SOURCES = \
libpolkit-session.h libpolkit-session.c \
libpolkit-caller.h libpolkit-caller.c
libpolkit_la_LIBADD = @GLIB_LIBS@
libpolkit_la_LIBADD = @GLIB_LIBS@ @DBUS_LIBS@
libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
......
......@@ -128,17 +128,17 @@ void
libpolkit_caller_set_dbus_name (PolKitCaller *caller, const char *dbus_name)
{
g_return_if_fail (caller != NULL);
if (caller->dbus_name == NULL)
if (caller->dbus_name != NULL)
g_free (caller->dbus_name);
caller->dbus_name = g_strdup (dbus_name);
}
/**
* libpolkit_caller_set_pid:
* libpolkit_caller_set_uid:
* @caller: The caller object
* @pid: UNIX process id
* @uid: UNIX user id
*
* Set the callers UNIX process id.
* Set the callers UNIX user id.
**/
void
libpolkit_caller_set_uid (PolKitCaller *caller, uid_t uid)
......@@ -172,7 +172,7 @@ void
libpolkit_caller_set_selinux_context (PolKitCaller *caller, const char *selinux_context)
{
g_return_if_fail (caller != NULL);
if (caller->selinux_context == NULL)
if (caller->selinux_context != NULL)
g_free (caller->selinux_context);
caller->selinux_context = g_strdup (selinux_context);
}
......@@ -190,7 +190,7 @@ void
libpolkit_caller_set_ck_session (PolKitCaller *caller, PolKitSession *session)
{
g_return_if_fail (caller != NULL);
if (caller->session == NULL)
if (caller->session != NULL)
libpolkit_session_unref (caller->session);
caller->session = session != NULL ? libpolkit_session_ref (session) : NULL;
}
......@@ -214,11 +214,11 @@ libpolkit_caller_get_dbus_name (PolKitCaller *caller, char **out_dbus_name)
}
/**
* libpolkit_caller_get_pid:
* libpolkit_caller_get_uid:
* @caller: The caller object
* @out_pid: Returns the UNIX process id
* @out_uid: Returns the UNIX user id
*
* Get the callers UNIX process id.
* Get the callers UNIX user id.
*
* Returns: TRUE iff the value is returned
**/
......@@ -254,7 +254,8 @@ libpolkit_caller_get_pid (PolKitCaller *caller, pid_t *out_pid)
* @caller: The caller object
* @out_selinux_context: Returns the SELinux security context. The caller shall not free this string.
*
* Get the callers SELinux security context.
* Get the callers SELinux security context. Note that this may be
* #NULL if SELinux is not available on the system.
*
* Returns: TRUE iff the value is returned
**/
......@@ -272,7 +273,8 @@ libpolkit_caller_get_selinux_context (PolKitCaller *caller, char **out_selinux_c
* @caller: The caller object
* @out_session: Returns the session object. Caller shall not unref it.
*
* Get the callers session.
* Get the callers session. Note that this may be #NULL if the caller
* is not in any session.
*
* Returns: TRUE iff the value is returned
**/
......@@ -284,3 +286,152 @@ libpolkit_caller_get_ck_session (PolKitCaller *caller, PolKitSession **out_sessi
*out_session = caller->session;
return TRUE;
}
/**
* libpolkit_caller_new_from_dbus_name:
* @con: D-Bus system bus connection
* @dbus_name: unique system bus connection name
* @error: D-Bus error
*
* This function will construct a #PolKitCaller object by querying
* both the system bus daemon and the ConsoleKit daemon for
* information. Note that this will do a lot of blocking IO so it is
* best avoided if your process already tracks/caches all the
* information.
*
* Returns: the new object or #NULL if an error occured (in which case
* @error will be set)
**/
PolKitCaller *
libpolkit_caller_new_from_dbus_name (DBusConnection *con, const char *dbus_name, DBusError *error)
{
PolKitCaller *caller;
pid_t pid;
uid_t uid;
char *selinux_context;
char *ck_session_objpath;
PolKitSession *session;
DBusMessage *message;
DBusMessage *reply;
DBusMessageIter iter;
DBusMessageIter sub_iter;
char *str;
int num_elems;
g_return_val_if_fail (con != NULL, NULL);
g_return_val_if_fail (dbus_name != NULL, NULL);
g_return_val_if_fail (error != NULL, NULL);
g_return_val_if_fail (! dbus_error_is_set (error), NULL);
selinux_context = NULL;
ck_session_objpath = NULL;
caller = NULL;
session = NULL;
uid = dbus_bus_get_unix_user (con, dbus_name, error);
if (uid == ((unsigned long) -1) || dbus_error_is_set (error)) {
g_warning ("Could not get uid for connection: %s %s", error->name, error->message);
goto out;
}
message = dbus_message_new_method_call ("org.freedesktop.DBus",
"/org/freedesktop/DBus/Bus",
"org.freedesktop.DBus",
"GetConnectionUnixProcessID");
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing GetConnectionUnixProcessID on Bus: %s: %s", error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
goto out;
}
dbus_message_iter_init (reply, &iter);
dbus_message_iter_get_basic (&iter, &pid);
dbus_message_unref (message);
dbus_message_unref (reply);
message = dbus_message_new_method_call ("org.freedesktop.DBus",
"/org/freedesktop/DBus/Bus",
"org.freedesktop.DBus",
"GetConnectionSELinuxSecurityContext");
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &dbus_name);
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
/* SELinux might not be enabled */
if (dbus_error_is_set (error) &&
strcmp (error->name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown") == 0) {
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
dbus_error_init (error);
} else if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing GetConnectionSELinuxSecurityContext on Bus: %s: %s", error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
goto out;
} else {
/* TODO: verify signature */
dbus_message_iter_init (reply, &iter);
dbus_message_iter_recurse (&iter, &sub_iter);
dbus_message_iter_get_fixed_array (&sub_iter, (void *) &str, &num_elems);
if (str != NULL && num_elems > 0)
selinux_context = g_strndup (str, num_elems);
dbus_message_unref (message);
dbus_message_unref (reply);
}
message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
"/org/freedesktop/ConsoleKit/Manager",
"org.freedesktop.ConsoleKit.Manager",
"GetSessionForUnixProcess");
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &pid);
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing GetSessionForUnixProcess on ConsoleKit: %s: %s", error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
/* OK, this is not a catastrophe; just means the caller is not a
* member of any session or that ConsoleKit is not available..
*/
goto not_in_session;
}
dbus_message_iter_init (reply, &iter);
dbus_message_iter_get_basic (&iter, &str);
ck_session_objpath = g_strdup (str);
dbus_message_unref (message);
dbus_message_unref (reply);
session = libpolkit_session_new_from_objpath (con, ck_session_objpath, uid, error);
if (session == NULL) {
g_warning ("Got a session objpath but couldn't construct session object!");
}
not_in_session:
g_debug ("uid %d", uid);
g_debug ("pid %d", pid);
g_debug ("selinux context '%s'", selinux_context != NULL ? selinux_context : "(not set)");
g_debug ("ck session '%s'", ck_session_objpath != NULL ? ck_session_objpath : "(not in a session)");
caller = libpolkit_caller_new ();
libpolkit_caller_set_dbus_name (caller, dbus_name);
libpolkit_caller_set_uid (caller, uid);
libpolkit_caller_set_pid (caller, pid);
libpolkit_caller_set_selinux_context (caller, selinux_context);
if (session != NULL) {
libpolkit_caller_set_ck_session (caller, session);
libpolkit_session_unref (session); /* we own this session object */
}
out:
g_free (selinux_context);
g_free (ck_session_objpath);
return caller;
}
......@@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <libpolkit/libpolkit-session.h>
......@@ -37,6 +38,7 @@ struct PolKitCaller;
typedef struct PolKitCaller PolKitCaller;
PolKitCaller *libpolkit_caller_new (void);
PolKitCaller *libpolkit_caller_new_from_dbus_name (DBusConnection *con, const char *dbus_name, DBusError *error);
PolKitCaller *libpolkit_caller_ref (PolKitCaller *caller);
void libpolkit_caller_unref (PolKitCaller *caller);
void libpolkit_caller_set_dbus_name (PolKitCaller *caller, const char *dbus_name);
......
......@@ -120,7 +120,7 @@ void
libpolkit_privilege_set_privilege_id (PolKitPrivilege *privilege, const char *privilege_id)
{
g_return_if_fail (privilege != NULL);
if (privilege->id == NULL)
if (privilege->id != NULL)
g_free (privilege->id);
privilege->id = g_strdup (privilege_id);
}
......
......@@ -127,7 +127,7 @@ libpolkit_resource_set_resource_type (PolKitResource *resource, const char *res
{
g_return_if_fail (resource != NULL);
if (resource->type == NULL)
if (resource->type != NULL)
g_free (resource->type);
resource->type = g_strdup (resource_type);
}
......@@ -144,7 +144,7 @@ libpolkit_resource_set_resource_id (PolKitResource *resource, const char *resou
{
g_return_if_fail (resource != NULL);
if (resource->id == NULL)
if (resource->id != NULL)
g_free (resource->id);
resource->id = g_strdup (resource_id);
}
......
......@@ -120,7 +120,7 @@ void
libpolkit_seat_set_ck_objref (PolKitSeat *seat, const char *ck_objref)
{
g_return_if_fail (seat != NULL);
if (seat->ck_objref == NULL)
if (seat->ck_objref != NULL)
g_free (seat->ck_objref);
seat->ck_objref = g_strdup (ck_objref);
}
......
......@@ -144,7 +144,7 @@ void
libpolkit_session_set_ck_objref (PolKitSession *session, const char *ck_objref)
{
g_return_if_fail (session != NULL);
if (session->ck_objref == NULL)
if (session->ck_objref != NULL)
g_free (session->ck_objref);
session->ck_objref = g_strdup (ck_objref);
}
......@@ -190,7 +190,7 @@ void
libpolkit_session_set_ck_remote_host (PolKitSession *session, const char *remote_host)
{
g_return_if_fail (session != NULL);
if (session->remote_host == NULL)
if (session->remote_host != NULL)
g_free (session->remote_host);
session->remote_host = g_strdup (remote_host);
}
......@@ -209,7 +209,7 @@ void
libpolkit_session_set_seat (PolKitSession *session, PolKitSeat *seat)
{
g_return_if_fail (session != NULL);
if (session->seat == NULL)
if (session->seat != NULL)
libpolkit_seat_unref (session->seat);
session->seat = seat != NULL ? libpolkit_seat_ref (seat) : NULL;
}
......@@ -324,3 +324,242 @@ libpolkit_session_get_seat (PolKitSession *session, PolKitSeat **out_seat)
*out_seat = session->seat;
return TRUE;
}
/**
* libpolkit_session_new_from_objpath:
* @con: D-Bus system bus connection
* @objpath: object path of ConsoleKit session object
* @uid: the user owning the session or -1 if unknown
* @error: D-Bus error
*
* This function will construct a #PolKitSession object by querying
* the ConsoleKit daemon for information. Note that this will do a lot
* of blocking IO so it is best avoided if your process already
* tracks/caches all the information. If you pass in @uid as a
* non-negative number, a round trip can be saved.
*
* Returns: the new object or #NULL if an error occured (in which case
* @error will be set)
**/
PolKitSession *
libpolkit_session_new_from_objpath (DBusConnection *con, const char *objpath, uid_t uid, DBusError *error)
{
PolKitSeat *seat;
PolKitSession *session;
DBusMessage *message;
DBusMessage *reply;
char *str;
gboolean is_active;
gboolean is_local;
char *remote_host;
char *seat_path;
g_return_val_if_fail (con != NULL, NULL);
g_return_val_if_fail (objpath != NULL, NULL);
g_return_val_if_fail (error != NULL, NULL);
g_return_val_if_fail (! dbus_error_is_set (error), NULL);
session = NULL;
remote_host = NULL;
seat_path = NULL;
message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
objpath,
"org.freedesktop.ConsoleKit.Session",
"IsActive");
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing Session.IsActive on ConsoleKit: %s: %s", error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
goto out;
}
if (!dbus_message_get_args (reply, NULL,
DBUS_TYPE_BOOLEAN, &is_active,
DBUS_TYPE_INVALID)) {
g_warning ("Invalid IsActive reply from CK");
goto out;
}
dbus_message_unref (message);
dbus_message_unref (reply);
message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
objpath,
"org.freedesktop.ConsoleKit.Session",
"IsLocal");
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing Session.IsLocal on ConsoleKit: %s: %s", error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
goto out;
}
if (!dbus_message_get_args (reply, NULL,
DBUS_TYPE_BOOLEAN, &is_local,
DBUS_TYPE_INVALID)) {
g_warning ("Invalid IsLocal reply from CK");
goto out;
}
dbus_message_unref (message);
dbus_message_unref (reply);
if (!is_local) {
message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
objpath,
"org.freedesktop.ConsoleKit.Session",
"GetRemoteHostName");
reply = dbus_connection_send_with_reply_and_block (con, message, -1, error);
if (reply == NULL || dbus_error_is_set (error)) {
g_warning ("Error doing Session.GetRemoteHostName on ConsoleKit: %s: %s",
error->name, error->message);
dbus_message_unref (message);
if (reply != NULL)
dbus_message_unref (reply);
goto out;
}
if (!dbus_message_get_args (reply, NULL,
DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID)) {
g_warning ("Invalid GetRemoteHostName reply from CK");
goto out;
}
remote_host = g_strdup (str);
dbus_message_unref (message);
dbus_message_unref (reply);
}
message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
objpath,
"org.freedesktop.ConsoleKit.Session",
"GetSeatId");