[gnome-system-tools] Add checks when removing admins or admin rights



commit dea27ce554add6ece8116dfac4c926d701528f1d
Author: Milan Bouchet-Valat <nalimilan club fr>
Date:   Fri Dec 11 20:26:33 2009 +0100

    Add checks when removing admins or admin rights
    
    When deleting an user, check that it's not the only amdin account left. If that's the case, show an error dialog and block deletion.
    
    When removing admin rights from an account, warn if the selected user is the current one (i.e. the one corresponding to OobsSelfConfig). Refuse to remove the admin rights of the last admin left on the system. This is supported either when moving from a profile implying admin membership to a non-admin one, or when unselecting the admin privilege in the privileges table. People can still lose admin rights when tweaking groups membership, but they must know what they are doing...

 src/users/privileges-table.c |   17 ++++-
 src/users/user-settings.c    |  138 +++++++++++++++++++++++++++++++++++++++---
 src/users/user-settings.h    |    3 +
 3 files changed, 146 insertions(+), 12 deletions(-)
---
diff --git a/src/users/privileges-table.c b/src/users/privileges-table.c
index 64fc98f..5aaf589 100644
--- a/src/users/privileges-table.c
+++ b/src/users/privileges-table.c
@@ -31,6 +31,7 @@
 #include "gst.h"
 #include "privileges-table.h"
 #include "user-profiles.h"
+#include "user-settings.h"
 
 extern GstTool *tool;
 
@@ -50,7 +51,7 @@ struct _PrivilegeDescription {
 /* keep this sorted, or you'll go to hell */
 static const PrivilegeDescription descriptions[] = {
 	{ "adm", N_("Monitor system logs") },
-	{ "admin", N_("Administer the system") },
+	{ ADMIN_GROUP, N_("Administer the system") },
 	{ "audio", N_("Use audio devices") },
 	{ "cdrom", N_("Use CD-ROM drives") },
 	{ "cdwrite", N_("Burn CDs / DVDs") },
@@ -102,6 +103,7 @@ on_user_privilege_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointe
 	GtkTreeModel *model, *child_model;
 	GtkTreePath  *path  = gtk_tree_path_new_from_string (path_str);
 	GtkTreeIter   iter, child_iter;
+	OobsGroup    *group;
 	gboolean      value;
 
 	model = (GtkTreeModel*) data;
@@ -111,8 +113,17 @@ on_user_privilege_toggled (GtkCellRendererToggle *cell, gchar *path_str, gpointe
 		gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
 								  &child_iter, &iter);
 
-		gtk_tree_model_get (child_model, &child_iter, COL_MEMBER, &value, -1);
-		gtk_list_store_set (GTK_LIST_STORE (child_model), &child_iter, COL_MEMBER, !value, -1);
+		gtk_tree_model_get (child_model, &child_iter,
+		                    COL_MEMBER, &value,
+		                    COL_GROUP, &group, -1);
+
+		/* check that current user should be allowed to lose admin rights,
+		 * possibly showing a warning/error dialog */
+		if (!value || strcmp (oobs_group_get_name (group), ADMIN_GROUP) != 0
+		           || user_settings_check_revoke_admin_rights ())
+			gtk_list_store_set (GTK_LIST_STORE (child_model), &child_iter, COL_MEMBER, !value, -1);
+
+		g_object_unref (group);
 	}
 
 	gtk_tree_path_free (path);
diff --git a/src/users/user-settings.c b/src/users/user-settings.c
index 3dd94a3..278fabe 100644
--- a/src/users/user-settings.c
+++ b/src/users/user-settings.c
@@ -54,8 +54,15 @@ static gboolean
 check_user_delete (OobsUser *user)
 {
 	GtkWidget *dialog;
+	OobsGroupsConfig *config;
+	OobsGroup *admin_group;
+	GList *admin_users;
 	gint response;
 
+	config = OOBS_GROUPS_CONFIG (GST_USERS_TOOL (tool)->groups_config);
+	admin_group = oobs_groups_config_get_from_name (config, ADMIN_GROUP);
+	admin_users = oobs_group_get_users (admin_group);
+
 	if (oobs_user_get_uid (user) == 0) {
 		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
 						 GTK_DIALOG_MODAL,
@@ -65,10 +72,7 @@ check_user_delete (OobsUser *user)
 
 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 							  _("This would leave the system unusable."));
-		gtk_dialog_run (GTK_DIALOG (dialog));
-		gtk_widget_destroy (dialog);
 
-		return FALSE;
 	}
 	else if (oobs_user_get_active (user)) {
 		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
@@ -80,6 +84,21 @@ check_user_delete (OobsUser *user)
 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 						  _("Please ensure the user has logged out before deleting this account."));
 	}
+	/* don't allow deleting the last admin */
+	else if (oobs_user_is_in_group (user, admin_group)
+	         && g_list_length (admin_users) < 2)
+	{
+		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
+		                                 GTK_DIALOG_MODAL,
+		                                 GTK_MESSAGE_ERROR,
+		                                 GTK_BUTTONS_CLOSE,
+		                                 _("Can't delete the only administrator account"));
+		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+		                                          _("%s is the only administrator on this computer. "
+		                                            "Deleting this account would lock you out of "
+		                                            "administrating the system."),
+		                                          oobs_user_get_full_name (user));
+	}
 	else {
 		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
 		                                 GTK_DIALOG_MODAL,
@@ -102,6 +121,8 @@ check_user_delete (OobsUser *user)
 	gst_dialog_remove_edit_dialog (tool->main_dialog, dialog);
 
 	gtk_widget_destroy (dialog);
+	g_object_unref (admin_group);
+	g_list_free (admin_users);
 
 	return (response == GTK_RESPONSE_ACCEPT);
 }
