Commit e2a465d0 authored by David Zeuthen's avatar David Zeuthen

add built-in options and a new module pam-polkit-run-program.so

parent 0973db30
......@@ -178,6 +178,7 @@ modules/Makefile
modules/default/Makefile
modules/allow-all/Makefile
modules/deny-all/Makefile
modules/run-program/Makefile
])
dnl ==========================================================================
......
if MAN_PAGES_ENABLED
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_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 polkit-module-run-program.8.in polkit-module-builtins.8.in
man_MANS = $(MAN_IN_FILES:.in=)
......
......@@ -7,7 +7,7 @@
polkit-module-allow-all \- grant access to all privileges
.SH SYNOPSIS
.PP
.B polkit-module-allow-all.so [privilege=<regexp>] [user=<username>]
.B polkit-module-allow-all.so
.SH DESCRIPTION
.PP
This PolicyKit module will allow access to any privilege regardless of
......@@ -20,26 +20,14 @@ spec\fP which can be found in
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
This module does not require nor recognize any options.
.SH NOTES
.PP
Never use this module unless you
.B COMPLETELY
trust anyone with either remote or local access to the system.
trust anyone with either remote or local access to the system, or you
have confined the module using built-in options.
.SH BUGS
.PP
......@@ -51,8 +39,10 @@ on how to subscribe.
.SH SEE ALSO
.PP
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-module-builtins\fR\|(8),
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-deny-all\fR\|(8),
\&\fIpolkit-module-run-program\fR\|(8),
\&\fI@sysconfdir@/PolicyKit/privileges\fR\|,
\&\fI@sysconfdir@/PolicyKit/PolicyKit.conf\fR\|
......
.\"
.\" polkit-module-builtins manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-MODULE-BUILTINS 8
.SH NAME
polkit-module-builtins \- options that apply to any PolicyKit module
.SH SYNOPSIS
.PP
.B any-module.so [privilege=<regexp>] [user=<username> ...]
.SH DESCRIPTION
.PP
This manual page describes options that can be used for any PolicyKit
module to confine what requests it should deal with.
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. This option can be used multiple times to specify
multiple users. Example:
.B user=davidz user=bateman
.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.
......@@ -7,7 +7,7 @@
polkit-module-deny-all \- grant access to all privileges
.SH SYNOPSIS
.PP
.B polkit-module-deny-all.so [privilege=<regexp>] [user=<username>]
.B polkit-module-deny-all.so
.SH DESCRIPTION
.PP
This PolicyKit module will deny access to any privilege regardless of
......@@ -20,25 +20,13 @@ spec\fP which can be found in
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
This module does not require nor recognize any options.
.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.
Unless confined using built-in options, this module is only useful
in situations where it's desirable to lock down the system so it's
unusable by normal unprivileged users.
.SH BUGS
.PP
......@@ -50,8 +38,10 @@ on how to subscribe.
.SH SEE ALSO
.PP
\&\fIPolicyKit\fR\|(8),
\&\fIpolkit-module-builtins\fR\|(8),
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-allow-all\fR\|(8),
\&\fIpolkit-module-run-program\fR\|(8),
\&\fI@sysconfdir@/PolicyKit/privileges\fR\|,
\&\fI@sysconfdir@/PolicyKit/PolicyKit.conf\fR\|
......
.\"
.\" polkit-module-run-program manual page.
.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
.\"
.TH POLKIT-MODULE-RUN-PROGRAM 8
.SH NAME
polkit-module-run-program \- determine policy by running a program
.SH SYNOPSIS
.PP
.HP 31
\fBpolkit-module-run-program.so\fR program=\fI<program>\fR
.SH DESCRIPTION
.PP
This PolicyKit module will run a program every time a privilege is
requested. 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 program=<program>
Absolute path to program to run; this is a mandatory option. Examples:
.B privilege=/usr/bin/my-program
or
.B privilege="/path/to/program --foo --bar"
.SH DESCRIPTION
This module will invoke the given program and will export a minimal
environment with values identifying the request. The program
.B SHOULD NOT
have any side effects; it is only invoked to make a decision - not to
alter state on the system. Further, the program is not guaranteed to
run as
.B uid 0
(e.g. root); it is effectively invoked by a mechanism (such as
\fBhald\fR(7)) that may run as an unprivileged system user.
.PP
If the program fails to run or exits with a non-zero exit code, it
means that the request is denied (same as returning
.B no
- see below). If the program exits with exit code 0,
.I stdout
of the program is examined to determine the result of the decision
(these values map directly to the possible values in the
.I PolKitResult
enumeration):
.I
.TP
.B unknown
The passed privilege is unknown.
.TP
.B not_authorized
The mechanism / caller (e.g. the program using
.I libpolkit
that loads this module) is not sufficiently privileged to know the
answer.
.TP
.B no
Access denied.
.TP
.B auth_root
Access denied, but authentication of the caller as root will grant
access to only that caller.
.TP
.B auth_root_keep_session
Access denied, but authentication of the caller as root will grant
access for the remainder of the session the caller stems from.
.TP
.B auth_root_keep_always
Access denied, but authentication of the caller as root will grant
access to the user of the caller in the future.
.TP
.B auth_self
Access denied, but authentication of the caller as himself will grant
access to only that caller.
.TP
.B auth_self_keep_session
Access denied, but authentication of the caller as himself will grant
access for the remainder of the session the caller stems from.
.TP
.B auth_self_keep_always
Access denied, but authentication of the caller as himself will grant
access to the user of the caller in the future.
.TP
.B yes
Access granted.
.PP
For a request concerning decisions for calls via the system message
bus daemon, the environment will contain:
.TP
.B POLKIT_REQUEST_CALLER=1
To identify the request to be concerning a decision about a caller on
the system message bus.
.TP
.B POLKIT_PRIVILEGE_ID
Privilege identifier
.TP
.B POLKIT_RESOURCE_ID
Resource identifier
.TP
.B POLKIT_RESOURCE_TYPE
Resource type
.TP
.B POLKIT_CALLER_UID
UNIX user id of the caller
.TP
.B POLKIT_CALLER_DBUS_NAME
Unique name of the caller on the system message bus
.TP
.B POLKIT_CALLER_PID
UNIX process id of the caller
.TP
.B POLKIT_CALLER_SELINUX_CONTEXT
SELinux security context of the caller (only set if SELinux is enabled)
.TP
.B POLKIT_SESSION_CK_IS_ACTIVE
Whether ConsoleKit regards the session as active (only set if the caller belong to a session)
.TP
.B POLKIT_SESSION_CK_IS_LOCAL
Whether ConsoleKit regards the session as local (only set if the caller belong to a session)
.TP
.B POLKIT_SESSION_CK_OBJREF
ConsoleKit session D-Bus object reference (only set if the caller belong to a session)
.TP
.B POLKIT_SESSION_UID
UNIX user ID of the user owning the session (only set if the caller belong to a session)
.TP
.B POLKIT_SEAT_CK_OBJREF
ConsoleKit seat D-Bus object reference of the seat that the session belongs to (only set if the caller belong to a session)
.PP
For a request concerning session-wide decisions the environment will
contain:
.TP
.B POLKIT_REQUEST_SESSION=1
To identify the request to be session-wide.
.TP
.B POLKIT_PRIVILEGE_ID
Privilege identifier
.TP
.B POLKIT_RESOURCE_ID
Resource identifier
.TP
.B POLKIT_RESOURCE_TYPE
Resource type
.TP
.B POLKIT_SESSION_CK_IS_ACTIVE
Whether ConsoleKit regards the session as active
.TP
.B POLKIT_SESSION_CK_IS_LOCAL
Whether ConsoleKit regards the session as local
.TP
.B POLKIT_SESSION_CK_OBJREF
ConsoleKit session D-Bus object reference
.TP
.B POLKIT_SESSION_UID
UNIX user ID of the user owning the session
.TP
.B POLKIT_SEAT_CK_OBJREF
ConsoleKit seat D-Bus object reference of the seat that the session belongs to
.SH NOTES
.PP
As PolicyKit modules are heavily used to enforce policy, running a
program on every request may put unneccessary load on the system
unless judicious use of built-in options to confine the module are
employed.
.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),
\&\fIhald\fR\|(8),
\&\fIdbus-daemon\fR\|(1),
\&\fIpolkit-module-default\fR\|(8),
\&\fIpolkit-module-builtins\fR\|(8),
\&\fIpolkit-module-default\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.
......@@ -42,6 +42,13 @@
#include "libpolkit-privilege-cache.h"
#include "libpolkit-module.h"
/**
* SECTION:libpolkit
* @short_description: Centralized policy management.
*
* libpolkit is a C library for centralized policy management.
**/
/**
* SECTION:libpolkit-context
* @short_description: Context.
......@@ -545,11 +552,24 @@ libpolkit_context_can_session_access_resource (PolKitContext *pk_context,
_pk_debug ("Asking module '%s'", libpolkit_module_get_name (module_interface));
module_control = libpolkit_module_interface_get_control (module_interface);
module_result = func (module_interface,
pk_context,
privilege,
resource,
session);
if (libpolkit_module_interface_check_builtin_confinement_for_session (
module_interface,
pk_context,
privilege,
resource,
session)) {
/* module is confined by built-in options */
module_result = LIBPOLKIT_RESULT_UNKNOWN_PRIVILEGE;
_pk_debug ("Module '%s' confined by built-in's",
libpolkit_module_get_name (module_interface));
} else {
module_result = func (module_interface,
pk_context,
privilege,
resource,
session);
}
/* if a module returns _UNKNOWN_PRIVILEGE, it means that it doesn't
* have an opinion about the query; e.g. polkit-module-allow-all(8)
......@@ -653,11 +673,24 @@ libpolkit_context_can_caller_access_resource (PolKitContext *pk_context,
_pk_debug ("Asking module '%s'", libpolkit_module_get_name (module_interface));
module_control = libpolkit_module_interface_get_control (module_interface);
module_result = func (module_interface,
pk_context,
privilege,
resource,
caller);
if (libpolkit_module_interface_check_builtin_confinement_for_caller (
module_interface,
pk_context,
privilege,
resource,
caller)) {
/* module is confined by built-in options */
module_result = LIBPOLKIT_RESULT_UNKNOWN_PRIVILEGE;
_pk_debug ("Module '%s' confined by built-in's",
libpolkit_module_get_name (module_interface));
} else {
module_result = func (module_interface,
pk_context,
privilege,
resource,
caller);
}
/* if a module returns _UNKNOWN_PRIVILEGE, it means that it doesn't
* have an opinion about the query; e.g. polkit-module-allow-all(8)
......
......@@ -34,6 +34,9 @@
# include <config.h>
#endif
#include <dlfcn.h>
#include <regex.h>
#include <pwd.h>
#include <grp.h>
#include "libpolkit-debug.h"
#include "libpolkit-module.h"
......@@ -58,8 +61,114 @@ struct PolKitModuleInterface
PolKitModuleIsResourceAssociatedWithSeat func_is_resource_associated_with_seat;
PolKitModuleCanSessionAccessResource func_can_session_access_resource;
PolKitModuleCanCallerAccessResource func_can_caller_access_resource;
gboolean builtin_have_privilege_regex;
regex_t builtin_privilege_regex_compiled;
GSList *builtin_users;
};
static uid_t
_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;
}
static void
_parse_builtin_remove_option (int *argc, char *argv[], int position)
{
int n;
for (n = position; n < *argc; n++)
argv[n] = argv[n+1];
(*argc)--;
}
static gboolean
_parse_builtin (PolKitModuleInterface *mi, int *argc, char *argv[])
{
int n;
gboolean ret;
ret = FALSE;
for (n = 1; n < *argc; ) {
if (g_str_has_prefix (argv[n], "privilege=")) {
const char *regex;
if (mi->builtin_have_privilege_regex) {
_pk_debug ("Already have option 'privilege='");
goto error;
}
regex = argv[n] + 10;
if (regcomp (&(mi->builtin_privilege_regex_compiled), regex, REG_EXTENDED) != 0) {
_pk_debug ("Regex '%s' didn't compile", regex);
goto error;
}
mi->builtin_have_privilege_regex = TRUE;
_pk_debug ("Compiled regex '%s' for option 'privilege=' OK", regex);
_parse_builtin_remove_option (argc, argv, n);
} else if (g_str_has_prefix (argv[n], "user=")) {
const char *user;
uid_t uid;
GSList *i;
user = argv[n] + 5;
uid = _util_name_to_uid (user, NULL);
if ((int) uid == -1) {
_pk_debug ("Unknown user name '%s'", user);
goto error;
}
for (i = mi->builtin_users; i != NULL; i = g_slist_next (i)) {
uid_t uid_in_list = GPOINTER_TO_INT (i->data);
if (uid_in_list == uid) {
_pk_debug ("Already have user '%s'", user);
goto error;
}
}
_pk_debug ("adding uid %d", uid);
mi->builtin_users = g_slist_prepend (mi->builtin_users, GINT_TO_POINTER (uid));
_parse_builtin_remove_option (argc, argv, n);
} else {
n++;
}
}
ret = TRUE;
error:
return ret;
}
/**
* libpolkit_module_interface_load_module:
* @name: name of module, e.g. "polkit-module-default.so"
......@@ -112,6 +221,11 @@ libpolkit_module_interface_load_module (const char *name, PolKitModuleControl mo
goto error;
}
if (!_parse_builtin (mi, &argc, argv)) {
_pk_debug ("Error parsing built-in module options for '%s'", name);
goto error;
}
if (!mi->func_initialize (mi, argc, argv)) {
_pk_debug ("Module '%s' returned FALSE in initialization function", name);
goto error;
......@@ -193,6 +307,11 @@ libpolkit_module_interface_unref (PolKitModuleInterface *module_interface)
if (module_interface->refcount > 0)
return;
/* builtins */
if (module_interface->builtin_have_privilege_regex)
regfree (&module_interface->builtin_privilege_regex_compiled);
g_slist_free (module_interface->builtin_users);
/* shutdown the module and unload it */
if (module_interface->func_shutdown != NULL)
module_interface->func_shutdown (module_interface);
......@@ -488,3 +607,140 @@ libpolkit_module_get_user_data (PolKitModuleInterface *module_interface)
return module_interface->module_user_data;
}
static gboolean
_check_privilege (PolKitModuleInterface *module_interface, PolKitPrivilege *privilege)
{
gboolean ret;
ret = FALSE;
if (module_interface->builtin_have_privilege_regex) {
char *privilege_name;
if (libpolkit_privilege_get_privilege_id (privilege, &privilege_name)) {
if (regexec (&module_interface->builtin_privilege_regex_compiled,
privilege_name, 0, NULL, 0) == 0) {
ret = TRUE;
}
}
} else {
ret = TRUE;
}
return ret;
}
/*----*/
static gboolean
_check_uid_in_list (GSList *list, uid_t given_uid)
{
GSList *i;
for (i = list; i != NULL; i = g_slist_next (i)) {
uid_t uid = GPOINTER_TO_INT (i->data);
if (given_uid == uid)
return TRUE;
}
return FALSE;
}
static gboolean