Commit 3638c6c1 authored by David Zeuthen's avatar David Zeuthen

add module loading to PolicyKit

This paves the way for writing

 1. A module that tracks temporary (look in /var/run) and permanent (look
    in /var/lib) privilege grants
 2. A D-Bus service to authenticate a client to obtain to a privilege
    grant and then writing the grant in temporary or permanent storage

Also, this feature lets people very easily lock down the system; just
edit /etc/PolicyKit/PolicyKit.conf; add pam-module-deny-all / -allow-all
stanzas with various privilege=<regexp> and user=<username> options.
parent a1b5a12b
## Process this file with automake to produce Makefile.in
SUBDIRS = libpolkit doc tools privileges
SUBDIRS = libpolkit modules doc tools privileges
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libpolkit.pc
......
......@@ -174,6 +174,10 @@ doc/spec/Makefile
doc/spec/polkit-spec.xml.in
doc/man/Makefile
privileges/Makefile
modules/Makefile
modules/default/Makefile
modules/allow-all/Makefile
modules/deny-all/Makefile
])
dnl ==========================================================================
......
......@@ -64,7 +64,6 @@
PolicyKit library.
</para>
</partintro>
<xi:include href="xml/libpolkit.xml"/>
<xi:include href="xml/libpolkit-error.xml"/>
<xi:include href="xml/libpolkit-result.xml"/>
<xi:include href="xml/libpolkit-context.xml"/>
......@@ -77,6 +76,7 @@
<xi:include href="xml/libpolkit-seat.xml"/>
<xi:include href="xml/libpolkit-session.xml"/>
<xi:include href="xml/libpolkit-caller.xml"/>
<xi:include href="xml/libpolkit-module.xml"/>
</reference>
<index>
......
if MAN_PAGES_ENABLED
MAN_IN_FILES = polkit-check-caller.1.in polkit-check-session.1.in polkit-privilege-file-validate.1.in
MAN_IN_FILES = polkit-check-caller.1.in polkit-check-session.1.in polkit-privilege-file-validate.1.in PolicyKit.8.in polkit-module-default.8.in polkit-module-allow-all.8.in polkit-module-deny-all.8.in
man_MANS = $(MAN_IN_FILES:.in=)
......@@ -10,7 +10,7 @@ endif # MAN_PAGES_ENABLED
EXTRA_DIST=$(man_MANS) $(MAN_IN_FILES)
clean-local:
rm -f *~ *.1
rm -f *~ *.1 *.8
%: %.in Makefile
$(edit) $< >$@
......
.\"
.\" PolicyKit manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLICYKIT 8
.SH NAME
PolicyKit \- centralized policy management
.SH DESCRIPTION
.PP
For more information about the big picture refer to the \fIPolicyKit
spec\fP which can be found in
.I "@docdir@/spec/polkit-spec.html"
depending on the distribution.
.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
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-allow-all\fR\|(8),
\&\fIpolkit-module-deny-all\fR\|(8),
\&\fIpolkit-check-caller\fR\|(1),
\&\fIpolkit-check-session\fR\|(1),
\&\fIpolkit-privilege-file-validate\fR\|(1),
\&\fIdbus-daemon\fR\|(1),
\&\fIhald\fR\|(8)
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
......@@ -56,6 +56,7 @@ on how to subscribe.
.SH SEE ALSO
.PP
\&\fIPolicyKit\fR\|(8),
\&\fIdbus-daemon\fR\|(1),
\&\fIpolkit-check-session\fR\|(1)
......
......@@ -56,6 +56,7 @@ on how to subscribe.
.SH SEE ALSO
.PP
\&\fIPolicyKit\fR\|(8),
\&\fIdbus-daemon\fR\|(1),
\&\fIpolkit-check-caller\fR\|(1)
......
.\"
.\" polkit-module-allow-all manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-MODULE-ALLOW-ALL 8
.SH NAME
polkit-module-allow-all \- grant access to all privileges
.SH SYNOPSIS
.PP
.B polkit-module-allow-all.so [privilege=<regexp>] [user=<username>]
.SH DESCRIPTION
.PP
This PolicyKit module will allow access to any privilege regardless of
the entity requesting it, what the requested privilege is and what
resource is involved.
For more information about the big picture refer to the \fIPolicyKit
spec\fP which can be found in
.I "@docdir@/spec/polkit-spec.html"
depending on the distribution.
.SH OPTIONS
.TP 3n
.B privilege=<regexp>
Only consider requests where the privilege name matches the given
regular expression. Example:
.B privilege=hal-storage-mount*
.TP 3n
.B user=<username>
Only consider requests matching the given username. May be both a
numerical
.B uid
value or a username. Example:
.B user=davidz
.SH NOTES
.PP
Never use this module unless you
.B COMPLETELY
trust anyone with either remote or local access to the system.
.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
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-deny-all\fR\|(8),
\&\fI@sysconfdir@/PolicyKit/privileges\fR\|,
\&\fI@sysconfdir@/PolicyKit/PolicyKit.conf\fR\|
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
.\"
.\" polkit-module-default manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-MODULE-DEFAULT 8
.SH NAME
polkit-module-default \- use default policy for privileges
.SH SYNOPSIS
.PP
.B standard polkit-module-default.so
.SH DESCRIPTION
.PP
This PolicyKit module uses the default policy as specified (and
required) for by the privilege definition file for a given privilege.
For more information about the big picture refer to the \fIPolicyKit
spec\fP which can be found in
.I "@docdir@/spec/polkit-spec.html"
depending on the distribution.
.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
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-module-allow-all\fR\|(8),
\&\fIpolkit-module-deny-all\fR\|(8),
\&\fI@sysconfdir@/PolicyKit/privileges\fR\|,
\&\fI@sysconfdir@/PolicyKit/PolicyKit.conf\fR\|
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
.\"
.\" polkit-module-deny-all manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-MODULE-DENY-ALL 8
.SH NAME
polkit-module-deny-all \- grant access to all privileges
.SH SYNOPSIS
.PP
.B polkit-module-deny-all.so [privilege=<regexp>] [user=<username>]
.SH DESCRIPTION
.PP
This PolicyKit module will deny access to any privilege regardless of
the entity requesting it, what the requested privilege is and what
resource is involved.
For more information about the big picture refer to the \fIPolicyKit
spec\fP which can be found in
.I "@docdir@/spec/polkit-spec.html"
depending on the distribution.
.SH OPTIONS
.TP 3n
.B privilege=<regexp>
Only consider requests where the privilege name matches the given
regular expression. Example:
.B privilege=hal-storage-mount*
.TP 3n
.B user=<username>
Only consider requests matching the given username. May be both a
numerical
.B uid
value or a username. Example:
.B user=davidz
.SH NOTES
.PP
This module is mostly useful in situations where it's desirable to
lock down the system so it's unusable by normal unprivileged users.
.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
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-allow-all\fR\|(8),
\&\fI@sysconfdir@/PolicyKit/privileges\fR\|,
\&\fI@sysconfdir@/PolicyKit/PolicyKit.conf\fR\|
.SH AUTHOR
Written by David Zeuthen <david@fubar.dk> with a lot of help from many
others.
......@@ -43,6 +43,7 @@ on how to subscribe.
.SH SEE ALSO
.PP
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-check-caller\fR\|(1),
\&\fIpolkit-check-session\fR\|(1)
......
......@@ -8,6 +8,7 @@ INCLUDES = \
-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
-DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
-DPACKAGE_LIB_DIR=\""$(libdir)"\" \
-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
@GLIB_CFLAGS@ @DBUS_CFLAGS@
......@@ -28,10 +29,11 @@ libpolkitinclude_HEADERS = \
libpolkit-privilege-file-entry.h \
libpolkit-privilege-file.h \
libpolkit-privilege-cache.h \
libpolkit-privilege-default.h
libpolkit-privilege-default.h \
libpolkit-module.h
libpolkit_la_SOURCES = \
libpolkit.h libpolkit.c \
libpolkit.h \
libpolkit-error.h libpolkit-error.c \
libpolkit-result.h libpolkit-result.c \
libpolkit-context.h libpolkit-context.c \
......@@ -44,9 +46,10 @@ libpolkit_la_SOURCES = \
libpolkit-privilege-file.h libpolkit-privilege-file.c \
libpolkit-privilege-cache.h libpolkit-privilege-cache.c \
libpolkit-privilege-default.h libpolkit-privilege-default.c \
libpolkit-debug.h libpolkit-debug.c
libpolkit-debug.h libpolkit-debug.c \
libpolkit-module.h libpolkit-module.c
libpolkit_la_LIBADD = @GLIB_LIBS@ @DBUS_LIBS@
libpolkit_la_LIBADD = @GLIB_LIBS@ @DBUS_LIBS@ -ldl
libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
......
......@@ -40,6 +40,7 @@
#include "libpolkit-debug.h"
#include "libpolkit-context.h"
#include "libpolkit-privilege-cache.h"
#include "libpolkit-module.h"
/**
* SECTION:libpolkit-context
......@@ -66,6 +67,8 @@ struct PolKitContext
char *priv_dir;
PolKitPrivilegeCache *priv_cache;
GSList *modules;
};
/**
......@@ -84,6 +87,147 @@ libpolkit_context_new (void)
return pk_context;
}
static gboolean
unload_modules (PolKitContext *pk_context)
{
GSList *i;
for (i = pk_context->modules; i != NULL; i = g_slist_next (i)) {
PolKitModuleInterface *module_interface = i->data;
libpolkit_module_interface_unref (module_interface);
}
g_slist_free (pk_context->modules);
pk_context->modules = NULL;
_pk_debug ("Unloaded modules");
return TRUE;
}
static gboolean
load_modules (PolKitContext *pk_context, GError **error)
{
const char *config_file;
gboolean ret;
char *buf;
char *end;
char line[256];
char *p;
char *q;
gsize len;
int line_number;
int mod_number;
ret = FALSE;
buf = NULL;
mod_number = 0;
config_file = PACKAGE_SYSCONF_DIR "/PolicyKit/PolicyKit.conf";
if (!g_file_get_contents (config_file,
&buf,
&len,
error)) {
_pk_debug ("Cannot load PolicyKit configuration file at '%s'", config_file);
goto out;
}
end = buf + len;
/* parse the config file; one line at a time (yes, this is super ugly code) */
p = buf;
line_number = -1;
while (TRUE) {
int argc;
char **tokens;
char *module_name;
char *module_path;
PolKitModuleControl module_control;
PolKitModuleInterface *module_interface;
line_number++;
q = p;
while (*q != '\n' && q != '\0' && q < end)
q++;
if (*q == '\0' || q >= end) {
/* skip last line if it's not terminated by whitespace */
break;
}
if ((unsigned int) (q - p) > sizeof(line) - 1) {
_pk_debug ("Line is too long; skipping it");
continue;
}
strncpy (line, p, q - p);
line[q - p] = '\0';
p = q + 1;
/* remove leading and trailing white space */
g_strstrip (line);
/* comments, blank lines are fine; just skip them */
if (line[0] == '#' || strlen (line) == 0) {
continue;
}
/*_pk_debug ("Looking at line: '%s'", line);*/
if (!g_shell_parse_argv (line, &argc, &tokens, NULL)) {
_pk_debug ("Cannot parse line %d - skipping", line_number);
continue;
}
if (argc < 2) {
_pk_debug ("Line %d is malformed - skipping line", line_number);
g_strfreev (tokens);
continue;
}
if (!libpolkit_module_control_from_string_representation (tokens[0], &module_control)) {
_pk_debug ("Unknown module_control '%s' at line %d - skipping line", tokens[0], line_number);
g_strfreev (tokens);
continue;
}
module_name = tokens[1];
module_path = g_strdup_printf (PACKAGE_LIB_DIR "/PolicyKit/modules/%s", module_name);
_pk_debug ("MODULE: number=%d control=%d name=%s argc=%d",
mod_number, module_control, module_name, argc - 1);
module_interface = libpolkit_module_interface_load_module (module_path,
module_control,
argc - 1,
tokens + 1);
g_free (module_path);
if (module_interface != NULL) {
pk_context->modules = g_slist_append (pk_context->modules, module_interface);
mod_number++;
}
g_strfreev (tokens);
}
ret = TRUE;
out:
if (buf != NULL)
g_free (buf);
_pk_debug ("Loaded %d modules in total", mod_number);
return ret;
}
static void
_config_file_events (PolKitContext *pk_context,
PolKitContextFileMonitorEvent event_mask,
const char *path,
gpointer user_data)
{
_pk_debug ("Config file changed");
unload_modules (pk_context);
load_modules (pk_context, NULL);
/* signal that our configuration (may have) changed */
if (pk_context->config_changed_cb) {
pk_context->config_changed_cb (pk_context, pk_context->config_changed_user_data);
}
}
static void
_privilege_dir_events (PolKitContext *pk_context,
PolKitContextFileMonitorEvent event_mask,
......@@ -117,11 +261,8 @@ _privilege_dir_events (PolKitContext *pk_context,
gboolean
libpolkit_context_init (PolKitContext *pk_context, GError **error)
{
gboolean ret;
const char *dirname;
ret = FALSE;
dirname = getenv ("POLKIT_PRIVILEGE_DIR");
if (dirname != NULL) {
pk_context->priv_dir = g_strdup (dirname);
......@@ -130,11 +271,16 @@ libpolkit_context_init (PolKitContext *pk_context, GError **error)
}
_pk_debug ("Using privilege files from directory %s", pk_context->priv_dir);
/* Load modules */
if (!load_modules (pk_context, error))
goto error;
/* don't populate the cache until it's needed.. */
if (pk_context->file_monitor_add_watch_func == NULL) {
_pk_debug ("No file monitor; cannot monitor '%s' for .priv file changes", dirname);
} else {
/* Watch when privilege definitions file change */
pk_context->file_monitor_add_watch_func (pk_context,
pk_context->priv_dir,
POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE|
......@@ -142,12 +288,23 @@ libpolkit_context_init (PolKitContext *pk_context, GError **error)
POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE,
_privilege_dir_events,
NULL);
/* Config file changes */
pk_context->file_monitor_add_watch_func (pk_context,
PACKAGE_SYSCONF_DIR "/PolicyKit",
POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE|
POLKIT_CONTEXT_FILE_MONITOR_EVENT_DELETE|
POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE,
_config_file_events,
NULL);
}
/* right now we can't fail - but in the future modules we load may */
return TRUE;
error:
if (pk_context != NULL)
libpolkit_context_unref (pk_context);
ret = TRUE;
return ret;
return FALSE;
}
/**
......@@ -177,10 +334,14 @@ libpolkit_context_ref (PolKitContext *pk_context)
void
libpolkit_context_unref (PolKitContext *pk_context)
{
g_return_if_fail (pk_context != NULL);
pk_context->refcount--;
if (pk_context->refcount > 0)
return;
unload_modules (pk_context);
g_free (pk_context);
}
......@@ -263,3 +424,273 @@ libpolkit_context_get_privilege_cache (PolKitContext *pk_context)
return pk_context->priv_cache;
}
/**
* libpolkit_context_get_seat_resource_association:
* @pk_context: the PolicyKit context
* @visitor: visitor function
* @user_data: user data
*
* Retrieve information about what resources are associated to what
* seats. Note that a resource may be associated to more than one
* seat. This information stems from user configuration and consumers
* of this information that know better (e.g. HAL) may choose to
* override it.
*
* Typically, this information is used to e.g. bootstrap the system
* insofar that it can be used to start login greeters on the given
* video hardware (e.g. resources) on the given user-configured seats.
*
* If a resource is not associated with any seat, it is assumed to be
* available to any local seat.
*
* Returns: A #PolKitResult - can only be one of
* #LIBPOLKIT_RESULT_NOT_AUTHORIZED_TO_KNOW or
* #LIBPOLKIT_RESULT_YES (if the callback was invoked)
*/
PolKitResult
libpolkit_context_get_seat_resource_association (PolKitContext *pk_context,
PolKitSeatVisitorCB visitor,
gpointer *user_data)
{
return LIBPOLKIT_RESULT_YES;
}
/**
* libpolkit_context_is_resource_associated_with_seat:
* @pk_context: the PolicyKit context
* @resource: the resource in question
* @seat: the seat
*
* Determine if a given resource is associated with a given seat. The
* same comments noted in libpolkit_get_seat_resource_association() about the
* source purely being user configuration applies here as well.
*
* Returns: A #PolKitResult - can only be one of
* #LIBPOLKIT_RESULT_NOT_AUTHORIZED_TO_KNOW,
* #LIBPOLKIT_RESULT_YES, #LIBPOLKIT_RESULT_NO.
*/
PolKitResult
libpolkit_context_is_resource_associated_with_seat (PolKitContext *pk_context,
PolKitResource *resource,
PolKitSeat *seat)
{
return LIBPOLKIT_RESULT_NO;
}
/**
* libpolkit_context_can_session_access_resource:
* @pk_context: the PolicyKit context
* @privilege: the type of access to check for
* @resource: the resource in question
* @session: the session in question
*
* Determine if a given session can access a given resource in a given way.
*
* Returns: A #PolKitResult - can only be one of
* #LIBPOLKIT_RESULT_NOT_AUTHORIZED_TO_KNOW,
* #LIBPOLKIT_RESULT_YES, #LIBPOLKIT_RESULT_NO.
*/
PolKitResult
libpolkit_context_can_session_access_resource (PolKitContext *pk_context,
PolKitPrivilege *privilege,
PolKitResource *resource,
PolKitSession *session)
{
PolKitPrivilegeCache *cache;