Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Meego:Netbook:1.1
gnome-control-center-netbook
0009-Add-Security-settings-panel.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0009-Add-Security-settings-panel.patch of Package gnome-control-center-netbook
From b413e6a321237ab9289de89a4b5e164687fb3039 Mon Sep 17 00:00:00 2001 From: Thomas Wood <thomas.wood@intel.com> Date: Thu, 26 Aug 2010 15:39:36 +0100 Subject: [PATCH 09/13] Add Security settings panel --- capplets/Makefile.am | 5 + capplets/security/Makefile.am | 61 +++ capplets/security/cc-security-panel.c | 579 +++++++++++++++++++++++ capplets/security/cc-security-panel.h | 54 +++ capplets/security/run-passwd.c | 753 ++++++++++++++++++++++++++++++ capplets/security/run-passwd.h | 57 +++ capplets/security/security-module.c | 42 ++ capplets/security/security.desktop.in.in | 9 + capplets/security/security.ui | 214 +++++++++ configure.ac | 20 + po/POTFILES.in | 4 + po/POTFILES.skip | 1 + 12 files changed, 1799 insertions(+), 0 deletions(-) create mode 100644 capplets/security/Makefile.am create mode 100644 capplets/security/cc-security-panel.c create mode 100644 capplets/security/cc-security-panel.h create mode 100644 capplets/security/run-passwd.c create mode 100644 capplets/security/run-passwd.h create mode 100644 capplets/security/security-module.c create mode 100644 capplets/security/security.desktop.in.in create mode 100644 capplets/security/security.ui diff --git a/capplets/Makefile.am b/capplets/Makefile.am index 65d80c3..d991c4e 100644 --- a/capplets/Makefile.am +++ b/capplets/Makefile.am @@ -21,6 +21,7 @@ DIST_SUBDIRS = \ keyboard \ mouse \ network \ + security \ windows \ display \ date \ @@ -32,4 +33,8 @@ if BUILD_ABOUTME SUBDIRS += about-me endif +if BUILD_SECURITY +SUBDIRS += security +endif + -include $(top_srcdir)/git.mk diff --git a/capplets/security/Makefile.am b/capplets/security/Makefile.am new file mode 100644 index 0000000..bbe0cc4 --- /dev/null +++ b/capplets/security/Makefile.am @@ -0,0 +1,61 @@ +cappletname = security + +NULL = + +libsecurity_la_SOURCES = \ + security-module.c \ + cc-security-panel.c \ + cc-security-panel.h \ + run-passwd.h \ + run-passwd.c \ + $(NULL) + +ui_files = \ + security.ui \ + $(NULL) + + +libsecurity_la_CFLAGS = \ + $(EXTENSION_CFLAGS) \ + $(EXTENSION_COMMON_CFLAGS) + +libsecurity_la_LDFLAGS = \ + $(EXTENSION_LIBTOOL_FLAGS) + +libsecurity_la_LIBADD = \ + $(EXTENSION_LIBS) \ + $(EXTENSION_COMMON_LIBS) \ + $(MX_GTK_LIBS) \ + $(NULL) + +@INTLTOOL_DESKTOP_RULE@ + +uidir = $(pkgdatadir)/ui +ui_DATA = $(ui_files) + +desktopdir = $(datadir)/applications +desktop_in_files = security.desktop.in +desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) + +INCLUDES = \ + $(GNOMECC_CAPPLETS_CFLAGS) \ + $(MX_GTK_CFLAGS) \ + -I$(top_srcdir)/libgnome-control-center-extension \ + -DUIDIR=\""$(uidir)"\" \ + -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \ + $(NULL) + +ccmodulesdir = $(EXTENSIONSDIR) +ccmodules_LTLIBRARIES = libsecurity.la + +CLEANFILES = \ + $(GNOMECC_CAPPLETS_CLEANFILES) \ + $(desktop_in_files) \ + $(desktop_DATA) \ + $(NULL) + +EXTRA_DIST = \ + $(ui_DATA) \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/capplets/security/cc-security-panel.c b/capplets/security/cc-security-panel.c new file mode 100644 index 0000000..8c4e424 --- /dev/null +++ b/capplets/security/cc-security-panel.c @@ -0,0 +1,579 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ + +/* cc-security-panel.c + * Copyright (C) 2010 Intel Corporation + * + * Written by: Jussi Kukkonen <jku@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* TODO: + * * there is currently no indication that the current passwd is being + * checked when unfocusing the entry. A busy-interactive cursor might + * work + * + * NOTES: + * * currently uses PasswdHandler from accounts-dialog/users-admin/ + * gnome-about-me. This is quite horrible and seems to break in some + * cases. Using something like accountsservice might be a better long + * term solution. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <gconf/gconf-client.h> +#include <gtk/gtk.h> +#include <mx-gtk/mx-gtk.h> + +#include "capplet-util.h" +#include "run-passwd.h" +#include "cc-security-panel.h" + +#define SCREEN_LOCK_DIR "/apps/gnome-screensaver" +#define SCREEN_LOCK_KEY SCREEN_LOCK_DIR"/lock_enabled" + +#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_SECURITY_PANEL, CcSecurityPanelPrivate)) + +#define GET_WIDGET(b,s) GTK_WIDGET (gtk_builder_get_object (b, s)) + +struct CcSecurityPanelPrivate { + GtkWidget *password_toggle; + guint toggle_id; + + GtkWidget *current_entry; + GtkWidget *current_info_bar; + gboolean grab_after_validation; + gboolean current_is_valid; + + GtkWidget *new_entry; + GtkWidget *verify_entry; + GtkWidget *verify_info_bar; + GtkWidget *verify_info_label; + + GtkWidget *save_button; + + PasswdHandler *passwd_handler; + GConfClient *gconf; +}; + +G_DEFINE_DYNAMIC_TYPE (CcSecurityPanel, cc_security_panel, CC_TYPE_PANEL) + +static void +cc_security_panel_update_sensitivity (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + gboolean ok = FALSE; + + if (priv->current_is_valid) { + char const *new, *verify; + + new = gtk_entry_get_text (GTK_ENTRY (priv->new_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (priv->verify_entry)); + if (strlen (new) != 0 && + strlen (verify) != 0 && + strcmp (new, verify) == 0) { + ok = TRUE; + } + } + gtk_widget_set_sensitive (priv->save_button, ok); +} + +static void +password_authenticated_cb (PasswdHandler *passwd_handler, + GError *error, + CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + if (error) { + priv->current_is_valid = FALSE; + gtk_widget_show (priv->current_info_bar); + } else { + priv->current_is_valid = TRUE; + gtk_widget_hide (priv->current_info_bar); + if (priv->grab_after_validation && + GTK_WIDGET_HAS_FOCUS (priv->current_entry)) { + gtk_widget_grab_focus (priv->new_entry); + } + } + priv->grab_after_validation = FALSE; + + cc_security_panel_update_sensitivity (panel); +} + +static void +cc_security_panel_validate_current_password (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (priv->current_entry)); + if (strlen (text) > 0) { + passwd_authenticate (priv->passwd_handler, text, + (PasswdCallback)password_authenticated_cb, + panel); + } +} + +static gboolean +cc_security_panel_verify_new_password (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + char const *new, *verify; + + new = gtk_entry_get_text (GTK_ENTRY (priv->new_entry)); + verify = gtk_entry_get_text (GTK_ENTRY (priv->verify_entry)); + if (strlen (new) == 0 || strlen (verify) == 0) { + gtk_widget_hide (priv->verify_info_bar); + return FALSE; + } else if (strcmp (new, verify) == 0) { + gtk_widget_hide (priv->verify_info_bar); + return TRUE; + } else { + gtk_label_set_text (GTK_LABEL (priv->verify_info_label), + _("Sorry, the passwords do not match")); + gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->verify_info_bar), + GTK_MESSAGE_WARNING); + gtk_widget_show (priv->verify_info_bar); + return FALSE; + } +} + +static void +password_changed_cb (PasswdHandler *passwd_handler, + GError *error, + CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + gtk_widget_set_sensitive (priv->current_entry, TRUE); + gtk_widget_set_sensitive (priv->new_entry, TRUE); + gtk_widget_set_sensitive (priv->verify_entry, TRUE); + + if (!error) { + gtk_entry_set_text (GTK_ENTRY (priv->current_entry), ""); + gtk_entry_set_text (GTK_ENTRY (priv->new_entry), ""); + gtk_entry_set_text (GTK_ENTRY (priv->verify_entry), ""); + + gtk_label_set_text (GTK_LABEL (priv->verify_info_label), + _("The new password is now saved")); + gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->verify_info_bar), + GTK_MESSAGE_INFO); + gtk_widget_show (priv->verify_info_bar); + } else { + switch (error->code) { + case PASSWD_ERROR_REJECTED: + gtk_entry_set_text (GTK_ENTRY (priv->new_entry), ""); + gtk_entry_set_text (GTK_ENTRY (priv->verify_entry), ""); + gtk_widget_grab_focus (priv->new_entry); + + gtk_label_set_text (GTK_LABEL (priv->verify_info_label), + error->message); + gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->verify_info_bar), + GTK_MESSAGE_WARNING); + gtk_widget_show (priv->verify_info_bar); + break; + + case PASSWD_ERROR_AUTH_FAILED: + gtk_entry_set_text (GTK_ENTRY (priv->current_entry), ""); + gtk_widget_grab_focus (priv->current_entry); + + gtk_widget_show (priv->current_info_bar); + break; + + default: + g_warning ("Password change failed: %s", error->message); + + gtk_widget_set_sensitive (priv->save_button, TRUE); + + gtk_label_set_text (GTK_LABEL (priv->verify_info_label), + _("Sorry, the password could not be changed")); + gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->verify_info_bar), + GTK_MESSAGE_WARNING); + gtk_widget_show (priv->verify_info_bar); + } + } + + /* PasswdHandler seems to break in interesting ways after this. + * Fixing it is not trivial, working around... */ + passwd_destroy (priv->passwd_handler); + priv->passwd_handler = passwd_init (); + cc_security_panel_validate_current_password (panel); +} + +static void +cc_security_panel_change_password (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + const char *new; + + gtk_widget_set_sensitive (priv->current_entry, FALSE); + gtk_widget_set_sensitive (priv->new_entry, FALSE); + gtk_widget_set_sensitive (priv->verify_entry, FALSE); + gtk_widget_set_sensitive (priv->save_button, FALSE); + + new = gtk_entry_get_text (GTK_ENTRY (priv->new_entry)); + passwd_change_password (priv->passwd_handler, new, + (PasswdCallback)password_changed_cb, panel); +} + +static void +cc_security_panel_update_password_toggle (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + GError *error = NULL; + gboolean lock = FALSE; + + lock = gconf_client_get_bool (priv->gconf, SCREEN_LOCK_KEY, &error); + if (error) { + g_warning ("Could not read key %s: %s", + SCREEN_LOCK_KEY, error->message); + g_error_free (error); + } + + g_signal_handler_block (priv->password_toggle, priv->toggle_id); + g_object_set (priv->password_toggle, + "active", lock, + NULL); + g_signal_handler_unblock (priv->password_toggle, priv->toggle_id); + +} + +static void +current_entry_activate (GtkEntry *entry, CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + priv->grab_after_validation = TRUE; + cc_security_panel_validate_current_password (panel); +} + +static gboolean +current_entry_focus_out (GtkEntry *entry, + GdkEventFocus *event, + CcSecurityPanel *panel) +{ + cc_security_panel_validate_current_password (panel); + return FALSE; +} + +static void +current_entry_notify_text (GtkEntry *entry, + GParamSpec *pspec, + CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + gtk_widget_hide (priv->current_info_bar); + priv->current_is_valid = FALSE; + + cc_security_panel_update_sensitivity (panel); +} + +static void +new_entry_activate (GtkEntry *entry, CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + cc_security_panel_verify_new_password (panel); + gtk_widget_grab_focus (priv->verify_entry); +} + +static void +verify_entry_activate (GtkEntry *entry, CcSecurityPanel *panel) +{ + if (cc_security_panel_verify_new_password (panel)) { + cc_security_panel_change_password (panel); + } +} + +static gboolean +new_or_verify_entry_focus_out (GtkEntry *entry, + GdkEventFocus *event, + CcSecurityPanel *panel) +{ + if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0) { + cc_security_panel_verify_new_password (panel); + } + return FALSE; +} + +static void +new_or_verify_entry_notify_text (GtkEntry *entry, + GParamSpec *pspec, + CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + gtk_widget_hide (priv->verify_info_bar); + cc_security_panel_update_sensitivity (panel); +} + +static void +password_toggle_notify_active (GtkWidget *widget, + GParamSpec *pspec, + CcSecurityPanel *panel) +{ + char *lockfile; + gboolean lock; + + g_object_get (widget, "active", &lock, NULL); + gconf_client_set_bool (panel->priv->gconf, + SCREEN_LOCK_KEY, lock, + NULL); + + /* touch or remove a file to set lock-on-boot status */ + lockfile = g_strdup_printf ("%s/lock-screen", g_get_user_config_dir ()); + if (lock) { + g_file_set_contents (lockfile, "", -1, NULL); + } else { + g_remove (lockfile); + } + g_free (lockfile); +} + +static void +save_button_clicked (GtkButton *button, CcSecurityPanel *panel) +{ + cc_security_panel_change_password (panel); +} + +static void +gconf_notify (GConfClient *gconf, + guint id, + GConfEntry *entry, + CcSecurityPanel *panel) +{ + cc_security_panel_update_password_toggle (panel); +} + +static void +panel_active_changed (CcSecurityPanel *panel, gboolean active) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + + if (active) { + gtk_entry_set_text (GTK_ENTRY (priv->current_entry), ""); + gtk_entry_set_text (GTK_ENTRY (priv->new_entry), ""); + gtk_entry_set_text (GTK_ENTRY (priv->verify_entry), ""); + + gtk_widget_hide (priv->verify_info_bar); + gtk_widget_hide (priv->current_info_bar); + } +} + +static void +cc_security_panel_setup_panel (CcSecurityPanel *panel) +{ + CcSecurityPanelPrivate *priv = GET_PRIVATE (panel); + GtkWidget *main_window, *box, *toggle_box, *c_area, *label; + GtkBuilder *builder; + GError *error = NULL; + + builder = gtk_builder_new (); + gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); + + if (gtk_builder_add_from_file (builder, + UIDIR"/security.ui", + &error) == 0) { + g_error ("Could not parse UI file: %s", error->message); + g_error_free (error); + g_object_unref (builder); + return; + } + + priv->gconf = gconf_client_get_default (); + gconf_client_add_dir (priv->gconf, + SCREEN_LOCK_DIR, + GCONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + gconf_client_notify_add (priv->gconf, + SCREEN_LOCK_KEY, + (GConfClientNotifyFunc) gconf_notify, + panel, NULL, NULL); + + main_window = GET_WIDGET (builder, "main_window"); + gtk_widget_reparent (gtk_bin_get_child (GTK_BIN (main_window)), + GTK_WIDGET (panel)); + + toggle_box = GET_WIDGET (builder, "password_toggle_box"); + priv->password_toggle = mx_gtk_light_switch_new (); + gtk_box_pack_start (GTK_BOX (toggle_box), priv->password_toggle, + FALSE, FALSE, 0); + cc_security_panel_update_password_toggle (panel); + priv->toggle_id = g_signal_connect (priv->password_toggle, + "notify::active", + G_CALLBACK (password_toggle_notify_active), + panel); + + priv->current_entry = GET_WIDGET (builder, "current_entry"); + g_signal_connect (priv->current_entry, "activate", + G_CALLBACK (current_entry_activate), panel); + g_signal_connect (priv->current_entry, "focus-out-event", + G_CALLBACK (current_entry_focus_out), panel); + g_signal_connect (priv->current_entry, "notify::text", + G_CALLBACK (current_entry_notify_text), panel); + + /* no infobar in glade yet... */ + box = GET_WIDGET (builder, "current_warning_box"); + priv->current_info_bar = gtk_info_bar_new (); + gtk_widget_set_no_show_all (priv->current_info_bar, TRUE); + gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->current_info_bar), + GTK_MESSAGE_WARNING); + gtk_box_pack_start_defaults (GTK_BOX (box), priv->current_info_bar); + label = gtk_label_new (_("Sorry, that password is incorrect")); + gtk_widget_show (label); + c_area = gtk_info_bar_get_content_area ( + GTK_INFO_BAR (priv->current_info_bar)); + gtk_container_add (GTK_CONTAINER (c_area), label); + + box = GET_WIDGET (builder, "verify_warning_box"); + priv->verify_info_bar = gtk_info_bar_new (); + gtk_widget_set_no_show_all (priv->verify_info_bar, TRUE); + gtk_box_pack_start_defaults (GTK_BOX (box), priv->verify_info_bar); + priv->verify_info_label = gtk_label_new (""); + gtk_widget_show (priv->verify_info_label); + c_area = gtk_info_bar_get_content_area ( + GTK_INFO_BAR (priv->verify_info_bar)); + gtk_container_add (GTK_CONTAINER (c_area), priv->verify_info_label); + + priv->new_entry = GET_WIDGET (builder, "new_entry"); + g_signal_connect (priv->new_entry, "activate", + G_CALLBACK (new_entry_activate), panel); + g_signal_connect (priv->new_entry, "focus-out-event", + G_CALLBACK (new_or_verify_entry_focus_out), panel); + g_signal_connect (priv->new_entry, "notify::text", + G_CALLBACK (new_or_verify_entry_notify_text), panel); + + priv->verify_entry = GET_WIDGET (builder, "verify_entry"); + g_signal_connect (priv->verify_entry, "activate", + G_CALLBACK (verify_entry_activate), panel); + g_signal_connect (priv->verify_entry, "focus-out-event", + G_CALLBACK (new_or_verify_entry_focus_out), panel); + g_signal_connect (priv->verify_entry, "notify::text", + G_CALLBACK (new_or_verify_entry_notify_text), panel); + + priv->save_button = GET_WIDGET (builder, "save_button"); + g_signal_connect (priv->save_button, "clicked", + G_CALLBACK (save_button_clicked), panel); + + g_object_unref (builder); + + priv->passwd_handler = passwd_init (); + + g_signal_connect (panel, "active-changed", + G_CALLBACK (panel_active_changed), NULL); +} + +static GObject * +cc_security_panel_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + CcSecurityPanel *panel; + + panel = CC_SECURITY_PANEL (G_OBJECT_CLASS (cc_security_panel_parent_class)->constructor + (type, n_construct_properties, construct_properties)); + + g_object_set (panel, + "display-name", _("Security"), + "id", "security.desktop", + NULL); + + cc_security_panel_setup_panel (panel); + + return G_OBJECT (panel); +} + + +static void +cc_security_panel_class_finalize (CcSecurityPanelClass *klass) +{ +} + +static void +cc_security_panel_init (CcSecurityPanel *panel) +{ + panel->priv = GET_PRIVATE (panel); +} + +static void +cc_security_panel_dispose (GObject *object) +{ + CcSecurityPanel *panel; + CcSecurityPanelPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (CC_IS_SECURITY_PANEL (object)); + + panel = CC_SECURITY_PANEL (object); + priv = GET_PRIVATE (panel); + + if (priv->passwd_handler) { + passwd_destroy (priv->passwd_handler); + priv->passwd_handler = NULL; + } + + if (priv->gconf) { + g_object_unref (priv->gconf); + priv->gconf = NULL; + } +} + +static void +cc_security_panel_finalize (GObject *object) +{ + CcSecurityPanel *panel; + + g_return_if_fail (object != NULL); + g_return_if_fail (CC_IS_SECURITY_PANEL (object)); + + panel = CC_SECURITY_PANEL (object); + + g_return_if_fail (panel->priv != NULL); + + G_OBJECT_CLASS (cc_security_panel_parent_class)->finalize (object); +} + +static void +cc_security_panel_class_init (CcSecurityPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructor = cc_security_panel_constructor; + object_class->finalize = cc_security_panel_finalize; + object_class->dispose = cc_security_panel_dispose; + + g_type_class_add_private (klass, sizeof (CcSecurityPanelPrivate)); +} + +void +cc_security_panel_register (GIOModule *module) +{ + cc_security_panel_register_type (G_TYPE_MODULE (module)); + g_io_extension_point_implement (CC_PANEL_EXTENSION_POINT_NAME, + CC_TYPE_SECURITY_PANEL, + "security", + 10); +} diff --git a/capplets/security/cc-security-panel.h b/capplets/security/cc-security-panel.h new file mode 100644 index 0000000..bc76d27 --- /dev/null +++ b/capplets/security/cc-security-panel.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __CC_SECURITY_PANEL_H +#define __CC_SECURITY_PANEL_H + +#include <gtk/gtk.h> +#include "cc-panel.h" + +G_BEGIN_DECLS + +#define CC_TYPE_SECURITY_PANEL (cc_security_panel_get_type ()) +#define CC_SECURITY_PANEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CC_TYPE_SECURITY_PANEL, CcSecurityPanel)) +#define CC_SECURITY_PANEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CC_TYPE_SECURITY_PANEL, CcSecurityPanelClass)) +#define CC_IS_SECURITY_PANEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CC_TYPE_SECURITY_PANEL)) +#define CC_IS_SECURITY_PANEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CC_TYPE_SECURITY_PANEL)) +#define CC_SECURITY_PANEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CC_TYPE_SECURITY_PANEL, CcSecurityPanelClass)) + +typedef struct CcSecurityPanelPrivate CcSecurityPanelPrivate; + +typedef struct +{ + CcPanel parent; + CcSecurityPanelPrivate *priv; +} CcSecurityPanel; + +typedef struct +{ + CcPanelClass parent_class; +} CcSecurityPanelClass; + +GType cc_security_panel_get_type (void); +void cc_security_panel_register (GIOModule *module); + +G_END_DECLS + +#endif /* __CC_SECURITY_PANEL_H */ diff --git a/capplets/security/run-passwd.c b/capplets/security/run-passwd.c new file mode 100644 index 0000000..c43a145 --- /dev/null +++ b/capplets/security/run-passwd.c @@ -0,0 +1,753 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* run-passwd.c + * + * Copyright (C) 2002 Diego Gonzalez + * Copyright (C) 2006 Johannes H. Jensen + * Copyright (C) 2010 Milan Bouchet-Valat + * + * Written by: Diego Gonzalez <diego@pemas.net> + * Modified by: Johannes H. Jensen <joh@deworks.net>, + * Milan Bouchet-Valat <nalimilan@club.fr>. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * This code is taken from accountsdialog, whose developers apparently + * took it from users-admin. users-admin version seems to originate from + * gnome-about-me-password.c. Ah, the circle of life... + */ + +#include <config.h> +#include <glib/gi18n.h> + +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/wait.h> + +#if __sun +#include <sys/types.h> +#include <signal.h> +#endif + +#include "run-passwd.h" + +/* Passwd states */ +typedef enum { + PASSWD_STATE_NONE, /* Passwd is not asking for anything */ + PASSWD_STATE_AUTH, /* Passwd is asking for our current password */ + PASSWD_STATE_NEW, /* Passwd is asking for our new password */ + PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */ + PASSWD_STATE_DONE, /* Passwd succeeded but has not yet exited */ + PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */ +} PasswdState; + +struct PasswdHandler { + const char *current_password; + const char *new_password; + const char *retyped_password; + + /* Communication with the passwd program */ + GPid backend_pid; + + GIOChannel *backend_stdin; + GIOChannel *backend_stdout; + + GQueue *backend_stdin_queue; /* Write queue to backend_stdin */ + + /* GMainLoop IDs */ + guint backend_child_watch_id; /* g_child_watch_add (PID) */ + guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */ + + /* State of the passwd program */ + PasswdState backend_state; + gboolean changing_password; + + PasswdCallback auth_cb; + gpointer auth_cb_data; + + PasswdCallback chpasswd_cb; + gpointer chpasswd_cb_data; +}; + +/* Buffer size for backend output */ +#define BUFSIZE 128 + + +static GQuark +passwd_error_quark (void) +{ + static GQuark q = 0; + + if (q == 0) { + q = g_quark_from_static_string("passwd_error"); + } + + return q; +} + +/* Error handling */ +#define PASSWD_ERROR (passwd_error_quark ()) + + +static void +stop_passwd (PasswdHandler *passwd_handler); + +static void +free_passwd_resources (PasswdHandler *passwd_handler); + +static gboolean +io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler); + + +/* + * Spawning and closing of backend {{ + */ + +/* Child watcher */ +static void +child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler) +{ + if (WIFEXITED (status)) { + if (WEXITSTATUS (status) >= 255) { + g_warning ("Child exited unexpectedly"); + } + if (WEXITSTATUS (status) == 0) { + if (passwd_handler->backend_state == PASSWD_STATE_RETYPE) { + passwd_handler->backend_state = PASSWD_STATE_DONE; + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + NULL, + passwd_handler->auth_cb_data); + } + } + } + + free_passwd_resources (passwd_handler); +} + +static void +ignore_sigpipe (gpointer data) +{ + signal (SIGPIPE, SIG_IGN); +} + +/* Spawn passwd backend + * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ +static gboolean +spawn_passwd (PasswdHandler *passwd_handler, GError **error) +{ + gchar *argv[2]; + gchar *envp[1]; + gint my_stdin, my_stdout, my_stderr; + + argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ + argv[1] = NULL; + + envp[0] = NULL; /* If we pass an empty array as the environment, + * will the childs environment be empty, and the + * locales set to the C default? From the manual: + * "If envp is NULL, the child inherits its + * parent'senvironment." + * If I'm wrong here, we somehow have to set + * the locales here. + */ + + if (!g_spawn_async_with_pipes (NULL, /* Working directory */ + argv, /* Argument vector */ + envp, /* Environment */ + G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ + ignore_sigpipe, /* Child setup */ + NULL, /* Data to child setup */ + &passwd_handler->backend_pid, /* PID */ + &my_stdin, /* Stdin */ + &my_stdout, /* Stdout */ + &my_stderr, /* Stderr */ + error)) { /* GError */ + + /* An error occured */ + free_passwd_resources (passwd_handler); + + return FALSE; + } + + /* 2>&1 */ + if (dup2 (my_stderr, my_stdout) == -1) { + /* Failed! */ + g_set_error_literal (error, + PASSWD_ERROR, + PASSWD_ERROR_BACKEND, + strerror (errno)); + + /* Clean up */ + stop_passwd (passwd_handler); + + return FALSE; + } + + /* Open IO Channels */ + passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin); + passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout); + + /* Set raw encoding */ + /* Set nonblocking mode */ + if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || + g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { + + /* Clean up */ + stop_passwd (passwd_handler); + return FALSE; + } + + /* Turn off buffering */ + g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE); + g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE); + + /* Add IO Channel watcher */ + passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout, + G_IO_IN | G_IO_PRI, + (GIOFunc) io_watch_stdout, passwd_handler); + + /* Add child watcher */ + passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler); + + /* Success! */ + + return TRUE; +} + +/* Stop passwd backend */ +static void +stop_passwd (PasswdHandler *passwd_handler) +{ + /* This is the standard way of returning from the dialog with passwd. + * If we return this way we can safely kill passwd as it has completed + * its task. + */ + + if (passwd_handler->backend_pid != -1) { + kill (passwd_handler->backend_pid, 9); + } + + /* We must run free_passwd_resources here and not let our child + * watcher do it, since it will access invalid memory after the + * dialog has been closed and cleaned up. + * + * If we had more than a single thread we'd need to remove + * the child watch before trying to kill the child. + */ + free_passwd_resources (passwd_handler); +} + +/* Clean up passwd resources */ +static void +free_passwd_resources (PasswdHandler *passwd_handler) +{ + GError *error = NULL; + + /* Remove the child watcher */ + if (passwd_handler->backend_child_watch_id != 0) { + + g_source_remove (passwd_handler->backend_child_watch_id); + + passwd_handler->backend_child_watch_id = 0; + } + + + /* Close IO channels (internal file descriptors are automatically closed) */ + if (passwd_handler->backend_stdin != NULL) { + + if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message); + g_error_free (error); + error = NULL; + } + + g_io_channel_unref (passwd_handler->backend_stdin); + passwd_handler->backend_stdin = NULL; + } + + if (passwd_handler->backend_stdout != NULL) { + + if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message); + g_error_free (error); + error = NULL; + } + + g_io_channel_unref (passwd_handler->backend_stdout); + + passwd_handler->backend_stdout = NULL; + } + + /* Remove IO watcher */ + if (passwd_handler->backend_stdout_watch_id != 0) { + + g_source_remove (passwd_handler->backend_stdout_watch_id); + + passwd_handler->backend_stdout_watch_id = 0; + } + + /* Close PID */ + if (passwd_handler->backend_pid != -1) { + + g_spawn_close_pid (passwd_handler->backend_pid); + + passwd_handler->backend_pid = -1; + } + + /* Clear backend state */ + passwd_handler->backend_state = PASSWD_STATE_NONE; +} + +/* + * }} Spawning and closing of backend + */ + +/* + * Backend communication code {{ + */ + +/* Write the first element of queue through channel */ +static void +io_queue_pop (GQueue *queue, GIOChannel *channel) +{ + gchar *buf; + gsize bytes_written; + GError *error = NULL; + + buf = g_queue_pop_head (queue); + if (buf != NULL) { + + if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) { + g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message); + g_error_free (error); + } + + /* Ensure passwords are cleared from memory */ + memset (buf, 0, strlen (buf)); + g_free (buf); + } +} + +/* Goes through the argument list, checking if one of them occurs in str + * Returns: TRUE as soon as an element is found to match, FALSE otherwise */ +static gboolean +is_string_complete (gchar *str, ...) +{ + va_list ap; + gchar *arg; + + if (strlen (str) == 0) { + return FALSE; + } + + va_start (ap, str); + + while ((arg = va_arg (ap, char *)) != NULL) { + if (strstr (str, arg) != NULL) { + va_end (ap); + return TRUE; + } + } + + va_end (ap); + + return FALSE; +} + +/* + * IO watcher for stdout, called whenever there is data to read from the backend. + * This is where most of the actual IO handling happens. + */ +static gboolean +io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler) +{ + static GString *str = NULL; /* Persistent buffer */ + + gchar buf[BUFSIZE]; /* Temporary buffer */ + gsize bytes_read; + GError *gio_error = NULL; /* Error returned by functions */ + GError *error = NULL; /* Error sent to callbacks */ + + gboolean reinit = FALSE; + + /* Initialize buffer */ + if (str == NULL) { + str = g_string_new (""); + } + + if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error) + != G_IO_STATUS_NORMAL) { + g_warning ("IO Channel read error: %s", gio_error->message); + g_error_free (gio_error); + + return TRUE; + } + + str = g_string_append_len (str, buf, bytes_read); + /* In which state is the backend? */ + switch (passwd_handler->backend_state) { + case PASSWD_STATE_AUTH: + /* Passwd is asking for our current password */ + + if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) { + + if (strstr (str->str, "assword: ") != NULL) { + /* Authentication successful */ + + passwd_handler->backend_state = PASSWD_STATE_NEW; + + /* Trigger callback to update authentication status */ + if (passwd_handler->auth_cb) + passwd_handler->auth_cb (passwd_handler, + NULL, + passwd_handler->auth_cb_data); + + } else { + /* Authentication failed */ + + error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, + _("Authentication failed")); + + passwd_handler->changing_password = FALSE; + + /* This error can happen both while authenticating or while changing password: + * if chpasswd_cb is set, this means we're already changing password */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + error, + passwd_handler->auth_cb_data); + else if (passwd_handler->auth_cb) + passwd_handler->auth_cb (passwd_handler, + error, + passwd_handler->auth_cb_data); + + g_error_free (error); + } + + reinit = TRUE; + } + break; + case PASSWD_STATE_NEW: + /* Passwd is asking for our new password */ + + if (is_string_complete (str->str, "assword: ", NULL)) { + /* Advance to next state */ + passwd_handler->backend_state = PASSWD_STATE_RETYPE; + + /* Pop retyped password from queue and into IO channel */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + + reinit = TRUE; + } + break; + case PASSWD_STATE_RETYPE: + /* Passwd is asking for our retyped new password */ + + if (is_string_complete (str->str, + "successfully", + "short", + "longer", + "palindrome", + "dictionary", + "simple", + "similar", + "wrapped", + "recovered", + "unchanged", + "match", + "1 numeric or special", + "failure", + "DIFFERENT", + "BAD PASSWORD", + NULL)) { + + if (strstr (str->str, "successfully") != NULL) { + /* Hooray! */ + + passwd_handler->backend_state = PASSWD_STATE_DONE; + /* Trigger callback to update status */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + NULL, + passwd_handler->chpasswd_cb_data); + } + else { + /* Ohnoes! */ + + if (strstr (str->str, "recovered") != NULL) { + /* What does this indicate? + * "Authentication information cannot be recovered?" from libpam? */ + error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, + str->str); + } else if (strstr (str->str, "short") != NULL || + strstr (str->str, "longer") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password is too short")); + } else if (strstr (str->str, "palindrome") != NULL || + strstr (str->str, "simple") != NULL || + strstr (str->str, "dictionary") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password is too simple")); + } else if (strstr (str->str, "similar") != NULL || + strstr (str->str, "wrapped") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The old and new passwords are too similar")); + } else if (strstr (str->str, "1 numeric or special") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password must contain numeric or special characters")); + } else if (strstr (str->str, "unchanged") != NULL || + strstr (str->str, "match") != NULL) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The old and new passwords are the same")); + } else if (strstr (str->str, "failure") != NULL) { + /* Authentication failure */ + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED, + _("Your password has been changed since you initially authenticated!")); + } + else if (strstr (str->str, "DIFFERENT")) { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED, + _("The new password does not contain enough different characters")); + } + else { + error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN, + _("Unknown error")); + } + + /* At this point, passwd might have exited, in which case + * child_watch_cb should clean up for us and remove this watcher. + * On some error conditions though, passwd just re-prompts us + * for our new password. */ + passwd_handler->backend_state = PASSWD_STATE_ERR; + + passwd_handler->changing_password = FALSE; + + /* Trigger callback to update status */ + if (passwd_handler->chpasswd_cb) + passwd_handler->chpasswd_cb (passwd_handler, + error, + passwd_handler->chpasswd_cb_data); + + g_error_free (error); + + } + + reinit = TRUE; + + /* child_watch_cb should clean up for us now */ + } + break; + case PASSWD_STATE_NONE: + /* Passwd is not asking for anything yet */ + if (is_string_complete (str->str, "assword: ", NULL)) { + + /* If the user does not have a password set, + * passwd will immediately ask for the new password, + * so skip the AUTH phase */ + if (is_string_complete (str->str, "new", "New", NULL)) { + gchar *pw; + + passwd_handler->backend_state = PASSWD_STATE_NEW; + + /* since passwd didn't ask for our old password + * in this case, simply remove it from the queue */ + pw = g_queue_pop_head (passwd_handler->backend_stdin_queue); + g_free (pw); + } else { + + passwd_handler->backend_state = PASSWD_STATE_AUTH; + + /* Pop the IO queue, i.e. send current password */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + } + + reinit = TRUE; + } + break; + default: + /* Passwd has returned an error */ + reinit = TRUE; + break; + } + + if (reinit) { + g_string_free (str, TRUE); + str = NULL; + } + + /* Continue calling us */ + return TRUE; +} + +/* + * }} Backend communication code + */ + +/* Adds the current password to the IO queue */ +static void +authenticate (PasswdHandler *passwd_handler) +{ + gchar *s; + + s = g_strdup_printf ("%s\n", passwd_handler->current_password); + + g_queue_push_tail (passwd_handler->backend_stdin_queue, s); +} + +/* Adds the new password twice to the IO queue */ +static void +update_password (PasswdHandler *passwd_handler) +{ + gchar *s; + + s = g_strdup_printf ("%s\n", passwd_handler->new_password); + + g_queue_push_tail (passwd_handler->backend_stdin_queue, s); + /* We need to allocate new space because io_queue_pop() g_free()s + * every element of the queue after it's done */ + g_queue_push_tail (passwd_handler->backend_stdin_queue, g_strdup (s)); +} + + +PasswdHandler * +passwd_init (void) +{ + PasswdHandler *passwd_handler; + + passwd_handler = g_new0 (PasswdHandler, 1); + + /* Initialize backend_pid. -1 means the backend is not running */ + passwd_handler->backend_pid = -1; + + /* Initialize IO Channels */ + passwd_handler->backend_stdin = NULL; + passwd_handler->backend_stdout = NULL; + + /* Initialize write queue */ + passwd_handler->backend_stdin_queue = g_queue_new (); + + /* Initialize watchers */ + passwd_handler->backend_child_watch_id = 0; + passwd_handler->backend_stdout_watch_id = 0; + + /* Initialize backend state */ + passwd_handler->backend_state = PASSWD_STATE_NONE; + passwd_handler->changing_password = FALSE; + + return passwd_handler; +} + +void +passwd_destroy (PasswdHandler *passwd_handler) +{ + g_queue_free (passwd_handler->backend_stdin_queue); + stop_passwd (passwd_handler); + g_free (passwd_handler); +} + +void +passwd_authenticate (PasswdHandler *passwd_handler, + const char *current_password, + PasswdCallback cb, + const gpointer user_data) +{ + GError *error = NULL; + + /* Don't stop if we've already started chaging password */ + if (passwd_handler->changing_password) + return; + + /* Clear data from possible previous attempts to change password */ + passwd_handler->new_password = NULL; + passwd_handler->chpasswd_cb = NULL; + passwd_handler->chpasswd_cb_data = NULL; + g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL); + g_queue_clear (passwd_handler->backend_stdin_queue); + + passwd_handler->current_password = current_password; + passwd_handler->auth_cb = cb; + passwd_handler->auth_cb_data = user_data; + + /* Spawn backend */ + stop_passwd (passwd_handler); + + if (!spawn_passwd (passwd_handler, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return; + } + + authenticate (passwd_handler); + + /* Our IO watcher should now handle the rest */ +} + +gboolean +passwd_change_password (PasswdHandler *passwd_handler, + const char *new_password, + PasswdCallback cb, + const gpointer user_data) +{ + GError *error = NULL; + + passwd_handler->changing_password = TRUE; + + passwd_handler->new_password = new_password; + passwd_handler->chpasswd_cb = cb; + passwd_handler->chpasswd_cb_data = user_data; + + /* Stop passwd if an error occured and it is still running */ + if (passwd_handler->backend_state == PASSWD_STATE_ERR) { + + /* Stop passwd, free resources */ + stop_passwd (passwd_handler); + } + + /* Check that the backend is still running, or that an error + * has occured but it has not yet exited */ + if (passwd_handler->backend_pid == -1) { + /* If it is not, re-run authentication */ + + /* Spawn backend */ + stop_passwd (passwd_handler); + + if (!spawn_passwd (passwd_handler, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return FALSE; + } + + /* Add current and new passwords to queue */ + authenticate (passwd_handler); + update_password (passwd_handler); + } else { + /* Only add new passwords to queue */ + update_password (passwd_handler); + } + + /* Pop new password through the backend */ + io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); + + /* Our IO watcher should now handle the rest */ + + return TRUE; +} diff --git a/capplets/security/run-passwd.h b/capplets/security/run-passwd.h new file mode 100644 index 0000000..1c567a7 --- /dev/null +++ b/capplets/security/run-passwd.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* run-passwd.h + * + * Copyright (C) 2010 Milan Bouchet-Valat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Milan Bouchet-Valat <nalimilan@club.fr> + */ + +#ifndef _RUN_PASSWD_H +#define _RUN_PASSWD_H + +struct PasswdHandler; + +typedef struct PasswdHandler PasswdHandler; + +typedef void (*PasswdCallback) (PasswdHandler *passwd_handler, GError *error, const gpointer user_data); + +/* Error codes */ +typedef enum { + PASSWD_ERROR_REJECTED, /* New password is not secure enough */ + PASSWD_ERROR_AUTH_FAILED, /* Wrong old password, or PAM failure */ + PASSWD_ERROR_REAUTH_FAILED, /* Password has changed since first authentication */ + PASSWD_ERROR_BACKEND, /* Backend error */ + PASSWD_ERROR_UNKNOWN /* General error */ +} PasswdError; + + +PasswdHandler *passwd_init (void); + +void passwd_destroy (PasswdHandler *passwd_handler); + +void passwd_authenticate (PasswdHandler *passwd_handler, + const char *current_password, + PasswdCallback cb, + gpointer user_data); + +gboolean passwd_change_password (PasswdHandler *passwd_handler, + const char *new_password, + PasswdCallback cb, + const gpointer user_data); + +#endif /* _RUN_PASSWD_H */ + diff --git a/capplets/security/security-module.c b/capplets/security/security-module.c new file mode 100644 index 0000000..e82ee89 --- /dev/null +++ b/capplets/security/security-module.c @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2010 Intel Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <config.h> + +#include <glib.h> +#include <glib/gi18n-lib.h> +#include <gmodule.h> +#include <gio/gio.h> + +#include "cc-security-panel.h" + +void +g_io_module_load (GIOModule *module) +{ + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + cc_security_panel_register (module); +} + +void +g_io_module_unload (GIOModule *module) +{ +} diff --git a/capplets/security/security.desktop.in.in b/capplets/security/security.desktop.in.in new file mode 100644 index 0000000..6e03350 --- /dev/null +++ b/capplets/security/security.desktop.in.in @@ -0,0 +1,9 @@ +[Desktop Entry] +_Name=Security and passwords +Icon=moblin-security +Exec=gnome-control-center security.desktop +Terminal=false +Type=Application +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings; +OnlyShowIn=GNOME; diff --git a/capplets/security/security.ui b/capplets/security/security.ui new file mode 100644 index 0000000..fc790c6 --- /dev/null +++ b/capplets/security/security.ui @@ -0,0 +1,214 @@ +<?xml version="1.0"?> +<interface> + <requires lib="gtk+" version="2.16"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkWindow" id="main_window"> + <child> + <object class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="border_width">12</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="spacing">8</property> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Require a password to turn on or wake up my computer</property> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="password_toggle_box"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Change password</property> + <attributes> + <attribute name="weight" value="bold"/> + <attribute name="scale" value="1.200000"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">5</property> + <property name="n_columns">2</property> + <property name="column_spacing">6</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Current password:</property> + </object> + <packing> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">New password:</property> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Repeat password:</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="current_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="new_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="verify_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="visibility">False</property> + <property name="invisible_char">●</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="current_warning_box"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <object class="GtkVBox" id="verify_warning_box"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="save_button"> + <property name="label" translatable="yes">Save new password</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/configure.ac b/configure.ac index 6707c48..55444b1 100644 --- a/configure.ac +++ b/configure.ac @@ -265,6 +265,24 @@ fi AM_CONDITIONAL(BUILD_ABOUTME, test "x$enable_aboutme" = "xyes") dnl ============================================== +dnl Security +dnl ============================================== + +AC_MSG_CHECKING([whether to enable Security]) +AC_ARG_ENABLE([security], + AC_HELP_STRING([--enable-security], + [enable security capplet]),, + [enable_security=no]) +AC_MSG_RESULT([$enable_security]) + +if test "x$enable_security" = "xyes"; then + PKG_CHECK_MODULES(MX_GTK, [mx-gtk-1.0]) +fi +AC_SUBST(MX_GTK_CFLAGS) +AC_SUBST(MX_GTK_LIBS) + +AM_CONDITIONAL(BUILD_SECURITY, test "x$enable_security" = "xyes") + dnl ============================================== dnl Check the window manager we need to work with dnl ============================================== @@ -388,6 +406,8 @@ capplets/network/Makefile capplets/network/gnome-network-properties.desktop.in capplets/windows/Makefile capplets/windows/window-properties.desktop.in +capplets/security/Makefile +capplets/security/security.desktop.in capplets/date/Makefile capplets/language/Makefile font-viewer/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 43d38c2..6d58016 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -82,6 +82,10 @@ capplets/network/cc-network-panel.c capplets/network/gnome-network-properties.c capplets/network/gnome-network-properties.desktop.in.in [type: gettext/glade]capplets/network/gnome-network-properties.ui +capplets/security/cc-security-panel.c +capplets/security/run-passwd.c +capplets/security/security.desktop.in.in +capplets/security/security.ui capplets/windows/gnome-window-properties.c [type: gettext/glade]capplets/windows/gnome-window-properties.ui capplets/windows/window-properties.desktop.in.in diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 1ac7639..0f60f42 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -12,6 +12,7 @@ capplets/keyboard/keyboard.desktop.in capplets/localization/localization.desktop.in capplets/mouse/gnome-settings-mouse.desktop.in capplets/network/gnome-network-properties.desktop.in +capplets/security/security.desktop.in capplets/sound/gnome-settings-sound.desktop.in capplets/windows/window-properties.desktop.in font-viewer/gnome-font-viewer.desktop.in -- 1.7.2.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor