From e2a465d0f9a16b501754b03267d743ac20135973 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Sun, 8 Apr 2007 16:49:27 -0400 Subject: [PATCH] add built-in options and a new module pam-polkit-run-program.so --- configure.in | 1 + doc/man/Makefile.am | 2 +- doc/man/polkit-module-allow-all.8.in | 22 +- doc/man/polkit-module-builtins.8.in | 55 ++++ doc/man/polkit-module-deny-all.8.in | 24 +- doc/man/polkit-module-run-program.8.in | 198 +++++++++++++ libpolkit/libpolkit-context.c | 53 +++- libpolkit/libpolkit-module.c | 256 +++++++++++++++++ libpolkit/libpolkit-module.h | 15 + modules/Makefile.am | 2 +- modules/allow-all/polkit-module-allow-all.c | 153 +--------- modules/deny-all/Makefile.am | 4 +- modules/deny-all/polkit-module-deny-all.c | 92 ++++++ modules/run-program/Makefile.am | 25 ++ modules/run-program/polkit-module-run-program.c | 359 ++++++++++++++++++++++++ 15 files changed, 1063 insertions(+), 198 deletions(-) create mode 100644 doc/man/polkit-module-builtins.8.in create mode 100644 doc/man/polkit-module-run-program.8.in create mode 100644 modules/deny-all/polkit-module-deny-all.c create mode 100644 modules/run-program/Makefile.am create mode 100644 modules/run-program/polkit-module-run-program.c diff --git a/configure.in b/configure.in index 25fc9af..97d0aa0 100644 --- a/configure.in +++ b/configure.in @@ -178,6 +178,7 @@ modules/Makefile modules/default/Makefile modules/allow-all/Makefile modules/deny-all/Makefile +modules/run-program/Makefile ]) dnl ========================================================================== diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 93de521..7e9464c 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -1,7 +1,7 @@ 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=) diff --git a/doc/man/polkit-module-allow-all.8.in b/doc/man/polkit-module-allow-all.8.in index decd097..17de422 100644 --- a/doc/man/polkit-module-allow-all.8.in +++ b/doc/man/polkit-module-allow-all.8.in @@ -7,7 +7,7 @@ polkit-module-allow-all \- grant access to all privileges .SH SYNOPSIS .PP -.B polkit-module-allow-all.so [privilege=] [user=] +.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= -Only consider requests where the privilege name matches the given -regular expression. Example: -.B privilege=hal-storage-mount* - -.TP 3n -.B user= -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\| diff --git a/doc/man/polkit-module-builtins.8.in b/doc/man/polkit-module-builtins.8.in new file mode 100644 index 0000000..333076b --- /dev/null +++ b/doc/man/polkit-module-builtins.8.in @@ -0,0 +1,55 @@ +.\" +.\" polkit-module-builtins manual page. +.\" Copyright (C) 2007 David Zeuthen +.\" +.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=] [user= ...] +.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= +Only consider requests where the privilege name matches the given +regular expression. Example: +.B privilege=hal-storage-mount* + +.TP 3n +.B user= +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 with a lot of help from many +others. diff --git a/doc/man/polkit-module-deny-all.8.in b/doc/man/polkit-module-deny-all.8.in index feee066..f2648c5 100644 --- a/doc/man/polkit-module-deny-all.8.in +++ b/doc/man/polkit-module-deny-all.8.in @@ -7,7 +7,7 @@ polkit-module-deny-all \- grant access to all privileges .SH SYNOPSIS .PP -.B polkit-module-deny-all.so [privilege=] [user=] +.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= -Only consider requests where the privilege name matches the given -regular expression. Example: -.B privilege=hal-storage-mount* - -.TP 3n -.B user= -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\| diff --git a/doc/man/polkit-module-run-program.8.in b/doc/man/polkit-module-run-program.8.in new file mode 100644 index 0000000..96f0868 --- /dev/null +++ b/doc/man/polkit-module-run-program.8.in @@ -0,0 +1,198 @@ +.\" +.\" polkit-module-run-program manual page. +.\" Copyright (C) 2007 David Zeuthen +.\" +.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\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= +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 with a lot of help from many +others. diff --git a/libpolkit/libpolkit-context.c b/libpolkit/libpolkit-context.c index 5dcc5b2..0f71293 100644 --- a/libpolkit/libpolkit-context.c +++ b/libpolkit/libpolkit-context.c @@ -43,6 +43,13 @@ #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) diff --git a/libpolkit/libpolkit-module.c b/libpolkit/libpolkit-module.c index 562e90c..414d2c8 100644 --- a/libpolkit/libpolkit-module.c +++ b/libpolkit/libpolkit-module.c @@ -34,6 +34,9 @@ # include #endif #include +#include +#include +#include #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 +_check_users_for_session (PolKitModuleInterface *module_interface, PolKitSession *session) +{ + uid_t uid; + GSList *list; + if ((list = module_interface->builtin_users) == NULL) + return TRUE; + if (session == NULL) + return FALSE; + if (!libpolkit_session_get_uid (session, &uid)) + return FALSE; + return _check_uid_in_list (list, uid); +} + +static gboolean +_check_users_for_caller (PolKitModuleInterface *module_interface, PolKitCaller *caller) +{ + uid_t uid; + GSList *list; + if ((list = module_interface->builtin_users) == NULL) + return TRUE; + if (caller == NULL) + return FALSE; + if (!libpolkit_caller_get_uid (caller, &uid)) + return FALSE; + return _check_uid_in_list (list, uid); +} + + +/** + * libpolkit_module_interface_check_builtin_confinement_for_session: + * @module_interface: the given module + * @pk_context: the PolicyKit context + * @privilege: the type of access to check for + * @resource: the resource in question + * @session: the session in question + * + * Check whether some of the built-in module options (e.g. privilege="hal-storage-*", + * user=davidz) confines the given module, e.g. whether it should be skipped. + * + * Returns: TRUE if, and only if, the module is confined from handling the request + **/ +gboolean +libpolkit_module_interface_check_builtin_confinement_for_session (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitSession *session) +{ + gboolean ret; + ret = TRUE; + + g_return_val_if_fail (module_interface != NULL, ret); + + if (!_check_privilege (module_interface, privilege)) + goto out; + if (!_check_users_for_session (module_interface, session)) + goto out; + + /* not confined */ + ret = FALSE; +out: + return ret; +} + +/** + * libpolkit_module_interface_check_builtin_confinement_for_caller: + * @module_interface: the given module + * @pk_context: the PolicyKit context + * @privilege: the type of access to check for + * @resource: the resource in question + * @caller: the resource in question + * + * Check whether some of the built-in module options (e.g. privilege="hal-storage-*", + * user=davidz) confines the given module, e.g. whether it should be skipped. + * + * Returns: TRUE if, and only if, the module is confined from handling the request + **/ +gboolean +libpolkit_module_interface_check_builtin_confinement_for_caller (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitCaller *caller) +{ + gboolean ret; + ret = TRUE; + + g_return_val_if_fail (module_interface != NULL, ret); + + if (!_check_privilege (module_interface, privilege)) + goto out; + if (!_check_users_for_caller (module_interface, caller)) + goto out; + + /* not confined */ + ret = FALSE; +out: + return ret; +} diff --git a/libpolkit/libpolkit-module.h b/libpolkit/libpolkit-module.h index 9f325e3..bb99383 100644 --- a/libpolkit/libpolkit-module.h +++ b/libpolkit/libpolkit-module.h @@ -189,4 +189,19 @@ PolKitModuleInterface *libpolkit_module_interface_load_module (const char *name, PolKitModuleControl libpolkit_module_interface_get_control (PolKitModuleInterface *module_interface); + +gboolean +libpolkit_module_interface_check_builtin_confinement_for_session (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitSession *session); + +gboolean +libpolkit_module_interface_check_builtin_confinement_for_caller (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitCaller *caller); + #endif /* LIBPOLKIT_MODULE_H */ diff --git a/modules/Makefile.am b/modules/Makefile.am index b8c1a0d..b4eee78 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = default allow-all deny-all +SUBDIRS = default allow-all deny-all run-program polkitconfdir = $(sysconfdir)/PolicyKit dist_polkitconf_DATA = PolicyKit.conf diff --git a/modules/allow-all/polkit-module-allow-all.c b/modules/allow-all/polkit-module-allow-all.c index 82701c2..507868c 100644 --- a/modules/allow-all/polkit-module-allow-all.c +++ b/modules/allow-all/polkit-module-allow-all.c @@ -35,90 +35,21 @@ #include #include #include -#include #include /* The symbol that libpolkit looks up when loading this module */ gboolean libpolkit_module_set_functions (PolKitModuleInterface *module_interface); -typedef struct { - regex_t preg; - uid_t uid; - gboolean have_regex; - gboolean have_uid; -} UserData; - -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 gboolean _module_init (PolKitModuleInterface *module_interface, int argc, char *argv[]) { - int n; - UserData *user_data; - - user_data = g_new0 (UserData, 1); - for (n = 1; n < argc; n++) { - if (g_str_has_prefix (argv[n], "privilege=")) { - const char *regex; - regex = argv[n] + 10; - if (regcomp (&(user_data->preg), regex, REG_EXTENDED) != 0) { - printf ("Regex '%s' didn't compile\n", regex); - goto error; - } - user_data->have_regex = TRUE; - } else if (g_str_has_prefix (argv[n], "user=")) { - const char *user; - user = argv[n] + 5; - user_data->uid = _util_name_to_uid (user, NULL); - if ((int) user_data->uid == -1) - goto error; - user_data->have_uid = TRUE; - } - } - - libpolkit_module_set_user_data (module_interface, user_data); - return TRUE; -error: - g_free (user_data); - return FALSE; } static void _module_shutdown (PolKitModuleInterface *module_interface) { - UserData *user_data; - user_data = libpolkit_module_get_user_data (module_interface); - g_free (user_data); } static PolKitResult @@ -128,48 +59,7 @@ _module_can_session_access_resource (PolKitModuleInterface *module_interface, PolKitResource *resource, PolKitSession *session) { - UserData *user_data; - PolKitResult result; - gboolean user_check_ok; - gboolean regex_check_ok; - - user_check_ok = FALSE; - regex_check_ok = FALSE; - - user_data = libpolkit_module_get_user_data (module_interface); - - if (user_data->have_regex) { - char *privilege_name; - if (libpolkit_privilege_get_privilege_id (privilege, &privilege_name)) { - if (regexec (&user_data->preg, privilege_name, 0, NULL, 0) == 0) { - regex_check_ok = TRUE; - } - } - } else { - regex_check_ok = TRUE; - } - - if (user_data->have_uid) { - if (session != NULL) { - uid_t session_uid; - if (libpolkit_session_get_uid (session, &session_uid) && session_uid == user_data->uid) { - user_check_ok = TRUE; - } - } - } else { - user_check_ok = TRUE; - } - - if (user_check_ok && regex_check_ok) { -#ifdef IS_POLKIT_MODULE_DENY_ALL - result = LIBPOLKIT_RESULT_NO; -#else - result = LIBPOLKIT_RESULT_YES; -#endif - } else { - result = LIBPOLKIT_RESULT_UNKNOWN_PRIVILEGE; - } - return result; + return LIBPOLKIT_RESULT_YES; } static PolKitResult @@ -179,46 +69,7 @@ _module_can_caller_access_resource (PolKitModuleInterface *module_interface, PolKitResource *resource, PolKitCaller *caller) { - UserData *user_data; - PolKitResult result; - gboolean user_check_ok; - gboolean regex_check_ok; - - user_check_ok = FALSE; - regex_check_ok = FALSE; - - user_data = libpolkit_module_get_user_data (module_interface); - - if (user_data->have_regex) { - char *privilege_name; - if (libpolkit_privilege_get_privilege_id (privilege, &privilege_name)) { - if (regexec (&user_data->preg, privilege_name, 0, NULL, 0) == 0) { - regex_check_ok = TRUE; - } - } - } else { - regex_check_ok = TRUE; - } - - if (user_data->have_uid) { - uid_t caller_uid; - if (libpolkit_caller_get_uid (caller, &caller_uid) && caller_uid == user_data->uid) { - user_check_ok = TRUE; - } - } else { - user_check_ok = TRUE; - } - - if (user_check_ok && regex_check_ok) { -#ifdef IS_POLKIT_MODULE_DENY_ALL - result = LIBPOLKIT_RESULT_NO; -#else - result = LIBPOLKIT_RESULT_YES; -#endif - } else { - result = LIBPOLKIT_RESULT_UNKNOWN_PRIVILEGE; - } - return result; + return LIBPOLKIT_RESULT_YES; } gboolean diff --git a/modules/deny-all/Makefile.am b/modules/deny-all/Makefile.am index db5a282..d6a134a 100644 --- a/modules/deny-all/Makefile.am +++ b/modules/deny-all/Makefile.am @@ -9,7 +9,7 @@ INCLUDES = \ -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \ -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ - @GLIB_CFLAGS@ @DBUS_CFLAGS@ -DIS_POLKIT_MODULE_DENY_ALL + @GLIB_CFLAGS@ @DBUS_CFLAGS@ polkitmoduledir = $(libdir)/PolicyKit/modules polkitmodule_LTLIBRARIES = \ @@ -17,7 +17,7 @@ polkitmodule_LTLIBRARIES = \ $(NULL) -polkit_module_deny_all_la_SOURCES = ../allow-all/polkit-module-allow-all.c +polkit_module_deny_all_la_SOURCES = polkit-module-deny-all.c polkit_module_deny_all_la_LDFLAGS = -no-undefined -module -avoid-version polkit_module_deny_all_la_LIBADD = $(top_builddir)/libpolkit/libpolkit.la @GLIB_LIBS@ diff --git a/modules/deny-all/polkit-module-deny-all.c b/modules/deny-all/polkit-module-deny-all.c new file mode 100644 index 0000000..feece30 --- /dev/null +++ b/modules/deny-all/polkit-module-deny-all.c @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/*************************************************************************** + * + * polkit-module-allow-all.c : PolicyKit module that says NO to everything + * + * Copyright (C) 2007 David Zeuthen, + * + * 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 + * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* The symbol that libpolkit looks up when loading this module */ +gboolean libpolkit_module_set_functions (PolKitModuleInterface *module_interface); + +static gboolean +_module_init (PolKitModuleInterface *module_interface, int argc, char *argv[]) +{ + return TRUE; +} + +static void +_module_shutdown (PolKitModuleInterface *module_interface) +{ +} + +static PolKitResult +_module_can_session_access_resource (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitSession *session) +{ + return LIBPOLKIT_RESULT_NO; +} + +static PolKitResult +_module_can_caller_access_resource (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitCaller *caller) +{ + return LIBPOLKIT_RESULT_NO; +} + +gboolean +libpolkit_module_set_functions (PolKitModuleInterface *module_interface) +{ + gboolean ret; + + ret = FALSE; + if (module_interface == NULL) + goto out; + + libpolkit_module_set_func_initialize (module_interface, _module_init); + libpolkit_module_set_func_shutdown (module_interface, _module_shutdown); + libpolkit_module_set_func_can_session_access_resource (module_interface, _module_can_session_access_resource); + libpolkit_module_set_func_can_caller_access_resource (module_interface, _module_can_caller_access_resource); + + ret = TRUE; +out: + return ret; +} diff --git a/modules/run-program/Makefile.am b/modules/run-program/Makefile.am new file mode 100644 index 0000000..057c996 --- /dev/null +++ b/modules/run-program/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + -I$(top_builddir) -I$(top_srcdir) \ + -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \ + -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_BIN_DIR=\""$(bindir)"\" \ + -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ + -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ + @GLIB_CFLAGS@ @DBUS_CFLAGS@ + +polkitmoduledir = $(libdir)/PolicyKit/modules +polkitmodule_LTLIBRARIES = \ + polkit-module-run-program.la \ + $(NULL) + + +polkit_module_run_program_la_SOURCES = polkit-module-run-program.c +polkit_module_run_program_la_LDFLAGS = -no-undefined -module -avoid-version +polkit_module_run_program_la_LIBADD = $(top_builddir)/libpolkit/libpolkit.la @GLIB_LIBS@ + +clean-local : + rm -f *~ diff --git a/modules/run-program/polkit-module-run-program.c b/modules/run-program/polkit-module-run-program.c new file mode 100644 index 0000000..af641c6 --- /dev/null +++ b/modules/run-program/polkit-module-run-program.c @@ -0,0 +1,359 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ +/*************************************************************************** + * + * polkit-module-run-program.c : determine policy by running a program + * + * Copyright (C) 2007 David Zeuthen, + * + * 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 + * (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* The symbol that libpolkit looks up when loading this module */ +gboolean libpolkit_module_set_functions (PolKitModuleInterface *module_interface); + +typedef struct { + int program_argc; + char **program_argv; +} UserData; + +static gboolean +_module_init (PolKitModuleInterface *module_interface, int argc, char *argv[]) +{ + int n; + UserData *user_data; + + user_data = g_new0 (UserData, 1); + for (n = 1; n < argc; n++) { + if (g_str_has_prefix (argv[n], "program=")) { + const char *program; + program = argv[n] + 8; + + if (!g_shell_parse_argv (program, + &user_data->program_argc, + &user_data->program_argv, NULL)) { + printf ("Cannot parse '%s' - skipping\n", program); + goto error; + } + + if (!g_file_test (user_data->program_argv[0], + G_FILE_TEST_IS_EXECUTABLE|G_FILE_TEST_IS_REGULAR)) { + printf ("Program '%s' is not an executable file - skipping\n", + user_data->program_argv[0]); + goto error; + } + + printf ("program = '%s'\n", user_data->program_argv[0]); + + /* TODO: + * O_o o_O... we could monitor the executable file :-) and trigger config changes! + */ + } + } + + if (user_data->program_argv == NULL) + goto error; + + libpolkit_module_set_user_data (module_interface, user_data); + + return TRUE; +error: + if (user_data->program_argv != NULL) + g_strfreev (user_data->program_argv); + g_free (user_data); + return FALSE; +} + +static void +_module_shutdown (PolKitModuleInterface *module_interface) +{ + UserData *user_data; + user_data = libpolkit_module_get_user_data (module_interface); + if (user_data != NULL) { + if (user_data->program_argv != NULL) + g_strfreev (user_data->program_argv); + g_free (user_data); + } +} + +static gboolean +_add_privilege_to_env (PolKitPrivilege *privilege, GPtrArray *envp) +{ + char *p_id; + if (!libpolkit_privilege_get_privilege_id (privilege, &p_id)) + goto error; + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_PRIVILEGE_ID=%s", p_id)); + return TRUE; +error: + return FALSE; +} + +static gboolean +_add_resource_to_env (PolKitResource *resource, GPtrArray *envp) +{ + char *r_type; + char *r_id; + if (!libpolkit_resource_get_resource_type (resource, &r_type)) + goto error; + if (!libpolkit_resource_get_resource_id (resource, &r_id)) + goto error; + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_RESOURCE_TYPE=%s", r_type)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_RESOURCE_ID=%s", r_id)); + return TRUE; +error: + return FALSE; +} + +static gboolean +_add_seat_to_env (PolKitSeat *seat, GPtrArray *envp) +{ + char *s_ck_objref; + if (!libpolkit_seat_get_ck_objref (seat, &s_ck_objref)) + goto error; + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SEAT_CK_OBJREF=%s", s_ck_objref)); + return TRUE; +error: + return FALSE; +} + +static gboolean +_add_session_to_env (PolKitSession *session, GPtrArray *envp) +{ + uid_t s_uid; + char *s_ck_objref; + gboolean s_ck_is_active; + gboolean s_ck_is_local; + char *s_ck_remote_host; + PolKitSeat *s_seat; + + if (!libpolkit_session_get_uid (session, &s_uid)) + goto error; + if (!libpolkit_session_get_ck_objref (session, &s_ck_objref)) + goto error; + if (!libpolkit_session_get_ck_is_active (session, &s_ck_is_active)) + goto error; + if (!libpolkit_session_get_ck_is_local (session, &s_ck_is_local)) + goto error; + if (!s_ck_is_local) + if (!libpolkit_session_get_ck_remote_host (session, &s_ck_remote_host)) + goto error; + if (!libpolkit_session_get_seat (session, &s_seat)) + goto error; + + if (!_add_seat_to_env (s_seat, envp)) + goto error; + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SESSION_UID=%d", (int) s_uid)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SESSION_CK_OBJREF=%s", s_ck_objref)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SESSION_CK_IS_ACTIVE=%d", s_ck_is_active)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SESSION_CK_IS_LOCAL=%d", s_ck_is_local)); + if (!s_ck_is_local) + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_SESSION_CK_REMOTE_HOST=%s", s_ck_remote_host)); + return TRUE; +error: + return FALSE; +} + +static gboolean +_add_caller_to_env (PolKitCaller *caller, GPtrArray *envp) +{ + uid_t c_uid; + pid_t c_pid; + char *c_selinux_context; + char *c_dbus_name; + PolKitSession *c_session; + + if (!libpolkit_caller_get_uid (caller, &c_uid)) + goto error; + if (!libpolkit_caller_get_pid (caller, &c_pid)) + goto error; + if (!libpolkit_caller_get_dbus_name (caller, &c_dbus_name)) + goto error; + if (!libpolkit_caller_get_selinux_context (caller, &c_selinux_context)) /* SELinux may not be available */ + c_selinux_context = NULL; + if (!libpolkit_caller_get_ck_session (caller, &c_session)) /* Caller may not originate from a session */ + c_session = NULL; + + if (c_session != NULL) + if (!_add_session_to_env (c_session, envp)) + goto error; + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_CALLER_UID=%d", (int) c_uid)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_CALLER_PID=%d", (int) c_pid)); + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_CALLER_DBUS_NAME=%s", c_dbus_name)); + if (c_selinux_context != NULL) + g_ptr_array_add (envp, g_strdup_printf ("POLKIT_CALLER_SELINUX_CONTEXT=%s", c_selinux_context)); + return TRUE; +error: + return FALSE; +} + +static gboolean +_run_program (UserData *user_data, char **envp, PolKitResult *result) +{ + int n; + int exit_status; + GError *g_error; + char *prog_stdout; + gboolean ret; + + g_error = NULL; + prog_stdout = NULL; + ret = FALSE; + + if (!g_spawn_sync ("/", + user_data->program_argv, + envp, + 0, + NULL, + NULL, + &prog_stdout, + NULL, + &exit_status, + &g_error)) { + printf ("error spawning '%s': %s\n", user_data->program_argv[0], g_error->message); + g_error_free (g_error); + goto error; + } + + /* only care if the program returned 0 */ + if (exit_status != 0) + goto error; + + /* only care about the first line */ + for (n = 0; prog_stdout[n] != '\n' && prog_stdout[n] != '\0'; n++) + ; + prog_stdout[n] = '\0'; + + if (!libpolkit_result_from_string_representation (prog_stdout, result)) { + printf ("malformed result '%s' from program\n", prog_stdout); + goto error; + } + + ret = TRUE; +error: + g_free (prog_stdout); + return ret; +} + + +static PolKitResult +_module_can_session_access_resource (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitSession *session) +{ + PolKitResult result; + UserData *user_data; + GPtrArray *envp; + + envp = NULL; + result = LIBPOLKIT_RESULT_UNKNOWN_PRIVILEGE; + + user_data = libpolkit_module_get_user_data (module_interface); + + envp = g_ptr_array_new (); + + if (!_add_privilege_to_env (privilege, envp)) + goto error; + if (!_add_resource_to_env (resource, envp)) + goto error; + if (!_add_session_to_env (session, envp)) + goto error; + g_ptr_array_add (envp, g_strdup ("PATH=/usr/bin:/bin")); + g_ptr_array_add (envp, g_strdup ("POLKIT_REQUEST_SESSION=1")); + g_ptr_array_add (envp, NULL); + + if (!_run_program (user_data, (char **) envp->pdata, &result)) + goto error; + +error: + if (envp != NULL) { + g_ptr_array_foreach (envp, (GFunc) g_free, NULL); + g_ptr_array_free (envp, TRUE); + } + return result; +} + +static PolKitResult +_module_can_caller_access_resource (PolKitModuleInterface *module_interface, + PolKitContext *pk_context, + PolKitPrivilege *privilege, + PolKitResource *resource, + PolKitCaller *caller) +{ + PolKitResult result; + UserData *user_data; + GPtrArray *envp; + + envp = NULL; + result = LIBPOLKIT_RESULT_NO; + user_data = libpolkit_module_get_user_data (module_interface); + + envp = g_ptr_array_new (); + if (!_add_privilege_to_env (privilege, envp)) + goto error; + if (!_add_resource_to_env (resource, envp)) + goto error; + if (!_add_caller_to_env (caller, envp)) + goto error; + g_ptr_array_add (envp, g_strdup ("PATH=/usr/bin:/bin")); + g_ptr_array_add (envp, g_strdup ("POLKIT_REQUEST_CALLER=1")); + g_ptr_array_add (envp, NULL); + if(!_run_program (user_data, (char **) envp->pdata, &result)) + goto error; + +error: + if (envp != NULL) { + g_ptr_array_foreach (envp, (GFunc) g_free, NULL); + g_ptr_array_free (envp, TRUE); + } + return result; +} + +gboolean +libpolkit_module_set_functions (PolKitModuleInterface *module_interface) +{ + gboolean ret; + + ret = FALSE; + if (module_interface == NULL) + goto out; + + libpolkit_module_set_func_initialize (module_interface, _module_init); + libpolkit_module_set_func_shutdown (module_interface, _module_shutdown); + libpolkit_module_set_func_can_session_access_resource (module_interface, _module_can_session_access_resource); + libpolkit_module_set_func_can_caller_access_resource (module_interface, _module_can_caller_access_resource); + + ret = TRUE; +out: + return ret; +} -- 2.7.4