summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2017-01-07 17:40:05 +0100
committerLubomir Rintel <lkundrak@v3.sk>2017-03-24 15:30:16 +0100
commit963a89c05ee0150e2d644ce2f5024afbf3d10572 (patch)
tree05cb29a7b626c96d94e182a9024a40b0579aa687
parent174c00cdb88a87d1f52a5dd91a715fcead405609 (diff)
downloadnetwork-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.am4
-rw-r--r--configure.ac12
-rw-r--r--src/connection-editor/nm-connection-editor.c176
-rw-r--r--src/connection-editor/nm-connection-editor.h4
-rw-r--r--src/connection-editor/nm-connection-editor.ui221
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>