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



commit 963a89c05ee0150e2d644ce2f5024afbf3d10572
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.

 Makefile.am                                   |    4 +-
 configure.ac                                  |   12 ++
 src/connection-editor/nm-connection-editor.c  |  176 +++++++++++++++++++-
 src/connection-editor/nm-connection-editor.h  |    4 +
 src/connection-editor/nm-connection-editor.ui |  221 ++++++++++++++++++++++++-
 5 files changed, 414 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index b3360bc..5cf9eff 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 843ca32..a144116 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 f032f89..ca74d12 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 b7833be..f8c12a8 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 58b3afa..2ef5f3f 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>


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