diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2017-01-07 17:40:05 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2017-03-24 15:30:16 +0100 |
commit | 963a89c05ee0150e2d644ce2f5024afbf3d10572 (patch) | |
tree | 05cb29a7b626c96d94e182a9024a40b0579aa687 | |
parent | 174c00cdb88a87d1f52a5dd91a715fcead405609 (diff) | |
download | network-manager-applet-lr/selinux.tar.gz |
editor: warn users if certificates are labelled incorrectlylr/selinux
And provide an option to relabel them.
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | src/connection-editor/nm-connection-editor.c | 176 | ||||
-rw-r--r-- | src/connection-editor/nm-connection-editor.h | 4 | ||||
-rw-r--r-- | src/connection-editor/nm-connection-editor.ui | 221 |
5 files changed, 414 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index b3360bc7..5cf9efff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -694,7 +694,8 @@ src_connection_editor_nm_connection_editor_CPPFLAGS = \ -Isrc/libnma \ $(GTK_CFLAGS) \ $(LIBNM_CFLAGS) \ - $(JANSSON_CFLAGS) + $(JANSSON_CFLAGS) \ + $(SELINUX_CFLAGS) src_connection_editor_nm_connection_editor_LDADD = \ src/wireless-security/libwireless-security-libnm.la \ @@ -702,6 +703,7 @@ src_connection_editor_nm_connection_editor_LDADD = \ $(GTK_LIBS) \ $(LIBNM_LIBS) \ $(JANSSON_LIBS) \ + $(SELINUX_LIBS) \ -lm $(src_connection_editor_nm_connection_editor_OBJECTS): $(connection_editor_h_gen) diff --git a/configure.ac b/configure.ac index 843ca323..a1441164 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,18 @@ AM_CONDITIONAL(WITH_WWAN, test "${with_wwan}" != "no") dnl Check for gudev PKG_CHECK_MODULES(GUDEV, gudev-1.0 >= 147) +dnl SELinux +AC_ARG_WITH(selinux, AS_HELP_STRING([--with-selinux], [Enable support for adjusting SELinux labels in configuration editor (default: yes)])) +if (test "${with_selinux}" == "no"); then + AC_DEFINE(WITH_SELINUX, 0, [Define if libselinux is available]) +else + PKG_CHECK_MODULES(SELINUX, + [libselinux],, + AC_MSG_ERROR([libselinux is needed for SELinux label support in configuration editor. Use --without-selinux to build without it.])) + AC_DEFINE(WITH_SELINUX, 1, [Define if libselinux is available]) +fi +AM_CONDITIONAL(WITH_SELINUX, test "${with_selinux}" != "no") + dnl Jansson for team configuration editing AC_ARG_WITH(team, AS_HELP_STRING([--with-team], [Enable team configuration editor (default: yes)])) if (test "${with_team}" == "no"); then diff --git a/src/connection-editor/nm-connection-editor.c b/src/connection-editor/nm-connection-editor.c index f032f89d..ca74d12a 100644 --- a/src/connection-editor/nm-connection-editor.c +++ b/src/connection-editor/nm-connection-editor.c @@ -28,9 +28,15 @@ #include <string.h> #include <sys/types.h> #include <unistd.h> +#include <errno.h> #include <gdk/gdkx.h> +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +#endif + #include "nm-connection-editor.h" +#include "nma-cert-chooser.h" #include "ce-page.h" #include "page-general.h" @@ -177,6 +183,163 @@ update_sensitivity (NMConnectionEditor *editor) } } +#ifdef WITH_SELINUX +/* This is what the files in ~/.cert would get. */ +static const char certcon[] = "unconfined_u:object_r:home_cert_t:s0"; + +static gboolean +clear_name_if_present (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + gchar **filename = data; + gchar *existing; + + gtk_tree_model_get (model, iter, 2, &existing, -1); + if (g_strcmp0 (existing, *filename) == 0) { + *filename = NULL; + return TRUE; + } + + return FALSE; +} + +static void +update_relabel_list_filename (GtkListStore *store, char *filename) +{ + GtkTreeIter iter; + gboolean writable; + char *tcon; + /* Any kind of VPN would do. If OpenVPN can't access the files + * no VPN likely can. NetworkManager policy currently allows + * accessing home. It may make sense to tighten it some point. */ + static const char scon[] = "system_u:system_r:openvpn_t:s0"; + + gtk_tree_model_foreach (GTK_TREE_MODEL (store), clear_name_if_present, &filename); + if (filename == NULL) + return; + + if (getfilecon (filename, &tcon) == -1) { + /* Don't warn here, just ignore it. Perhaps the file + * is not on a SELinux-capable filesystem or something. */ + return; + } + + if (g_strcmp0 (certcon, tcon) == 0) + return; + + writable = (access (filename, W_OK) == 0); + + if (selinux_check_access (scon, tcon, "file", "open", NULL) == -1) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, writable, + 1, writable, + 2, filename, + -1); + } + + freecon (tcon); +} + +static void +update_relabel_list (GtkWidget *widget, GtkListStore *store) +{ + gchar *filename = NULL; + NMSetting8021xCKScheme scheme; + + if (!gtk_widget_is_sensitive (widget)) + return; + + if (NMA_IS_CERT_CHOOSER (widget)) { + filename = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (widget), &scheme); + if (filename && scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + update_relabel_list_filename (store, filename); + g_free (filename); + } + + filename = nma_cert_chooser_get_key (NMA_CERT_CHOOSER (widget), &scheme); + if (filename && scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + update_relabel_list_filename (store, filename); + g_free (filename); + } + } else if (GTK_IS_CONTAINER (widget)) { + gtk_container_foreach (GTK_CONTAINER (widget), + (GtkCallback) update_relabel_list, + store); + } +} + +static void +recheck_relabel (NMConnectionEditor *editor) +{ + gtk_list_store_clear (editor->relabel_list); + update_relabel_list (editor->window, editor->relabel_list); + + if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (editor->relabel_list), NULL)) + gtk_widget_show (editor->relabel_info); + else + gtk_widget_hide (editor->relabel_info); +} + +static void +relabel_toggled (GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data) +{ + NMConnectionEditor *editor = user_data; + GtkTreeIter iter; + gboolean relabel; + + if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (editor->relabel_list), &iter, path)) + g_return_if_reached (); + + gtk_tree_model_get (GTK_TREE_MODEL (editor->relabel_list), &iter, 0, &relabel, -1); + gtk_list_store_set (editor->relabel_list, &iter, 0, !relabel, -1); +} + +static gboolean +maybe_relabel (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + gboolean relabel; + gchar *filename; + + gtk_tree_model_get (model, iter, 0, &relabel, 2, &filename, -1); + if (relabel) { + if (setfilecon (filename, certcon) == -1) + g_warning ("setfilecon: %s\n", g_strerror (errno)); + } + + g_free (filename); + return FALSE; +} + +static void +relabel_button_clicked_cb (GtkWidget *widget, gpointer user_data) +{ + NMConnectionEditor *editor = NM_CONNECTION_EDITOR (user_data); + + if (gtk_dialog_run (GTK_DIALOG (editor->relabel_dialog)) == GTK_RESPONSE_APPLY) { + gtk_tree_model_foreach (GTK_TREE_MODEL (editor->relabel_list), maybe_relabel, NULL); + recheck_relabel (editor); + } + gtk_widget_hide (editor->relabel_dialog); +} +#else /* !WITH_SELINUX */ +static void +recheck_relabel (NMConnectionEditor *editor) +{ +} + +static void +relabel_toggled (GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data) +{ + g_return_if_reached (); +} + +static void +relabel_button_clicked_cb (GtkWidget *widget, gpointer user_data) +{ + g_return_if_reached (); +} +#endif /* WITH_SELINUX */ + static void connection_editor_validate (NMConnectionEditor *editor) { @@ -203,6 +366,8 @@ connection_editor_validate (NMConnectionEditor *editor) goto done; } + recheck_relabel (editor); + for (iter = editor->pages; iter; iter = g_slist_next (iter)) { if (!ce_page_validate (CE_PAGE (iter->data), editor->connection, &error)) { if (!validation_error) { @@ -267,7 +432,7 @@ nm_connection_editor_init (NMConnectionEditor *editor) { GtkWidget *dialog; GError *error = NULL; - const char *objects[] = { "nm-connection-editor", NULL }; + const char *objects[] = { "nm-connection-editor", "relabel_dialog", "relabel_list", NULL }; editor->builder = gtk_builder_new (); @@ -295,6 +460,13 @@ nm_connection_editor_init (NMConnectionEditor *editor) editor->cancel_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "cancel_button")); editor->export_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "export_button")); + editor->relabel_info = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_info")); + editor->relabel_dialog = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_dialog")); + editor->relabel_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_button")); + editor->relabel_list = GTK_LIST_STORE (gtk_builder_get_object (editor->builder, "relabel_list")); + gtk_builder_add_callback_symbol (editor->builder, "relabel_toggled", G_CALLBACK (relabel_toggled)); + + gtk_builder_connect_signals (editor->builder, editor); editor->inter_page_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) destroy_inter_page_item); } @@ -1109,6 +1281,8 @@ nm_connection_editor_run (NMConnectionEditor *self) G_CALLBACK (cancel_button_clicked_cb), self); g_signal_connect (G_OBJECT (self->export_button), "clicked", G_CALLBACK (export_button_clicked_cb), self); + g_signal_connect (G_OBJECT (self->relabel_button), "clicked", + G_CALLBACK (relabel_button_clicked_cb), self); nm_connection_editor_present (self); } diff --git a/src/connection-editor/nm-connection-editor.h b/src/connection-editor/nm-connection-editor.h index b7833be7..f8c12a80 100644 --- a/src/connection-editor/nm-connection-editor.h +++ b/src/connection-editor/nm-connection-editor.h @@ -60,6 +60,10 @@ typedef struct { GtkWidget *ok_button; GtkWidget *cancel_button; GtkWidget *export_button; + GtkWidget *relabel_info; + GtkWidget *relabel_dialog; + GtkWidget *relabel_button; + GtkListStore *relabel_list; gboolean busy; gboolean init_run; diff --git a/src/connection-editor/nm-connection-editor.ui b/src/connection-editor/nm-connection-editor.ui index 58b3afad..2ef5f3f1 100644 --- a/src/connection-editor/nm-connection-editor.ui +++ b/src/connection-editor/nm-connection-editor.ui @@ -132,6 +132,79 @@ <property name="can_focus">False</property> <property name="spacing">6</property> <child> + <object class="GtkInfoBar" id="relabel_info"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="message_type">warning</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <object class="GtkButton" id="relabel_button"> + <property name="label" translatable="yes">Fix</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child internal-child="content_area"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="spacing">16</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Security labels may prevent some files from being used with certificate authentication.</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> <object class="GtkVBox" id="vbox3"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -189,7 +262,7 @@ <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">0</property> + <property name="position">1</property> </packing> </child> <child> @@ -272,10 +345,156 @@ <property name="expand">False</property> <property name="fill">True</property> <property name="padding">6</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkListStore" id="relabel_list"> + <columns> + <!-- column-name relabel --> + <column type="gboolean"/> + <!-- column-name sensitive --> + <column type="gboolean"/> + <!-- column-name filename --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="relabel_dialog"> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="title" translatable="yes">File Relabel</property> + <property name="modal">True</property> + <property name="default_width">500</property> + <property name="default_height">300</property> + <property name="type_hint">dialog</property> + <property name="transient_for">nm-connection-editor</property> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="button1"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button2"> + <property name="label" translatable="yes">_Relabel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">The following files are not labelled for use with certificate authentication. Do you wish to adjust the labels?</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="relabel_view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">relabel_list</property> + <property name="headers_visible">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="relabel"> + <property name="title" translatable="yes">Relabel</property> + <child> + <object class="GtkCellRendererToggle" id="relabel_renderer"> + <signal name="toggled" handler="relabel_toggled" swapped="no"/> + </object> + <attributes> + <attribute name="sensitive">1</attribute> + <attribute name="active">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="filename"> + <property name="title" translatable="yes">Filename</property> + <child> + <object class="GtkCellRendererText" id="filename_renderer"/> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> + <action-widgets> + <action-widget response="-6">button1</action-widget> + <action-widget response="-10">button2</action-widget> + </action-widgets> </object> </interface> |