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 + * 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 + * + * 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 (_("Changing Password for User '%s'"), 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 @@ + + + + + + + + 6 + True + Change Password + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + change-password.png + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + 3 + 2 + False + 6 + 12 + + + + True + _Old Password: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + old_passwd_entry + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + _New Password: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + new_passwd_entry + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + _Confirm Password: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + confirm_passwd_entry + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + True + False + 1024 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + True + True + False + 1024 + + True + * + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + True + False + 1024 + + True + * + False + + + 1 + 2 + 2 + 3 + + + + + + + + + + + True + <b>Changing Password for User '%s'</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + label_item + + + + + 6 + True + True + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + 0.5 + 0.5 + 1 + 1 + 6 + 0 + 12 + 0 + + + + True + Password confirmation empty + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + + 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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 + * + * 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 + +#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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +/* PAM headers */ +#include +#include +#include + +#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