diff --git a/configure.ac b/configure.ac index 3fbcd86512..2dc18bc15f 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 cdf55ed62e..c0c05147a0 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -158,8 +158,11 @@ plugins-=remove-me auth-polkit Whether the system uses PolicyKit for authorization. - If false, all requests will be allowed. If - true, non-root requests are authorized using PolicyKit. + If true, non-root requests are authorized using PolicyKit. + Requests from root (user ID zero) are always granted without asking PolicyKit. + If false, all requests will be allowed and PolicyKit is + not used. If set to root-only PolicyKit is not used and + all requests except root are denied. The default value is &NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT;. 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 083f98aaaa..33e3bb2ccd 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" /*****************************************************************************/ @@ -49,7 +50,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..8f53304aa6 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_polkit_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_polkit_mode = nm_auth_polkit_mode_from_string (str); + if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) { + auth_polkit_mode = nm_auth_polkit_mode_from_string (NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT); + if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) { + nm_assert_not_reached (); + auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY; + } + } + + return auth_polkit_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 {