File gnome-control-center-passwd-dialog.patch of Package gnome-control-center

Index: gnome-control-center-2.19.4/capplets/Makefile.am
===================================================================
--- gnome-control-center-2.19.4.orig/capplets/Makefile.am
+++ gnome-control-center-2.19.4/capplets/Makefile.am
@@ -8,7 +8,8 @@ always_built_SUBDIRS =		\
 	sound			\
 	keybindings		\
 	network			\
-	windows
+	windows	                \
+	passwd
 
 SUBDIRS = $(always_built_SUBDIRS)
 
Index: gnome-control-center-2.19.4/capplets/passwd/ChangeLog
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/ChangeLog
@@ -0,0 +1,2 @@
+2005-02-04  Shakti Sen  <shprasad@novell.com>
+	* Added the password change GUI utility
Index: gnome-control-center-2.19.4/capplets/passwd/Makefile.am
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/Makefile.am
@@ -0,0 +1,37 @@
+SUBDIRS = pam
+bin_PROGRAMS = gnome-passwd
+
+gnome_passwd_SOURCES = gnome-passwd.c	\
+			pam-passwd.c	\
+			pam-passwd.h
+gnome_passwd_LDADD =				\
+	$(GNOMECC_CAPPLETS_LIBS)	\
+	$(PASSWD_PAM_LIBS)
+
+@INTLTOOL_DESKTOP_RULE@
+
+Gladedir   = $(pkgdatadir)/glade
+Glade_DATA = gnome-passwd.glade
+
+pixmapdir = $(pkgdatadir)/pixmaps
+pixmap_DATA = change-password.png
+
+desktopdir = $(datadir)/applications
+desktop_in_files = gnome-passwd.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES   = 						\
+	$(GNOMECC_CAPPLETS_CFLAGS)			\
+	$(PASSWD_PAM_INCLUDEDIR) 			\
+	-DGNOMELOCALEDIR="\"$(datadir)/locale\"" 	\
+	-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" 		\
+	-DGNOMECC_GLADE_DIR="\"$(pkgdatadir)/glade\""	\
+	-DINSTALL_PREFIX=\"$(prefix)\"
+
+
+
+CLEANFILES = $(GNOMECC_CAPPLETS_CLEANFILES) $(desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(glade_DATA) $(desktop_icons_DATA) $(desktop_in_files) $(desktop_DATA)
+
+install-exec-hook:
+	chmod o-r $(DESTDIR)$(bindir)/gnome-passwd
Index: gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.c
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.c
@@ -0,0 +1,214 @@
+/* gnome-passwd.c: password change capplet
+ *
+ * Copyright (C) 2005 Novell Inc.
+ *
+ * Written by: Shakti Sen <shprasad@novell.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <libgnome/libgnome.h>
+#include <gconf/gconf-client.h>
+#include <glade/glade.h>
+#include <gnome.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <pwd.h>
+#include <X11/XKBlib.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkx.h>
+
+#include "capplet-util.h"
+#include "pam-passwd.h"
+
+static gboolean
+is_caps_lock_on ()
+{
+	Display *dsp;
+	gint states;
+	dsp = GDK_DISPLAY ();
+	if (XkbGetIndicatorState (dsp, XkbUseCoreKbd, &states) != Success)
+		return FALSE;
+                                                                                
+	return (states & ShiftMask) != 0;
+
+}
+
+void
+cb_activate_entry_old_passwd (GtkEntry *entry, gpointer data)
+{
+	GtkWidget *new_passwd_entry;
+
+	new_passwd_entry = glade_xml_get_widget (GLADE_XML (data), "new_passwd_entry");
+	gtk_widget_grab_focus (new_passwd_entry);
+}
+
+void
+cb_activate_entry_new_passwd (GtkEntry *entry, gpointer data)
+{
+	GtkWidget *confirm_passwd_entry;
+
+	confirm_passwd_entry = glade_xml_get_widget (GLADE_XML (data), "confirm_passwd_entry");
+	gtk_widget_grab_focus (confirm_passwd_entry);
+}
+
+void
+cb_activate_entry_confirm_passwd (GtkEntry *entry, gpointer data)
+{
+	GtkWidget *ok_button;
+	GtkWidget *passwd_dialog;
+
+	ok_button = glade_xml_get_widget (GLADE_XML (data), "okbutton1");
+	passwd_dialog = glade_xml_get_widget (GLADE_XML (data), "passwd_dialog");
+
+	if (GTK_WIDGET_SENSITIVE (ok_button))
+		cb_dialog_response (GTK_DIALOG (passwd_dialog), GTK_RESPONSE_OK, data);
+}
+
+void
+cb_changed_confirmation_match (GtkEntry *entry, gpointer data)
+{
+	GtkWidget *new_passwd_entry;
+	GtkWidget *confirm_passwd_entry;
+	GtkWidget *status_label;
+	GtkWidget *ok_button;
+	gchar *new_passwd;
+	gchar *confirm_passwd;
+	gchar *message = NULL;
+	gboolean active = FALSE;
+
+	ok_button = glade_xml_get_widget (GLADE_XML (data), "okbutton1");
+
+	new_passwd_entry = glade_xml_get_widget (GLADE_XML (data), "new_passwd_entry");
+        new_passwd = g_strdup (gtk_entry_get_text (GTK_ENTRY (new_passwd_entry)));
+                                                                                
+        confirm_passwd_entry = glade_xml_get_widget (GLADE_XML (data), "confirm_passwd_entry");
+        confirm_passwd = g_strdup (gtk_entry_get_text (GTK_ENTRY (confirm_passwd_entry)));
+	status_label = glade_xml_get_widget (GLADE_XML (data), "label4");
+
+	if (!strcmp (new_passwd, confirm_passwd)) {
+	        if (strlen (new_passwd) == 0) {
+			message = _("New Password empty");
+		} else {
+			message = _("Passwords match");
+			active = TRUE;
+		}
+	} else
+		  message = _("Passwords do not match");
+
+	gtk_widget_set_sensitive (ok_button, active);
+	gtk_label_set (GTK_LABEL (status_label), message);
+
+	g_free (new_passwd);
+	g_free (confirm_passwd);
+}
+
+static void
+setup_dialog (GladeXML *dialog)
+{
+	struct passwd* passwd_info = NULL;
+	uid_t cur_uid;
+	gchar *label;
+	GtkWidget *passwd_dialog;
+	GtkWidget *caps_lock_dialog;
+	GtkWidget *old_passwd_entry;
+	GtkWidget *new_passwd_entry;
+	GtkWidget *confirm_passwd_entry;
+	GtkWidget *old_passwd_label;
+	GtkWidget *ok_button;
+                                                                                
+	GtkWidget *widget = glade_xml_get_widget (dialog, "label1");
+	ok_button = glade_xml_get_widget (dialog, "okbutton1");
+	
+	cur_uid = getuid ();
+	passwd_info = getpwuid (cur_uid);
+
+	label = g_strdup_printf (_("<b>Changing Password for User '%s'</b>"), passwd_info->pw_name);
+	gtk_label_set_markup (GTK_LABEL (widget), label);
+	g_free (label);
+	g_signal_connect (WID ("passwd_dialog"), "response",
+			  G_CALLBACK (cb_dialog_response), dialog);
+	g_signal_connect (WID ("passwd_dialog"), "destroy",
+			  G_CALLBACK (gtk_main_quit), dialog);
+	old_passwd_entry = glade_xml_get_widget (dialog, "old_passwd_entry");
+	new_passwd_entry = glade_xml_get_widget (dialog, "new_passwd_entry");
+	confirm_passwd_entry = glade_xml_get_widget (dialog, "confirm_passwd_entry");
+	g_signal_connect (old_passwd_entry, "activate",
+			  G_CALLBACK (cb_activate_entry_old_passwd), dialog);
+	g_signal_connect (new_passwd_entry, "activate",
+			  G_CALLBACK (cb_activate_entry_new_passwd), dialog);
+	g_signal_connect (confirm_passwd_entry, "activate",
+			  G_CALLBACK (cb_activate_entry_confirm_passwd), dialog);
+
+	g_signal_connect (confirm_passwd_entry, "changed",
+			  G_CALLBACK (cb_changed_confirmation_match), dialog);
+	g_signal_connect (new_passwd_entry, "changed",
+			  G_CALLBACK (cb_changed_confirmation_match), dialog);
+	cb_changed_confirmation_match(NULL, dialog);
+
+	if (cur_uid == 0) {
+		old_passwd_label = glade_xml_get_widget (dialog, "oldlabel");
+		gtk_widget_set_sensitive (old_passwd_entry, FALSE);
+		gtk_widget_set_sensitive (old_passwd_label, FALSE);
+		gtk_widget_grab_focus (new_passwd_entry);
+	}
+	else
+		gtk_widget_grab_focus (old_passwd_entry);
+
+
+	gtk_widget_set_sensitive (ok_button, FALSE);
+	passwd_dialog = WID ("passwd_dialog");
+        capplet_set_icon (passwd_dialog, "change-password");
+        gtk_widget_show_all (passwd_dialog);
+
+	if (is_caps_lock_on ()) {
+		caps_lock_dialog = gtk_message_dialog_new (GTK_WINDOW (passwd_dialog),
+					   GTK_DIALOG_MODAL,
+					   GTK_MESSAGE_INFO,
+					   GTK_BUTTONS_OK,
+					   _("You have got capslock on!\nPasswords are case-sensitive."));
+					   
+		g_signal_connect (G_OBJECT (caps_lock_dialog), "response",
+				  G_CALLBACK (gtk_widget_destroy),
+				  NULL);
+		gtk_widget_show (caps_lock_dialog);
+	}
+}
+
+int
+main (int argc, char **argv) 
+{
+	GladeXML    *dialog;
+
+	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	gnome_program_init ("gnome-passwd", VERSION,
+			    LIBGNOMEUI_MODULE,
+			    argc, argv, GNOME_PARAM_NONE);
+
+	dialog = glade_xml_new (GNOMECC_DATA_DIR "/glade/gnome-passwd.glade",
+				"passwd_dialog", NULL);
+
+	setup_dialog (dialog);
+	gtk_main ();
+
+	return 0;
+}
Index: gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.desktop.in.in
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.desktop.in.in
@@ -0,0 +1,15 @@
+[Desktop Entry]
+Encoding=UTF-8
+_Name=Change Password
+_Comment=Change your password
+Exec=gnome-passwd
+Icon=change-password-48
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=GNOME;Settings;
+OnlyShowIn=GNOME;
+X-GNOME-Bugzilla-Bugzilla=GNOME
+X-GNOME-Bugzilla-Product=control-center
+X-GNOME-Bugzilla-Component=password
+X-GNOME-Bugzilla-Version=@VERSION@
Index: gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.glade
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/gnome-passwd.glade
@@ -0,0 +1,318 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="passwd_dialog">
+  <property name="border_width">6</property>
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Change Password</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">False</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="icon">change-password.png</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="has_separator">False</property>
+
+  <child internal-child="vbox">
+    <widget class="GtkVBox" id="dialog-vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child internal-child="action_area">
+	<widget class="GtkHButtonBox" id="dialog-action_area1">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+	  <child>
+	    <widget class="GtkButton" id="cancelbutton1">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-6</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="okbutton1">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="has_focus">True</property>
+	      <property name="label">gtk-ok</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	      <property name="response_id">-5</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">True</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkFrame" id="frame1">
+	  <property name="visible">True</property>
+	  <property name="label_xalign">0</property>
+	  <property name="label_yalign">0.5</property>
+	  <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+	  <child>
+	    <widget class="GtkAlignment" id="alignment1">
+	      <property name="visible">True</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xscale">1</property>
+	      <property name="yscale">1</property>
+	      <property name="top_padding">6</property>
+	      <property name="bottom_padding">0</property>
+	      <property name="left_padding">12</property>
+	      <property name="right_padding">0</property>
+
+	      <child>
+		<widget class="GtkTable" id="table1">
+		  <property name="visible">True</property>
+		  <property name="n_rows">3</property>
+		  <property name="n_columns">2</property>
+		  <property name="homogeneous">False</property>
+		  <property name="row_spacing">6</property>
+		  <property name="column_spacing">12</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="oldlabel">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Old Password:</property>
+		      <property name="use_underline">True</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="mnemonic_widget">old_passwd_entry</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">0</property>
+		      <property name="bottom_attach">1</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="newlabel">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_New Password:</property>
+		      <property name="use_underline">True</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="mnemonic_widget">new_passwd_entry</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">1</property>
+		      <property name="bottom_attach">2</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="confirmlabel">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">_Confirm Password:</property>
+		      <property name="use_underline">True</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="mnemonic_widget">confirm_passwd_entry</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">2</property>
+		      <property name="bottom_attach">3</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="old_passwd_entry">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">False</property>
+		      <property name="max_length">1024</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char" translatable="yes">*</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">0</property>
+		      <property name="bottom_attach">1</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="new_passwd_entry">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">False</property>
+		      <property name="max_length">1024</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char" translatable="yes">*</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <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>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="confirm_passwd_entry">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">False</property>
+		      <property name="max_length">1024</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char" translatable="yes">*</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <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>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label1">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">&lt;b&gt;Changing Password for User '%s'&lt;/b&gt;</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">True</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	    <packing>
+	      <property name="type">label_item</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">6</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkFrame" id="frame2">
+	  <property name="visible">True</property>
+	  <property name="label_xalign">0</property>
+	  <property name="label_yalign">0.5</property>
+	  <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+	  <child>
+	    <widget class="GtkAlignment" id="alignment2">
+	      <property name="visible">True</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xscale">1</property>
+	      <property name="yscale">1</property>
+	      <property name="top_padding">6</property>
+	      <property name="bottom_padding">0</property>
+	      <property name="left_padding">12</property>
+	      <property name="right_padding">0</property>
+
+	      <child>
+		<widget class="GtkLabel" id="label4">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Password confirmation empty</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_CENTER</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <placeholder/>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
Index: gnome-control-center-2.19.4/capplets/passwd/pam-passwd.c
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/pam-passwd.c
@@ -0,0 +1,255 @@
+/* pam-passwd.c: password change capplet
+ *
+ * Copyright (C) 2005 Novell Inc.
+ *
+ * Written by: Shakti Sen <shprasad@novell.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.
+ */
+
+#include <libgnome/libgnome.h>
+#include <glade/glade.h>
+#include <glib.h>
+#include <glade/glade.h>
+#include <gnome.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "config.h"
+#include "pam-passwd.h"
+
+gboolean
+chpasswd_write (gint fd, gchar *msg, gint msg_len) {
+
+	while (msg_len > 0) {
+	        gint bytes_written;
+
+                bytes_written = write (fd, msg, msg_len);
+
+		if (bytes_written < 0) {
+			if (errno == EINTR)
+				continue;
+			else
+				return FALSE;
+		}
+
+		msg = msg + bytes_written;
+		msg_len -= bytes_written; 
+        }
+        return TRUE;
+}
+
+#define OUTPUT_MAX 16384
+
+gboolean
+authenticate_and_change_passwd (gchar* old_passwd,
+				gchar* new_passwd,
+				gchar* confirm_passwd,
+				GError** error)
+{
+    gint childExitStat = 0;
+    gint child_pid; 
+    gint std_input;
+    gint std_output;
+    gint std_error;
+    gint errCode = 0;
+    gboolean retval;
+    GString *snd_old_passwd;
+    GString *snd_new_passwd;
+    GString *snd_confirm_passwd;
+    gchar* command[] = {INSTALL_PREFIX "/sbin/change-passwd", NULL};
+    gchar output [OUTPUT_MAX];
+    gint output_i = 0;
+
+#ifdef DEBUG
+    gchar ch;
+#endif
+
+    snd_old_passwd = g_string_new (OLD_PASSWD_MSG_TITLE);
+    snd_old_passwd = g_string_append (snd_old_passwd, old_passwd);
+
+    snd_new_passwd = g_string_new (NEW_PASSWD_MSG_TITLE);
+    snd_new_passwd = g_string_append (snd_new_passwd, new_passwd);
+
+    snd_confirm_passwd = g_string_new (CONFIRM_PASSWD_MSG_TITLE);
+    snd_confirm_passwd = g_string_append (snd_confirm_passwd, confirm_passwd);
+
+    retval = g_spawn_async_with_pipes (NULL,
+					command,
+					NULL,
+					G_SPAWN_DO_NOT_REAP_CHILD,
+					NULL,
+					NULL,
+					&child_pid,
+					&std_input,
+					&std_output,
+					&std_error,
+					error);
+    if (!retval) {
+	g_set_error (error, 0, errno, _("Could not start helper program.\nCould not change password"));
+	return FALSE;
+    }
+
+    if (write (std_input, (void *)&(snd_old_passwd->len), sizeof (snd_old_passwd->len)) < 0) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }	
+    if (!chpasswd_write (std_input, snd_old_passwd->str, snd_old_passwd->len)) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }
+
+    if (write (std_input, (void *)&(snd_new_passwd->len), sizeof (snd_new_passwd->len)) < 0) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }
+    if (!chpasswd_write (std_input, snd_new_passwd->str, snd_new_passwd->len)) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }
+
+    if (write (std_input, (void *)&(snd_confirm_passwd->len), sizeof (snd_confirm_passwd->len)) < 0) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }
+    if (!chpasswd_write (std_input, snd_confirm_passwd->str, snd_confirm_passwd->len)) {
+	g_set_error (error, 0, errno, _("Unknown error while changing password.\nCould not change password"));
+	return FALSE;
+    }
+
+	while (output_i < OUTPUT_MAX - 1 && read (std_error, &output [output_i], 1))
+		output_i++;
+
+    /* Eliminate trailing newlines */
+    do {
+	output [output_i--] = '\0';
+    } while (output_i >= 0 && output [output_i] == '\n');    
+
+    waitpid (child_pid, &childExitStat, 0);
+
+    /* Use the errCode for displaying errors. */
+    if (WIFEXITED (childExitStat)) {
+	errCode = WEXITSTATUS (childExitStat);
+
+	switch (errCode) {
+	case 0:
+		g_set_error (error, 0, errCode, _("Password changed successfully"));
+		return TRUE;
+	case 7:
+		g_set_error (error, 0, errCode, _("Old password doesn't match. Please try again."));
+		return FALSE;
+	case 101:
+		g_set_error (error, 0, errCode, _("Password is insecure.\nPlease choose a new password."));
+		return FALSE;
+	case 102:
+		g_set_error (error, 0, errCode, _("Password confirmation doesn't match New Password.\nPlease retype new password and confirmation"));
+		return FALSE;
+	case 121:
+		g_set_error (error, 0, errCode, _("Protocol error"));
+		return FALSE;
+	default:
+		if (output [0] != '\0')
+			g_set_error (error, 0, errCode, output);
+		else
+			g_set_error (error, 0, errCode, _("Unknown error while changing password.\nCould not change password"));
+                return FALSE;
+	}
+    }
+
+
+    g_set_error (error, 0, errCode, _("Unknown error while changing password.\nCould not change password"));
+    return FALSE;
+}
+
+void
+cb_dialog_response (GtkDialog *dialog, gint response_id, gpointer data)
+{
+    if (response_id == GTK_RESPONSE_HELP)
+	/* Documentation not available */;
+
+    if (response_id == GTK_RESPONSE_OK) {
+	GtkWidget *old_passwd_entry;
+	GtkWidget *new_passwd_entry;
+	GtkWidget *conf_passwd_entry;
+	GtkWidget *ok_button;
+	GladeXML *xml = GLADE_XML (data);
+	GtkWidget *ok_dialog;
+	GtkWidget *err_dialog;
+	GtkWidget *status_label;
+	GError* error = NULL;
+	gchar *old_passwd = NULL;
+	gchar *new_passwd = NULL;
+	gchar *conf_passwd = NULL;
+	uid_t uid;
+	struct passwd* cur_user_passwd = NULL;
+
+	uid = getuid ();
+	cur_user_passwd = getpwuid (uid);
+                                                                              
+	ok_button = glade_xml_get_widget (xml, "okbutton1");
+	status_label = glade_xml_get_widget (xml, "label4");
+
+	old_passwd_entry = glade_xml_get_widget (xml, "old_passwd_entry");
+	old_passwd = g_strdup (gtk_entry_get_text (GTK_ENTRY (old_passwd_entry)));
+	new_passwd_entry = glade_xml_get_widget (xml, "new_passwd_entry");
+	new_passwd = g_strdup (gtk_entry_get_text (GTK_ENTRY (new_passwd_entry)));
+
+	conf_passwd_entry = glade_xml_get_widget (xml, "confirm_passwd_entry");
+	conf_passwd = g_strdup (gtk_entry_get_text (GTK_ENTRY (conf_passwd_entry)));
+
+	if (!authenticate_and_change_passwd (old_passwd, new_passwd, conf_passwd, &error)) {
+
+		err_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+						     GTK_DIALOG_MODAL,
+						     GTK_MESSAGE_ERROR,
+						     GTK_BUTTONS_OK,
+						     error->message);
+		gtk_widget_show (err_dialog);
+		gtk_dialog_run (GTK_DIALOG (err_dialog));
+		gtk_widget_destroy (GTK_WIDGET (err_dialog));
+		gtk_widget_set_sensitive (ok_button, FALSE);
+		gtk_entry_set_text (GTK_ENTRY (old_passwd_entry), "");
+		gtk_entry_set_text (GTK_ENTRY (new_passwd_entry), "");
+		gtk_entry_set_text (GTK_ENTRY (conf_passwd_entry), "");
+		if (uid == 0)
+			gtk_widget_grab_focus (new_passwd_entry);
+		else
+			gtk_widget_grab_focus (old_passwd_entry);
+		return;
+	}
+	else {
+		if (error->code == 0) {
+			ok_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+							    GTK_DIALOG_MODAL,
+							    GTK_MESSAGE_INFO,
+							    GTK_BUTTONS_OK,
+							    _("Success:\n%s"),
+							    error->message);
+			gtk_widget_show (ok_dialog);
+			gtk_dialog_run (GTK_DIALOG (ok_dialog));
+			gtk_widget_destroy (GTK_WIDGET (dialog));
+			gtk_main_quit ();
+		}
+	}
+    }
+    if (response_id == GTK_RESPONSE_CANCEL) {
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+	gtk_main_quit ();
+    }
+}
Index: gnome-control-center-2.19.4/capplets/passwd/pam-passwd.h
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/pam-passwd.h
@@ -0,0 +1,48 @@
+/* pam-passwd.h: password change capplet
+ *
+ * Copyright (C) 2005 Novell Inc.
+ *
+ * Written by: Shakti Sen <shprasad@novell.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.
+ */
+
+#ifndef __PAM_PASSWD_H
+#define __PAM_PASSWD_H
+                                                                                
+#include <gnome.h>
+
+#define OLD_PASSWD_MSG_TITLE     "old_passwd:"
+#define NEW_PASSWD_MSG_TITLE     "new_passwd:"
+#define CONFIRM_PASSWD_MSG_TITLE "confirm_passwd:"
+
+typedef struct _PAMError PAMError;
+typedef struct _PasswdMsg PasswdMsg;
+
+struct _PAMError {
+	gint error_code;
+	gchar *error_msg;
+};
+
+struct _PasswdMsg {
+	gint len;
+	gchar* msg;
+};
+
+void
+cb_dialog_response (GtkDialog *dialog, gint response_id, gpointer data);
+
+#endif                          /* __PAM_PASSWD_H */
Index: gnome-control-center-2.19.4/capplets/passwd/pam/Makefile.am
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/pam/Makefile.am
@@ -0,0 +1,15 @@
+sbin_PROGRAMS = change-passwd
+
+change_passwd_SOURCES = helper-passwd.c
+
+change_passwd_LDADD =				\
+	$(PASSWD_PAM_LIBS)
+
+pamdir=/etc/pam.d
+pam_DATA=gnome-passwd
+
+@INTLTOOL_DESKTOP_RULE@
+
+install-exec-hook:
+	chmod u+s $(DESTDIR)$(sbindir)/change-passwd
+
Index: gnome-control-center-2.19.4/capplets/passwd/pam/gnome-passwd
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/pam/gnome-passwd
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth	  include        common-auth 
+account  include        common-account 
+password include        common-password
+session  include        common-session 
+
Index: gnome-control-center-2.19.4/capplets/passwd/pam/helper-passwd.c
===================================================================
--- /dev/null
+++ gnome-control-center-2.19.4/capplets/passwd/pam/helper-passwd.c
@@ -0,0 +1,520 @@
+/* helper-passwd.c: password change capplet
+ *
+ * Copyright (C) 2005 Novell Inc.
+ *
+ * Written by: Shakti Sen <shprasad@novell.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.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+
+/* PAM headers */
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+#include <security/pam_modules.h>
+
+#include "config.h"
+
+/* Maximum number of arguments,
+   old-passwd, new-passwd and confirm-passwd
+   Incase of 'root' old-passwd is empty string.
+*/
+#define MAX_NUMBER_OF_ARGS 3
+
+/* Password-protocol-message defines */
+#define OLD_PASSWD_MSG_TITLE     "old_passwd:"
+#define NEW_PASSWD_MSG_TITLE     "new_passwd:"
+#define CONFIRM_PASSWD_MSG_TITLE "confirm_passwd:"
+
+/* Indexes corresponding to the type of passwds */
+#define OLD_PASSWD_INDEX     0
+#define NEW_PASSWD_INDEX     1
+#define CONFIRM_PASSWD_INDEX 2
+
+/* Length of the password */
+#define BUFFER_BASE_SIZE 256
+
+/* Custom error codes */
+#define CHPWD_ERR_RES_ALLOC   105
+#define CHPWD_ERR_IN_PROTOCOL 121
+
+/* Custom PAM error-codes */
+#define CUSTOM_PAM_ERR_BAD_PASSWORD              101
+#define CUSTOM_PAM_ERR_PASSWORD_MISMATCH         102
+#define CUSTOM_PAM_ERR_PASSWORD_CHANGE_ABORTED   103
+
+#define TRUE 1
+#define FALSE 0
+
+/* Counter to hold the current-number of conversation */
+static int cnt = 0;
+static char *pam_last_msg = NULL;
+
+/* Argument list that holds old-passwd, new-passwd and 
+   confirm-passwd values 
+*/
+char *args[] = {NULL, NULL, NULL};
+
+void
+exit_in_peace (int error_code)
+{
+    int i = 0;
+    
+    for (i = 0; i < MAX_NUMBER_OF_ARGS; i++) {
+	if (args [i])
+	    free (args [i]);
+    }
+
+    /* B'bye and see you later */
+    exit (error_code);
+}
+
+int
+environment_settings (void)
+{
+  struct rlimit rlim;
+  int retval = -1;
+                                                                                                                            
+  /* Don't create a core file.  */
+  rlim.rlim_cur = rlim.rlim_max = 0;
+  retval = setrlimit (RLIMIT_CORE, &rlim);
+  if (retval < 0)
+	return retval;
+
+  /* Set all limits to unlimited to avoid to run in any
+     problems later.  */
+  rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+  retval = setrlimit (RLIMIT_AS, &rlim);
+  if (retval < 0)
+        return retval;
+
+  retval = setrlimit (RLIMIT_CPU, &rlim);
+  if (retval < 0)
+        return retval;
+
+  retval = setrlimit (RLIMIT_DATA, &rlim);
+  if (retval < 0)
+        return retval;
+
+  retval = setrlimit (RLIMIT_FSIZE, &rlim);
+  if (retval < 0)
+        return retval;
+
+  retval = setrlimit (RLIMIT_RSS, &rlim);
+  if (retval < 0)
+        return retval;
+
+  retval = setrlimit (RLIMIT_STACK, &rlim);
+  if (retval < 0)
+        return retval;
+                                                                                                                            
+  /* Ignore all signals which may make trouble */
+  signal (SIGALRM, SIG_IGN);
+  signal (SIGXFSZ, SIG_IGN);
+  signal (SIGHUP, SIG_IGN);
+  signal (SIGINT, SIG_IGN);
+  signal (SIGPIPE, SIG_IGN);
+  signal (SIGQUIT, SIG_IGN);
+  signal (SIGTERM, SIG_IGN);
+  signal (SIGTSTP, SIG_IGN);
+  signal (SIGTTOU, SIG_IGN);
+
+  return 0;
+}
+
+char*
+chpwd_strlower (const char* source)
+{
+    char *dest;
+    char *iterator;
+
+    if (!source)
+	return NULL;
+
+    dest = malloc (strlen (source) + 1);
+    if (!dest)
+	return NULL;
+
+    iterator = dest;
+
+    while ((*iterator++ = tolower (*(source++))));
+    return dest;
+}
+
+char* 
+chpwd_strcasestr (const char* haystack, const char* needle)
+{
+    char* haystack_lower;
+    char* needle_lower;
+    char* found = NULL;
+    int index;
+
+    if (!haystack || !needle) 
+	return NULL;
+    
+    haystack_lower = chpwd_strlower (haystack);
+    needle_lower = chpwd_strlower (needle);  
+
+    if (haystack_lower && needle_lower)
+	found = strstr (haystack_lower, needle_lower);
+    if (!found)
+	return NULL;
+
+    index = found - haystack_lower;
+
+    if (index < 0)
+	return NULL;
+
+    found = (char *)(haystack + index);
+
+    free (haystack_lower);
+    free (needle_lower);
+    
+    return found;
+}
+
+int
+ignorable_error (const char* err_msg)
+{
+    int retval = 0;
+
+    if (chpwd_strcasestr (err_msg, "bad password")) {
+	retval = 0;
+    } else if (chpwd_strcasestr (err_msg, "do not match")) {
+	retval = 0;
+    } else if (chpwd_strcasestr (err_msg, "change aborted")) {
+	retval = 1;
+    }
+
+    return retval;
+}
+
+int 
+converse (int n, 
+	  const struct pam_message **msg,
+	  struct pam_response **resp, 
+	  void *data)
+{
+    struct pam_response *aresp;
+    int i;
+
+    if (n <= 0 || n > PAM_MAX_NUM_MSG)
+        return (PAM_CONV_ERR);
+    
+    if ((aresp = calloc (n, sizeof (*aresp))) == NULL)
+        return (PAM_BUF_ERR);
+
+    for (i = 0; i < n; ++i) {
+
+        aresp[i].resp_retcode = 0;
+        aresp[i].resp = NULL;
+
+        switch (msg[i]->msg_style) {
+
+	    case PAM_PROMPT_ECHO_OFF:
+
+		/* Do we need to return any ERROR status? */
+		if (cnt >= MAX_NUMBER_OF_ARGS)
+		    break;
+
+#ifdef DEBUG
+		    fprintf(stderr,"Message style is PAM_PROMPT_ECHO_OFF\n");
+		    fprintf(stderr,"What is in the buffer for %d?\n", cnt);
+		    fprintf(stderr,"\t\t%s\n", args [cnt]);
+#endif
+
+		/* PAM calls expects a pointer that they can free it */
+		aresp[i].resp = strdup (args [cnt]);
+
+		if (aresp[i].resp == NULL)
+		    goto fail;
+		cnt++;
+		break;
+
+	    case PAM_PROMPT_ECHO_ON:
+#ifdef DEBUG
+		    fprintf(stderr,"Message style is PAM_PROMPT_ECHO_ON\n");
+		    fprintf(stderr,"Message is: %s\n", msg[i]->msg);
+#endif
+		/* The user name is passed as the argument. 
+		   So, nothing to do here */
+
+		break;
+
+	    case PAM_ERROR_MSG:
+#ifdef DEBUG
+		    fprintf(stderr,"Message style is PAM_ERROR_MSG\n");
+		    fprintf(stderr,"Error: %s\n", msg[i]->msg);
+#endif
+		if (!ignorable_error (msg[i]->msg)) {
+       		    if (msg[i]->msg && (!pam_last_msg || (pam_last_msg && strcmp (msg[i]->msg, pam_last_msg)))) {
+		        fprintf (stderr, "%s\n\n", msg[i]->msg);
+		    }
+
+		    if (msg[i]->msg) {
+			if (pam_last_msg)
+			    free (pam_last_msg);
+			pam_last_msg = strdup (msg[i]->msg);
+		    }
+		    goto fail;
+		}
+		break;
+
+	    case PAM_TEXT_INFO:
+#ifdef DEBUG
+		    fprintf(stderr,"Message style is PAM_TEXT_INFO\n");
+		    fprintf(stderr,"Warn: %s\n", msg[i]->msg);
+#endif
+
+		if (msg[i]->msg && (!pam_last_msg || (pam_last_msg && strcmp (msg[i]->msg, pam_last_msg)))) {
+		    fprintf (stderr, "%s\n\n", msg[i]->msg);
+		}
+
+		if (msg[i]->msg) {
+		    if (pam_last_msg)
+			free (pam_last_msg);
+		    pam_last_msg = strdup (msg[i]->msg);
+		}
+
+		break;
+
+	    default:
+		goto fail;
+        }
+    }
+
+    *resp = aresp;
+    return (PAM_SUCCESS);
+
+ fail:
+    for (i = 0; i < n; ++i) {
+	if (aresp[i].resp != NULL) {
+	    memset (aresp[i].resp, 0, strlen (aresp[i].resp));
+	    free (aresp[i].resp);
+	}
+    }
+    memset (aresp, 0, n * sizeof (*aresp));
+    *resp = NULL;
+    return (PAM_CONV_ERR);
+}
+
+
+static struct pam_conv conv = {
+    converse,
+    NULL
+};
+
+/* WARN: Do not free the memory returned in **pwd */
+int
+decode_message (char *msg,
+		char **pwd)
+{
+    char *delimiter = NULL;
+
+    delimiter = strchr (msg, ':');
+    if (!delimiter)
+	return -1;
+
+#ifdef DEBUG
+    fprintf(stderr,"Password : %s", delimiter+1);
+#endif
+
+    *pwd = (char *)delimiter+1;
+
+    if (!strncmp (msg, OLD_PASSWD_MSG_TITLE, strlen (OLD_PASSWD_MSG_TITLE)))
+	return OLD_PASSWD_INDEX;
+    else if (!strncmp (msg, NEW_PASSWD_MSG_TITLE, strlen (NEW_PASSWD_MSG_TITLE)))
+	return NEW_PASSWD_INDEX;
+    else if (!strncmp (msg, CONFIRM_PASSWD_MSG_TITLE, strlen (CONFIRM_PASSWD_MSG_TITLE)))
+	return CONFIRM_PASSWD_INDEX;
+    else
+        return -1;
+}
+
+/* Returns bytes read, but thie call doesn't have to be repeated. */
+static int
+chpwd_read (int fd, char *buffer, int length)
+{
+    int bytes_left = length;
+    int bytes_read;
+    while (bytes_left > 0) {
+        bytes_read = read (fd, buffer + length - bytes_left, bytes_left);
+        if (bytes_read < 0) {
+            if (errno == EINTR)
+                continue;
+            else
+                return bytes_read;
+        }
+        if (bytes_read == 0)
+            break;
+        bytes_left -= bytes_read;
+    }
+    return length - bytes_left;
+}
+
+int
+handle_password_protocol ()
+{
+    int pwd_index = -1;
+    int count = 0;
+    char* msg = NULL;
+    char* passwd = NULL;
+    size_t msg_len = 0;
+    
+    while (count++ < MAX_NUMBER_OF_ARGS) {
+
+	if (chpwd_read (STDIN_FILENO, (char *) &msg_len, sizeof (msg_len)) != sizeof (msg_len)) {
+	    return TRUE;
+	}
+
+#ifdef DEBUG
+    fprintf(stderr,"Message Length: %d\n", msg_len);
+#endif
+
+	/* Avoid allocating a huge amount of memory. */
+	if (msg_len >= 1024) {
+	    return TRUE;
+	}
+
+	msg = (char*) malloc (msg_len + 1);
+	if (!msg)
+	    return TRUE;
+
+	if (chpwd_read (STDIN_FILENO, (char *) msg, msg_len) != msg_len)
+	    return TRUE;
+	msg[msg_len] = '\0';
+
+#ifdef DEBUG
+    fprintf(stderr,"Message : %s\n", msg);
+#endif
+
+	pwd_index = decode_message (msg, &passwd);
+
+	if (pwd_index < 0) {
+	    free (msg);
+	    return TRUE;
+	}
+
+#ifdef DEBUG
+    fprintf(stderr,"Password : %s\n", passwd);
+#endif
+
+	args [pwd_index] = strdup (passwd);
+
+	if (args[pwd_index] == NULL) {
+		free(msg);
+		return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+int 
+main (int argc, char *argv[])
+{
+    pam_handle_t *pamh=NULL;
+    int retval = 0;
+    struct stat filebuf;
+    struct passwd *user = NULL;
+    uid_t uid;
+
+    /* We exit if our standard input does not come from
+       a pipe. This is to avoid the user from running the helper app
+       from command line. No messages either. Just quit silently.
+    */
+    if (fstat (STDIN_FILENO, &filebuf) < 0)
+	exit_in_peace (1);
+    if (!S_ISFIFO (filebuf.st_mode)) {
+	exit_in_peace (1);
+    }
+
+
+    /* We do not support command line arguments */
+    if (argc > 1)
+	exit_in_peace (1); 
+
+    /* Get the user name from UID */
+    uid = getuid ();
+    user = getpwuid (uid);
+    if(!user)
+	exit_in_peace (1);
+    
+    /* Set the ulimit and ignore signals */
+     
+    retval = environment_settings ();
+    if (retval < 0)
+	exit_in_peace (CHPWD_ERR_RES_ALLOC);
+
+    if (handle_password_protocol ())
+	exit_in_peace (CHPWD_ERR_IN_PROTOCOL);
+
+    /* Make sure that args[cnt] contains the correct information */
+    if (uid == 0)
+	cnt++;
+
+    retval = pam_start ("gnome-passwd", user->pw_name, &conv, &pamh);
+    if (retval != PAM_SUCCESS) {
+#ifdef DEBUG
+	fprintf(stderr,"Error initializing PAM library.");
+#endif
+	exit_in_peace (1);
+    }
+
+#ifdef DEBUG
+    fprintf(stderr,"PAM library initialization successfull.\n");
+#endif
+    
+    /* Validate the account for password expiries etc.. */
+    retval = pam_acct_mgmt (pamh, 0); 
+    if(retval != PAM_SUCCESS) {
+#ifdef DEBUG
+	fprintf(stderr,pam_strerror (pamh, retval));
+#endif
+	exit_in_peace (retval);
+    }
+
+#ifdef DEBUG
+    fprintf(stderr,"Account validation is successfull.\n");
+#endif
+
+    retval = pam_chauthtok (pamh, 0);
+    if (retval != PAM_SUCCESS) {
+#ifdef DEBUG
+	fprintf(stderr,pam_strerror (pamh, retval));
+#endif
+	exit_in_peace (retval);
+    }
+
+    /* close PAM */
+    if (pam_end (pamh,retval) != PAM_SUCCESS) {
+        pamh = NULL;
+#ifdef DEBUG
+	fprintf(stderr,"Failed to unload-PAM-libraries. \n");
+#endif
+        exit_in_peace (2);
+    }
+    return 0;
+}
Index: gnome-control-center-2.19.4/configure.in
===================================================================
--- gnome-control-center-2.19.4.orig/configure.in
+++ gnome-control-center-2.19.4/configure.in
@@ -292,6 +292,18 @@ if test "x$enable_hal" != "xno"; then
 	AC_SUBST(HAL_LIBS)
 fi
 
+ dnl =======================================
+dnl Required For PAM
+dnl =======================================
+
+PASSWD_PAM_LIBDIR='-L/usr/include'
+PASSWD_PAM_LIBS="$PASSWD_PAM_LIBS -lpam"
+PASSWD_PAM_INCLUDEDIR="$PASSWD_PAM_INCLUDEDIR -I /use/include"
+
+dnl  AC_SUBST(PASSWD_PAM_LIBDIR)
+AC_SUBST(PASSWD_PAM_LIBS)
+AC_SUBST(PASSWD_PAM_INCLUDEDIR)
+
 dnl ==============================================
 dnl End: Check that we meet the  dependencies
 dnl ==============================================
@@ -498,6 +510,9 @@ capplets/mouse/Makefile
 capplets/mouse/gnome-settings-mouse.desktop.in
 capplets/network/Makefile
 capplets/network/gnome-network-preferences.desktop.in
+capplets/passwd/Makefile
+capplets/passwd/pam/Makefile
+capplets/passwd/gnome-passwd.desktop.in
 capplets/sound/Makefile
 capplets/sound/gnome-settings-sound.desktop.in
 capplets/windows/Makefile
Index: gnome-control-center-2.19.4/po/POTFILES.in
===================================================================
--- gnome-control-center-2.19.4.orig/po/POTFILES.in
+++ gnome-control-center-2.19.4/po/POTFILES.in
@@ -62,6 +62,10 @@ capplets/mouse/gnome-settings-mouse.desk
 capplets/network/gnome-network-preferences.c
 capplets/network/gnome-network-preferences.desktop.in.in
 capplets/network/gnome-network-preferences.glade
+capplets/passwd/gnome-passwd.desktop.in.in
+capplets/passwd/gnome-passwd.c
+capplets/passwd/pam-passwd.c
+capplets/passwd/gnome-passwd.glade
 capplets/sound/gnome-settings-sound.desktop.in.in
 capplets/sound/mixer-support.c
 capplets/sound/pipeline-tests.c
openSUSE Build Service is sponsored by