@@ -627,6 +648,100 @@ check_password (OobsUser *user)
 }
 
 /*
+ * Check that current user is not removing himself from the admin group: warn if it's the case.
+ * Also, if selected user is the only admin left, we directly show an error dialog.
+ * (This function assumes selected user is an administrator, so check this before calling.)
+ */
+gboolean
+user_settings_check_revoke_admin_rights ()
+{
+	OobsGroupsConfig *groups_config;
+	OobsSelfConfig *self_config;
+	OobsUser *user;
+	OobsGroup *admin_group;
+	GList *members;
+	GtkWidget *dialog;
+	int response;
+
+	groups_config = OOBS_GROUPS_CONFIG (GST_USERS_TOOL (tool)->groups_config);
+	self_config = OOBS_SELF_CONFIG (GST_USERS_TOOL (tool)->self_config);
+
+	user = users_table_get_current ();
+	admin_group = oobs_groups_config_get_from_name (groups_config, ADMIN_GROUP);
+	members = oobs_group_get_users (admin_group);
+
+	/* check that user is no alone in the admin group */
+	if (g_list_length (members) < 2) {
+		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
+		                                 GTK_DIALOG_MODAL,
+		                                 GTK_MESSAGE_ERROR,
+		                                 GTK_BUTTONS_CLOSE,
+		                                 _("Can't revoke administration rights"));
+
+		gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
+		                                            _("%s is the only administrator on this computer. "
+		                                              "Revoking administration rights for this account "
+		                                              "would lock you out of administrating the system."),
+		                                            oobs_user_get_full_name (user));
+
+		response = gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+		return FALSE;
+	}
+	/* If there are other admins, ask for confirmation only when dealing
+	 * with the current account. This does not catch the case where PolicyKit
+	 * authentication was done with another admin account, but this is not critical. */
+	else if (user == oobs_self_config_get_user (self_config)) {
+		dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
+		                                 GTK_DIALOG_MODAL,
+		                                 GTK_MESSAGE_WARNING,
+		                                 GTK_BUTTONS_NONE,
+		                                 _("You are about to revoke your own administration rights"));
+
+		gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
+		                                            _("%s will no longer be able to perform administrative tasks. "
+		                                              "This account won't be allowed to get administration rights back on its own."),
+		                                            oobs_user_get_full_name (user));
+		gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+		                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		                        _("Give up administration rights"), GTK_RESPONSE_OK, NULL);
+
+		response = gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+		return (response == GTK_RESPONSE_OK);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+check_profile (OobsUser *user, GstUserProfile *profile)
+{
+	OobsGroupsConfig *groups_config;
+	OobsGroup *admin_group;
+	char **l;
+	gboolean is_admin_profile;
+
+	groups_config = OOBS_GROUPS_CONFIG (GST_USERS_TOOL (tool)->groups_config);
+	admin_group = oobs_groups_config_get_from_name (groups_config, ADMIN_GROUP);
+
+	if (oobs_user_is_in_group (user, admin_group)) {
+		is_admin_profile = FALSE;
+
+		for (l = profile->groups; *l; l++)
+			  if (strcmp (ADMIN_GROUP, *l) == 0) {
+				  is_admin_profile = TRUE;
+				  break;
+			  }
+
+		  if (!is_admin_profile)
+			  return user_settings_check_revoke_admin_rights (user);
+	  }
+
+	return TRUE;
+}
+
+/*
  * Callback for user_new_name entry: on every change, fill the combo entry
  * with proposed logins. Also update validate button's sensitivity if name is empty.
  */
@@ -1224,15 +1339,20 @@ on_edit_user_profile (GtkButton *button, gpointer user_data)
 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (value))) {
 			profile = gst_user_profiles_get_from_name (GST_USERS_TOOL (tool)->profiles,
 			                                           (char *) key);
-			gst_user_profiles_apply (GST_USERS_TOOL (tool)->profiles,
-			                         profile, user, FALSE);
 			break;
 		}
 
-	if (response == GTK_RESPONSE_OK) {
-		if (gst_tool_commit (tool, GST_USERS_TOOL (tool)->users_config) == OOBS_RESULT_OK)
-			gst_tool_commit (tool, GST_USERS_TOOL (tool)->groups_config);
-	}
+	/* apply if conditions were met, else a message has been displayed in check_profile */
+	if (profile && check_profile (user, profile))
+	  {
+		  gst_user_profiles_apply (GST_USERS_TOOL (tool)->profiles,
+		                           profile, user, FALSE);
+
+		  if (response == GTK_RESPONSE_OK) {
+			  if (gst_tool_commit (tool, GST_USERS_TOOL (tool)->users_config) == OOBS_RESULT_OK)
+				  gst_tool_commit (tool, GST_USERS_TOOL (tool)->groups_config);
+		  }
+	  }
 
 	g_object_unref (user);
 }
diff --git a/src/users/user-settings.h b/src/users/user-settings.h
index 5328838..b162aff 100644
--- a/src/users/user-settings.h
+++ b/src/users/user-settings.h
@@ -30,6 +30,7 @@
 #include "user-profiles.h"
 
 #define NO_PASSWD_LOGIN_GROUP "nopasswdlogin"
+#define ADMIN_GROUP "admin"
 
 gboolean        user_delete                      (GtkTreeModel *model,
 						  GtkTreePath *path);
@@ -43,6 +44,8 @@ uid_t           user_settings_find_new_uid       (gint uid_min,
 gboolean        user_settings_is_user_in_group   (OobsUser  *user,
                                                   OobsGroup *group);
 
+gboolean        user_settings_check_revoke_admin_rights ();
+
 void            on_user_new                      (GtkButton *button, gpointer user_data);
 
 



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