summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-12-10 08:51:03 +0100
committerThomas Haller <thaller@redhat.com>2019-12-10 17:04:49 +0100
commita3a3287dd596e65d80c497ddc4f1cb454e9150c8 (patch)
tree573ffdbb3e10bbdc7b306bb5e662bd45068f3c4e
parent8b9f82be0b354564e03eab48b1c29187214e8343 (diff)
downloadNetworkManager-th/polkit-root-only.tar.gz
core: add main.auth-polkit option "root-only"th/polkit-root-only
We always build with PolicyKit support enabled, because it has no additional dependencies, beside some D-Bus calls. However, in NetworkManager.conf the user could configure "main.auth-polkit" to disable PolicyKit. However, previously it would only allow to disable PolicyKit while granting access to all users. I think it's useful to have an option that disables PolicyKit and grants access only to root. I think we should not go too far in implementing our own authorization mechanisms beside PolicyKit (e.g. you cannot disable PolicyKit and grant access based on group membership of the user). However, disabling PolicyKit can be useful sometimes, and it's simple to implement a "root-only" setup. Note one change is that when NetworkManager now runs without a D-Bus connection (in initrd), it would deny all non-root requests. Previously it would grant access. I think there should be little difference in practice, because if we have no D-Bus we also don't have any requests to authenticate.
-rw-r--r--configure.ac12
-rw-r--r--man/NetworkManager.conf.xml7
-rw-r--r--meson_options.txt2
-rw-r--r--src/main.c5
-rw-r--r--src/nm-auth-manager.c61
-rw-r--r--src/nm-auth-manager.h3
-rw-r--r--src/nm-config-data.c46
-rw-r--r--src/nm-config-data.h24
-rw-r--r--src/nm-config.h1
9 files changed, 125 insertions, 36 deletions
diff --git a/configure.ac b/configure.ac
index 70d8ff29cb..44bf51a11f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -614,18 +614,18 @@ AM_CONDITIONAL(WITH_JSON_VALIDATION, test "${enable_json_validation}" != "no")
# default configuration for main.auth-polkit. User can always enable/disable polkit
# authorization via config.
AC_ARG_ENABLE(polkit,
- AS_HELP_STRING([--enable-polkit=yes|no],
+ AS_HELP_STRING([--enable-polkit=yes|no|root-only],
[set default value for auth-polkit configuration option. This value can be overwritten by NM configuration. 'disabled' is an alias for 'no']),
[enable_polkit=${enableval}], [enable_polkit=yes])
-if (test "${enable_polkit}" != "no" -a "${enable_polkit}" != "disabled"); then
+if test "${enable_polkit}" == "root-only" ; then
+ enable_polkit='root-only'
+elif test "${enable_polkit}" != "no" -a "${enable_polkit}" != "disabled" ; then
enable_polkit=true
- AC_DEFINE(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "true", [The default value of the auth-polkit configuration option])
- AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, true)
else
enable_polkit=false
- AC_DEFINE(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "false", [The default value of the auth-polkit configuration option])
- AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, false)
fi
+AC_DEFINE_UNQUOTED(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "$enable_polkit", [The default value of the auth-polkit configuration option])
+AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, "$enable_polkit")
PKG_CHECK_MODULES(POLKIT, [polkit-agent-1 >= 0.97], [have_pk_agent=yes],[have_pk_agent=no])
AC_ARG_ENABLE(polkit-agent,
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index c213d342b6..6d78ab161c 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -158,8 +158,11 @@ plugins-=remove-me
<varlistentry>
<term><varname>auth-polkit</varname></term>
<listitem><para>Whether the system uses PolicyKit for authorization.
- If <literal>false</literal>, all requests will be allowed. If
- <literal>true</literal>, non-root requests are authorized using PolicyKit.
+ If <literal>true</literal>, non-root requests are authorized using PolicyKit.
+ Requests from root (user ID zero) are always granted without asking PolicyKit.
+ If <literal>false</literal>, all requests will be allowed and PolicyKit is
+ not used. If set to <literal>root-only</literal> PolicyKit is not used and
+ all requests except root are denied.
The default value is <literal>&NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT;</literal>.
</para></listitem>
</varlistentry>
diff --git a/meson_options.txt b/meson_options.txt
index 4f4f0d5c5a..041d9bfc38 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -14,7 +14,7 @@ option('session_tracking_consolekit', type: 'boolean', value: true, description:
option('session_tracking', type: 'combo', choices: ['systemd', 'elogind', 'no'], value: 'systemd', description: 'Compatibility option to choose one session tracking module')
option('suspend_resume', type: 'combo', choices: ['upower', 'systemd', 'elogind', 'consolekit', 'auto'], value: 'auto', description: 'Build NetworkManager with specific suspend/resume support')
option('polkit', type: 'boolean', value: true, description: 'User auth-polkit configuration option.')
-option('config_auth_polkit_default', type: 'combo', choices: ['default', 'true', 'false'], value: 'default', description: 'Default value for configuration main.auth-polkit.')
+option('config_auth_polkit_default', type: 'combo', choices: ['default', 'true', 'false', 'root-only'], value: 'default', description: 'Default value for configuration main.auth-polkit.')
option('modify_system', type: 'boolean', value: false, description: 'Allow users to modify system connections')
option('polkit_agent', type: 'boolean', value: false, description: 'enable polkit agent for clients')
option('selinux', type: 'boolean', value: true, description: 'Build with SELinux')
diff --git a/src/main.c b/src/main.c
index 24157b18c6..b1466c1852 100644
--- a/src/main.c
+++ b/src/main.c
@@ -410,10 +410,7 @@ main (int argc, char *argv[])
NM_UTILS_KEEP_ALIVE (config, nm_netns_get (), "NMConfig-depends-on-NMNetns");
- nm_auth_manager_setup (nm_config_data_get_value_boolean (nm_config_get_data_orig (config),
- NM_CONFIG_KEYFILE_GROUP_MAIN,
- NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
- NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_BOOL));
+ nm_auth_manager_setup (nm_config_data_get_main_auth_polkit (nm_config_get_data_orig (config)));
manager = nm_manager_setup ();
diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c
index 244342c035..3f248aeeec 100644
--- a/src/nm-auth-manager.c
+++ b/src/nm-auth-manager.c
@@ -42,7 +42,7 @@ typedef struct {
guint changed_signal_id;
bool disposing:1;
bool shutting_down:1;
- bool polkit_enabled_construct_only:1;
+ NMAuthPolkitMode auth_polkit_mode:3;
} NMAuthManagerPrivate;
struct _NMAuthManager {
@@ -118,6 +118,7 @@ struct _NMAuthManagerCallId {
gpointer user_data;
guint64 call_numid;
guint idle_id;
+ bool idle_is_authorized:1;
};
#define cancellation_id_to_str_a(call_numid) \
@@ -256,9 +257,10 @@ static gboolean
_call_on_idle (gpointer user_data)
{
NMAuthManagerCallId *call_id = user_data;
- gboolean is_authorized = TRUE;
+ gboolean is_authorized;
gboolean is_challenge = FALSE;
+ is_authorized = call_id->idle_is_authorized;
call_id->idle_id = 0;
_LOG2T (call_id, "completed: authorized=%d, challenge=%d (simulated)",
@@ -312,22 +314,25 @@ nm_auth_manager_check_authorization (NMAuthManager *self,
call_id = g_slice_new (NMAuthManagerCallId);
*call_id = (NMAuthManagerCallId) {
- .self = g_object_ref (self),
- .callback = callback,
- .user_data = user_data,
- .call_numid = ++priv->call_numid_counter,
+ .self = g_object_ref (self),
+ .callback = callback,
+ .user_data = user_data,
+ .call_numid = ++priv->call_numid_counter,
+ .idle_is_authorized = TRUE,
};
c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst);
- if (!priv->dbus_connection) {
- _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding due to polkit authorization disabled)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
- call_id->idle_id = g_idle_add (_call_on_idle, call_id);
- } else if (nm_auth_subject_is_internal (subject)) {
+ if (nm_auth_subject_is_internal (subject)) {
_LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for internal request)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
call_id->idle_id = g_idle_add (_call_on_idle, call_id);
} else if (nm_auth_subject_get_unix_process_uid (subject) == 0) {
_LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for root)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
call_id->idle_id = g_idle_add (_call_on_idle, call_id);
+ } else if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) {
+ _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (PolicyKit disabled and always %s authorization to non-root user)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)),
+ priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL ? "grant" : "deny");
+ call_id->idle_is_authorized = (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL);
+ call_id->idle_id = g_idle_add (_call_on_idle, call_id);
} else {
GVariant *parameters;
GVariantBuilder builder;
@@ -461,11 +466,17 @@ static void
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE ((NMAuthManager *) object);
+ int v_int;
switch (prop_id) {
case PROP_POLKIT_ENABLED:
/* construct-only */
- priv->polkit_enabled_construct_only = !!g_value_get_boolean (value);
+ v_int = g_value_get_int (value);
+ g_return_if_fail (NM_IN_SET (v_int, NM_AUTH_POLKIT_MODE_ROOT_ONLY,
+ NM_AUTH_POLKIT_MODE_ALLOW_ALL,
+ NM_AUTH_POLKIT_MODE_USE_POLKIT));
+ priv->auth_polkit_mode = v_int;
+ nm_assert (priv->auth_polkit_mode == v_int);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -481,6 +492,7 @@ nm_auth_manager_init (NMAuthManager *self)
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
c_list_init (&priv->calls_lst_head);
+ priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
}
static void
@@ -493,8 +505,11 @@ constructed (GObject *object)
G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object);
- if (!priv->polkit_enabled_construct_only) {
- create_message = "polkit disabled";
+ if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) {
+ if (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ROOT_ONLY)
+ create_message = "polkit disabled, root-only";
+ else
+ create_message = "polkit disabled, allow-all";
goto out;
}
@@ -503,7 +518,8 @@ constructed (GObject *object)
if (!priv->dbus_connection) {
/* This warrants an info level message. */
logl = LOGL_INFO;
- create_message = "D-Bus connection not available. Polkit is disabled and all requests are authenticated.";
+ create_message = "D-Bus connection not available. Polkit is disabled and only root will be authorized.";
+ priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
goto out;
}
@@ -527,14 +543,17 @@ out:
}
NMAuthManager *
-nm_auth_manager_setup (gboolean polkit_enabled)
+nm_auth_manager_setup (NMAuthPolkitMode auth_polkit_mode)
{
NMAuthManager *self;
g_return_val_if_fail (!singleton_instance, singleton_instance);
+ nm_assert (NM_IN_SET (auth_polkit_mode, NM_AUTH_POLKIT_MODE_ROOT_ONLY,
+ NM_AUTH_POLKIT_MODE_ALLOW_ALL,
+ NM_AUTH_POLKIT_MODE_USE_POLKIT));
self = g_object_new (NM_TYPE_AUTH_MANAGER,
- NM_AUTH_MANAGER_POLKIT_ENABLED, polkit_enabled,
+ NM_AUTH_MANAGER_POLKIT_ENABLED, (int) auth_polkit_mode,
NULL);
_LOGD ("set instance");
@@ -579,11 +598,11 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass)
object_class->dispose = dispose;
obj_properties[PROP_POLKIT_ENABLED] =
- g_param_spec_boolean (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "",
- FALSE,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
+ g_param_spec_int (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "",
+ NM_AUTH_POLKIT_MODE_ROOT_ONLY, NM_AUTH_POLKIT_MODE_USE_POLKIT, NM_AUTH_POLKIT_MODE_USE_POLKIT,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h
index 3e3124cacb..ab924e69a5 100644
--- a/src/nm-auth-manager.h
+++ b/src/nm-auth-manager.h
@@ -7,6 +7,7 @@
#define NM_AUTH_MANAGER_H
#include "nm-auth-subject.h"
+#include "nm-config-data.h"
/*****************************************************************************/
@@ -55,7 +56,7 @@ typedef struct _NMAuthManagerClass NMAuthManagerClass;
GType nm_auth_manager_get_type (void);
-NMAuthManager *nm_auth_manager_setup (gboolean polkit_enabled);
+NMAuthManager *nm_auth_manager_setup (NMAuthPolkitMode auth_polkit_mode);
NMAuthManager *nm_auth_manager_get (void);
void nm_auth_manager_force_shutdown (NMAuthManager *self);
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index b5868b7b1a..6461331c0a 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -386,6 +386,52 @@ _nm_config_data_get_keyfile_user (const NMConfigData *self)
/*****************************************************************************/
+static NMAuthPolkitMode
+nm_auth_polkit_mode_from_string (const char *str)
+{
+ int as_bool;
+
+ if (!str)
+ return NM_AUTH_POLKIT_MODE_UNKNOWN;
+
+ if (nm_streq (str, "root-only"))
+ return NM_AUTH_POLKIT_MODE_ROOT_ONLY;
+
+ as_bool = _nm_utils_ascii_str_to_bool (str, -1);
+ if (as_bool != -1) {
+ return as_bool
+ ? NM_AUTH_POLKIT_MODE_USE_POLKIT
+ : NM_AUTH_POLKIT_MODE_ALLOW_ALL;
+ }
+
+ return NM_AUTH_POLKIT_MODE_UNKNOWN;
+}
+
+NMAuthPolkitMode
+nm_config_data_get_main_auth_polkit (const NMConfigData *self)
+{
+ NMAuthPolkitMode auth_polit_mode;
+ const char *str;
+
+ str = nm_config_data_get_value (self,
+ NM_CONFIG_KEYFILE_GROUP_MAIN,
+ NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
+ NM_CONFIG_GET_VALUE_STRIP
+ | NM_CONFIG_GET_VALUE_NO_EMPTY);
+ auth_polit_mode = nm_auth_polkit_mode_from_string (str);
+ if (auth_polit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
+ auth_polit_mode = nm_auth_polkit_mode_from_string (NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT);
+ if (auth_polit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
+ nm_assert_not_reached ();
+ auth_polit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
+ }
+ }
+
+ return auth_polit_mode;
+}
+
+/*****************************************************************************/
+
/**
* nm_config_data_get_groups:
* @self: the #NMConfigData instance
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index a6f03902d5..f83ab92874 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -6,6 +6,28 @@
#ifndef NM_CONFIG_DATA_H
#define NM_CONFIG_DATA_H
+/*****************************************************************************/
+
+typedef enum {
+
+ /* an invalid mode. */
+ NM_AUTH_POLKIT_MODE_UNKNOWN,
+
+ /* don't use PolicyKit, but only allow root user (uid 0). */
+ NM_AUTH_POLKIT_MODE_ROOT_ONLY,
+
+ /* don't use PolicyKit, but allow all requests. */
+ NM_AUTH_POLKIT_MODE_ALLOW_ALL,
+
+ /* use PolicyKit to authorize requests. Root user (uid 0) always
+ * gets a free pass, without consulting PolicyKit. If PolicyKit is not
+ * running, authorization will fail for non root users. */
+ NM_AUTH_POLKIT_MODE_USE_POLKIT,
+
+} NMAuthPolkitMode;
+
+/*****************************************************************************/
+
#define NM_TYPE_CONFIG_DATA (nm_config_data_get_type ())
#define NM_CONFIG_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONFIG_DATA, NMConfigData))
#define NM_CONFIG_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONFIG_DATA, NMConfigDataClass))
@@ -132,6 +154,8 @@ const char *nm_config_data_get_connectivity_response (const NMConfigData *config
int nm_config_data_get_autoconnect_retries_default (const NMConfigData *config_data);
+NMAuthPolkitMode nm_config_data_get_main_auth_polkit (const NMConfigData *config_data);
+
const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config_data);
gboolean nm_config_data_get_no_auto_default_for_device (const NMConfigData *self, NMDevice *device);
diff --git a/src/nm-config.h b/src/nm-config.h
index e3e658c702..d9460ebb46 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -219,7 +219,6 @@ extern char *_nm_config_match_env;
#define NM_CONFIG_DEVICE_STATE_DIR ""NMRUNDIR"/devices"
-#define NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_BOOL (nm_streq (""NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "true"))
#define NM_CONFIG_DEFAULT_LOGGING_AUDIT_BOOL (nm_streq (""NM_CONFIG_DEFAULT_LOGGING_AUDIT, "true"))
typedef enum {