[network-manager-applet/lr/selinux: 2/2] editor: warn users if certificates are labelled incorrectly



commit 6921ba5f79384c2de4ad6615023e92c39bc0f925
Author: Lubomir Rintel <lkundrak v3 sk>
Date:   Sat Jan 7 17:40:05 2017 +0100

    editor: warn users if certificates are labelled incorrectly
    
    And provide an option to relabel them.

 configure.ac                                  |   12 ++
 src/connection-editor/Makefile.am             |    2 +
 src/connection-editor/nm-connection-editor.c  |  165 ++++++++++++++++++-
 src/connection-editor/nm-connection-editor.h  |    4 +
 src/connection-editor/nm-connection-editor.ui |  222 ++++++++++++++++++++++++-
 5 files changed, 403 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 820139e..cfefa6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,6 +123,18 @@ AM_CONDITIONAL(WITH_WWAN, test "${with_wwan}" != "no")
 dnl Check for gudev
 PKG_CHECK_MODULES(GUDEV, gudev-1.0 >= 147)
 
+dnl Jansson for selinux configuration editing
+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 in libnm (default: yes)]))
 if (test "${with_team}" == "no"); then
diff --git a/src/connection-editor/Makefile.am b/src/connection-editor/Makefile.am
index 03fbef9..e85f6b6 100644
--- a/src/connection-editor/Makefile.am
+++ b/src/connection-editor/Makefile.am
@@ -4,6 +4,7 @@ nm_connection_editor_CPPFLAGS = \
        $(GTK_CFLAGS) \
        $(LIBNM_CFLAGS) \
        $(JANSSON_CFLAGS) \
+       $(SELINUX_CFLAGS) \
        -DNM_VERSION_MIN_REQUIRED=NM_VERSION_1_4 \
        -DNM_VERSION_MAX_ALLOWED=NM_VERSION_1_4 \
        -DICONDIR=\""$(datadir)/icons"\" \
@@ -97,6 +98,7 @@ nm_connection_editor_LDADD = \
        $(GTK_LIBS) \
        $(LIBNM_LIBS) \
        $(JANSSON_LIBS) \
+       $(SELINUX_LIBS) \
        -lm
 
 ce-resources.h: ce.gresource.xml
diff --git a/src/connection-editor/nm-connection-editor.c b/src/connection-editor/nm-connection-editor.c
index 70f008e..e076175 100644
--- a/src/connection-editor/nm-connection-editor.c
+++ b/src/connection-editor/nm-connection-editor.c
@@ -28,8 +28,13 @@
 #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 "ce-page.h"
@@ -177,6 +182,153 @@ 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) {
+               g_free  (*filename);
+               *filename = NULL;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void
+update_relabel_list (GtkWidget *widget, GtkListStore *store)
+{
+       gchar *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";
+
+       if (!gtk_widget_is_sensitive (widget))
+               return;
+
+       if (GTK_IS_FILE_CHOOSER_BUTTON (widget)) {
+               filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+
+               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. */
+                       g_free (filename);
+                       return;
+               }
+
+               if (g_strcmp0 (certcon, tcon) == 0) {
+                       g_free (filename);
+                       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);
+               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 +355,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 +421,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 +449,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);
 }
@@ -1050,6 +1211,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 ff762df..78532d5 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 15e2a7b..aa2ecaf 100644
--- a/src/connection-editor/nm-connection-editor.ui
+++ b/src/connection-editor/nm-connection-editor.ui
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
 <interface>
   <requires lib="gtk+" version="3.4"/>
   <object class="GtkDialog" id="NMConnectionList">
@@ -131,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>
@@ -188,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>
@@ -259,10 +333,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>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]