[evolution-ews] Bug #674867 - Change Password Feature for EWS connector



commit 42388b57936edff49e7aba6bc9689db54690c25a
Author: Vibha Yadav <yvibha suse com>
Date:   Tue May 22 13:51:48 2012 +0530

    Bug #674867 - Change Password Feature for EWS connector
    
    Note: Add --with-krb5 to configure argument list for enabling the feature.
          Also add the realms in krb5.conf file for Kerberos communication
    and working feature.

 configure.ac                                       |   11 +
 m4/evo_krb5_support.m4                             |  136 ++++++++
 src/account-setup-eplugin/Makefile.am              |    2 +
 .../exchange-ews-account-setup.c                   |    7 +-
 .../exchange-ews-change-password.c                 |  364 ++++++++++++++++++++
 .../exchange-ews-change-password.h                 |   25 ++
 src/server/Makefile.am                             |   11 +
 src/server/ews-kerberos.c                          |  195 +++++++++++
 src/server/ews-kerberos.h                          |   33 ++
 9 files changed, 783 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index fca79e0..80f4fc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,7 @@
 AC_PREREQ(2.58)
 AC_INIT([evolution-ews], [3.5.2], [http://bugzilla.gnome.org/browse.cgi?product=evolution-ews])
 AM_INIT_AUTOMAKE([gnu 1.9 dist-xz no-dist-gzip -Wno-portability])
+AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR(README)
 AC_CONFIG_HEADERS(config.h)
 
@@ -166,6 +167,11 @@ dnl ****************************
 PKG_CHECK_MODULES(LIBICAL, libical)
 
 dnl ****************************
+dnl Check for kerberos
+dnl ****************************
+EVO_KRB5_SUPPORT
+
+dnl ****************************
 dnl Expose version information
 dnl ****************************
 API_VERSION=1.2
@@ -231,3 +237,8 @@ src/camel/Makefile
 po/Makefile.in
 ])
 AC_OUTPUT
+
+AC_MSG_NOTICE([
+	Kerberos 5	: $msg_krb5
+])
+
diff --git a/m4/evo_krb5_support.m4 b/m4/evo_krb5_support.m4
new file mode 100644
index 0000000..ba37e81
--- /dev/null
+++ b/m4/evo_krb5_support.m4
@@ -0,0 +1,136 @@
+dnl EVO_KRB5_SUPPORT(default)
+dnl Add --with-krb5, --with-krb5-libs and --with-krb5-include options.
+dnl --with-krb5 defaults to the given value if not specified.
+#serial 0.2
+AC_DEFUN([EVO_KRB5_SUPPORT],[
+	dnl ******************************
+	dnl Kerberos
+	dnl ******************************
+	default="$1"
+	AC_ARG_WITH([krb5],
+		AS_HELP_STRING([--with-krb5=PATH],
+		[Location of Kerberos 5 install dir]))
+
+	AC_ARG_WITH([krb5-libs],
+		AS_HELP_STRING([--with-krb5-libs=PATH],
+		[Location of Kerberos 5 libraries]))
+
+	AC_ARG_WITH([krb5-includes],
+		AS_HELP_STRING([--with-krb5-includes=PATH],
+		[Location of Kerberos 5 headers]))
+
+	dnl ******************************
+	dnl Kerberos 5
+	dnl ******************************
+	msg_krb5="no"
+	AC_MSG_CHECKING([for Kerberos 5])
+	with_krb5="${with_krb5:=$default}"
+	case $with_krb5 in
+		no|"")
+			with_krb5=no
+			;;
+		yes)
+			with_krb5=/usr
+			;;
+		*)
+			with_krb5=$with_krb5
+			;;
+	esac
+
+	if test "x${with_krb5}" != "xno"; then
+		LIBS_save="$LIBS"
+
+		case $with_krb5_libs in
+			yes|no|"")
+				with_krb5_libs=$with_krb5/lib
+				;;
+			*)
+				with_krb5_libs=$with_krb5_libs
+				;;
+		esac
+
+		case $with_krb5_includes in
+			yes|no|"")
+				with_krb5_includes=$with_krb5/include
+				;;
+			*)
+				with_krb5_includes=$with_krb5_includes
+				;;
+		esac
+
+		mitlibs="-lkrb5 -lk5crypto -lcom_err -lgssapi_krb5"
+		heimlibs="-lkrb5 -lcrypto -lasn1 -lcom_err -lroken -lgssapi"
+		sunlibs="-lkrb5 -lgss"
+		AC_CACHE_VAL([ac_cv_lib_kerberos5],
+		[
+			LIBS="$LIBS -L$with_krb5_libs $mitlibs"
+			AC_LINK_IFELSE([AC_LANG_CALL([], [krb5_init_context])],
+			[ac_cv_lib_kerberos5="$mitlibs"],
+			[
+				LIBS="$LIBS_save -L$with_krb5_libs $heimlibs"
+				AC_LINK_IFELSE([AC_LANG_CALL([], [krb5_init_context])],
+				[ac_cv_lib_kerberos5="$heimlibs"],
+				[
+					LIBS="$LIBS_save -L$with_krb5_libs $sunlibs"
+					AC_LINK_IFELSE([AC_LANG_CALL([], [krb5_init_context])],
+					[ac_cv_lib_kerberos5="$sunlibs"], [ac_cv_lib_kerberos5="no"])
+				])
+			])
+			LIBS="$LIBS_save"
+		])
+		if test "$ac_cv_lib_kerberos5" != "no"; then
+			AC_DEFINE(HAVE_KRB5,1,[Define if you have Krb5])
+			if test "$ac_cv_lib_kerberos5" = "$mitlibs"; then
+				AC_DEFINE(HAVE_MIT_KRB5,1,[Define if you have MIT Krb5])
+				if test -z "$with_krb5_includes"; then
+					KRB5_CFLAGS="-I$with_krb5/include"
+				else
+					KRB5_CFLAGS="-I$with_krb5_includes"
+				fi
+				msg_krb5="yes (MIT)"
+			else
+				if test "$ac_cv_lib_kerberos5" = "$heimlibs"; then
+					AC_DEFINE(HAVE_HEIMDAL_KRB5,1,[Define if you have Heimdal])
+					if test -z "$with_krb5_includes"; then
+						KRB5_CFLAGS="-I$with_krb5/include/heimdal"
+					else
+						KRB5_CFLAGS="-I$with_krb5_includes"
+					fi
+					msg_krb5="yes (Heimdal)"
+				else
+					AC_DEFINE(HAVE_SUN_KRB5,1,[Define if you have Sun Kerberosv5])
+					if test -z "$with_krb5_includes"; then
+						KRB5_CFLAGS="-I$with_krb5/include/kerberosv5"
+					else
+						KRB5_CFLAGS="-I$with_krb5_includes"
+					fi
+					msg_krb5="yes (Sun)"
+				fi
+			fi
+			KRB5_LIBS="-L$with_krb5_libs $ac_cv_lib_kerberos5"
+		else
+			AC_MSG_ERROR([You specified with krb5, but it was not found.])
+		fi
+	else
+		msg_krb5="no"
+	fi
+	AC_MSG_RESULT([$msg_krb5])
+
+	AM_CONDITIONAL(ENABLE_KRB5, [test "x$with_krb5" != "xno"])
+
+	AC_CHECK_HEADER([et/com_err.h],
+		[AC_DEFINE([HAVE_ET_COM_ERR_H], 1, [Have <et/com_err.h>])],,
+		[[	#if HAVE_ET_COM_ERR_H
+			#include <com_err.h>
+			#endif
+		]])
+	AC_CHECK_HEADER([com_err.h],
+		[AC_DEFINE([HAVE_COM_ERR_H], 1, [Have <com_err.h>])],,
+		[[	#if HAVE_COM_ERR_H
+			#include <com_err.h>
+			#endif
+		]])
+
+	AC_SUBST(KRB5_CFLAGS)
+	AC_SUBST(KRB5_LIBS)
+])
diff --git a/src/account-setup-eplugin/Makefile.am b/src/account-setup-eplugin/Makefile.am
index d597335..620b7ed 100644
--- a/src/account-setup-eplugin/Makefile.am
+++ b/src/account-setup-eplugin/Makefile.am
@@ -36,6 +36,8 @@ liborg_gnome_exchange_ews_la_SOURCES =  \
 	exchange-ews-account-listener.h \
 	exchange-ews-account-out-of-office.c \
 	exchange-ews-account-out-of-office.h \
+	exchange-ews-change-password.c		\
+	exchange-ews-change-password.h		\
 	$(NULL)
 
 liborg_gnome_exchange_ews_la_LIBADD =  \
diff --git a/src/account-setup-eplugin/exchange-ews-account-setup.c b/src/account-setup-eplugin/exchange-ews-account-setup.c
index b2682ca..eadc36f 100644
--- a/src/account-setup-eplugin/exchange-ews-account-setup.c
+++ b/src/account-setup-eplugin/exchange-ews-account-setup.c
@@ -50,6 +50,7 @@
 
 #include "exchange-ews-account-out-of-office.h"
 #include "exchange-ews-account-setup.h"
+#include "exchange-ews-change-password.h"
 
 #define d(x) x
 
@@ -744,7 +745,7 @@ org_gnome_ews_settings (EPlugin *epl,
 {
 	EMConfigTargetSettings *target_account;
 	GtkVBox *vbox_settings;
-	GtkWidget *oof;
+	GtkWidget *oof, *chgpwd;
 
 	target_account = (EMConfigTargetSettings *) data->config->target;
 
@@ -767,6 +768,10 @@ org_gnome_ews_settings (EPlugin *epl,
 	oof = ews_get_outo_office_widget (target_account);
 	gtk_box_pack_start (GTK_BOX (vbox_settings), oof, FALSE, FALSE, 0);
 
+	/*Get Change Password widget*/
+	chgpwd = ews_get_change_pwd_widget (target_account);
+	gtk_box_pack_start (GTK_BOX (vbox_settings), chgpwd, FALSE, FALSE, 0);
+
 	gtk_widget_show_all (GTK_WIDGET (vbox_settings));
 	gtk_notebook_insert_page (GTK_NOTEBOOK (data->parent), GTK_WIDGET (vbox_settings), gtk_label_new(_("EWS Settings")), 4);
 	return GTK_WIDGET (vbox_settings);
diff --git a/src/account-setup-eplugin/exchange-ews-change-password.c b/src/account-setup-eplugin/exchange-ews-change-password.c
new file mode 100644
index 0000000..f08536b
--- /dev/null
+++ b/src/account-setup-eplugin/exchange-ews-change-password.c
@@ -0,0 +1,364 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Authors : Vibha Yadav <yvibha suse com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* exchange-ews-change-password: Change Password code */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "server/e-ews-connection.h"
+#include "server/ews-kerberos.h"
+#include "utils/camel-ews-settings.h"
+#include "mail/em-config.h"
+#include <libedataserverui/e-passwords.h>
+#include <exchange-ews-account-setup.h>
+#include <e-util/e-dialog-utils.h>
+#include <stdlib.h>
+
+#include "exchange-ews-change-password.h"
+#include <gtk/gtk.h>
+
+
+#ifdef HAVE_KRB5
+static void
+entry_changed (GtkEntry *entry,
+               gpointer user_data)
+{
+	GtkEntry *new_entry, *confirm_entry;
+	GtkDialog *pass_dialog;
+	const gchar *text;
+
+	new_entry = GTK_ENTRY (entry);
+	confirm_entry = GTK_ENTRY (user_data);
+	pass_dialog = GTK_DIALOG (g_object_get_data (G_OBJECT (new_entry), "pass_dialog"));
+
+	text = gtk_entry_get_text (new_entry);
+	if (!text || !*text) {
+		gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, FALSE);
+		return;
+	}
+
+	text = gtk_entry_get_text (confirm_entry);
+	if (!text || !*text) {
+		gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, FALSE);
+		return;
+	}
+
+	gtk_dialog_set_response_sensitive (pass_dialog, GTK_RESPONSE_OK, TRUE);
+}
+
+static gchar *
+get_password (EMConfigTargetSettings *target_account)
+{
+	gchar *key, *password = NULL;
+	CamelSettings *settings;
+	CamelURL *url;
+
+	settings = target_account->storage_settings;
+
+	url = g_malloc0 (sizeof (CamelURL));
+	camel_settings_save_to_url (settings, url);
+	key = camel_url_to_string (url, CAMEL_URL_HIDE_PARAMS);
+	camel_url_free (url);
+
+	password = e_passwords_get_password (EXCHANGE_EWS_PASSWORD_COMPONENT, key);
+	if (!password || !*password) {
+		CamelNetworkSettings *network_settings;
+		const gchar *host;
+		gboolean remember = TRUE;
+		gchar *title;
+
+		network_settings = CAMEL_NETWORK_SETTINGS (settings);
+		host = camel_network_settings_get_host (network_settings);
+
+		g_free (password);
+		title = g_strdup_printf ("Enter Password for %s", host);
+		password = e_passwords_ask_password (title, EXCHANGE_EWS_PASSWORD_COMPONENT, key, title,
+						    E_PASSWORDS_REMEMBER_FOREVER | E_PASSWORDS_SECRET,
+						     &remember, NULL);
+		g_free (title);
+	}
+
+	if (!password || !*password) {
+		e_passwords_forget_password (EXCHANGE_EWS_PASSWORD_COMPONENT, key);
+		e_notice (NULL, GTK_MESSAGE_ERROR, "%s","Could not get password.");
+	}
+
+	g_free (key);
+
+	return password;
+}
+
+static gboolean
+e_ews_set_password (EMConfigTargetSettings *account,
+		    const gchar *old_pwd,
+		    const gchar *new_pwd)
+{
+	CamelSettings *settings;
+	CamelNetworkSettings *network_settings;
+	CamelURL *url;
+	EwsKerberosResult result;
+
+	const gchar *user;
+	const gchar *domain;
+	gchar *key;
+
+	/*add up code to call up kerberos set up*/
+	/*Get domain name*/
+	/*pass on username domain name, old and new password to kerberos libraries*/
+	settings = account->storage_settings;
+
+	if (!CAMEL_IS_EWS_SETTINGS (settings))
+		return FALSE;
+
+	/* Verify the storage and transport settings are shared. */
+	g_warn_if_fail (
+		account->storage_settings ==
+		account->transport_settings);
+
+	network_settings = CAMEL_NETWORK_SETTINGS (settings);
+
+	domain = camel_network_settings_get_host (network_settings);
+
+	user = camel_network_settings_get_user (network_settings);
+
+	result = ews_kerberos_change_password (user, domain, old_pwd, new_pwd);
+
+	if(result != EWS_KERBEROS_OK)
+		return FALSE;
+
+	/*On Success add new password to the keyring*/
+
+	url = g_malloc0 (sizeof (CamelURL));
+	camel_settings_save_to_url (settings, url);
+	key = camel_url_to_string (url, CAMEL_URL_HIDE_PARAMS);
+	camel_url_free (url);
+
+	e_passwords_forget_password (EXCHANGE_EWS_PASSWORD_COMPONENT, key);
+	e_passwords_add_password (key, new_pwd);
+	return TRUE;
+}
+#endif
+
+/**
+ * exchange_get_new_password:
+ * @existing_password: The user's current password
+ * @voluntary: %TRUE if the user has chosen "Change Password",
+ * %FALSE if their old password has expired.
+ *
+ * Prompt the user for a new password.
+ */
+gchar *
+e_ews_get_new_password (const gchar *existing_password,
+                           gboolean voluntary)
+{
+	gchar *new_pass = NULL;
+#ifdef HAVE_KRB5
+	GtkResponseType response;
+	GtkWidget *pass_dialog;
+	GtkWidget *dialog_vbox1;
+	GtkWidget *pass_label;
+	GtkWidget *table1;
+	GtkWidget *current_pass_label;
+	GtkWidget *new_pass_label;
+	GtkWidget *confirm_pass_label;
+	GtkWidget *current_pass_entry;
+	GtkWidget *new_pass_entry;
+	GtkWidget *confirm_pass_entry;
+
+	pass_dialog = gtk_dialog_new_with_buttons (
+		"Change Password",
+		NULL,
+		GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK,
+		NULL);
+
+	dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (pass_dialog));
+	gtk_widget_show (dialog_vbox1);
+
+	pass_label = gtk_label_new ("Your current password has expired. Please change your password now.");
+	gtk_widget_show (pass_label);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), pass_label, FALSE, FALSE, 0);
+	gtk_label_set_justify (GTK_LABEL (pass_label), GTK_JUSTIFY_CENTER);
+	gtk_label_set_line_wrap (GTK_LABEL (pass_label), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (pass_label), 0.52, 0.5);
+	gtk_misc_set_padding (GTK_MISC (pass_label), 0, 6);
+
+	table1 = gtk_table_new (3, 2, FALSE);
+	gtk_widget_show (table1);
+	gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0);
+	gtk_container_set_border_width (GTK_CONTAINER (table1), 6);
+	gtk_table_set_row_spacings (GTK_TABLE (table1), 6);
+	gtk_table_set_col_spacings (GTK_TABLE (table1), 6);
+
+	current_pass_label = gtk_label_new_with_mnemonic ("Current _Password:");
+	gtk_widget_show (current_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), current_pass_label, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (current_pass_label), 0, 0.5);
+
+	new_pass_label = gtk_label_new_with_mnemonic ("_New Password:");
+	gtk_widget_show (new_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), new_pass_label, 0, 1, 1, 2,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (new_pass_label), 0, 0.5);
+
+	confirm_pass_label = gtk_label_new_with_mnemonic ("_Confirm Password:");
+	gtk_widget_show (confirm_pass_label);
+	gtk_table_attach (GTK_TABLE (table1), confirm_pass_label, 0, 1, 2, 3,
+			  (GtkAttachOptions) (GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (confirm_pass_label), 0, 0.5);
+
+	new_pass_entry = gtk_entry_new ();
+	gtk_widget_show (new_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), new_pass_entry, 1, 2, 1, 2,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_entry_set_visibility (GTK_ENTRY (new_pass_entry), FALSE);
+
+	confirm_pass_entry = gtk_entry_new ();
+	gtk_widget_show (confirm_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), confirm_pass_entry, 1, 2, 2, 3,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 0);
+	gtk_entry_set_visibility (GTK_ENTRY (confirm_pass_entry), FALSE);
+
+	current_pass_entry = gtk_entry_new ();
+	gtk_widget_show (current_pass_entry);
+	gtk_table_attach (GTK_TABLE (table1), current_pass_entry, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+			  (GtkAttachOptions) (0), 0, 12);
+	gtk_entry_set_visibility (GTK_ENTRY (current_pass_entry), FALSE);
+
+	g_object_set_data (G_OBJECT (new_pass_entry), "pass_dialog", pass_dialog);
+	g_object_set_data (G_OBJECT (confirm_pass_entry), "pass_dialog", pass_dialog);
+	g_signal_connect (new_pass_entry, "changed", G_CALLBACK (entry_changed), confirm_pass_entry);
+	g_signal_connect (confirm_pass_entry, "changed", G_CALLBACK (entry_changed), new_pass_entry);
+	entry_changed (GTK_ENTRY (new_pass_entry), confirm_pass_entry);
+
+	if (voluntary)
+		gtk_widget_hide (GTK_WIDGET (pass_label));
+
+run_dialog_again:
+	response = gtk_dialog_run (GTK_DIALOG (pass_dialog));
+	if (response == GTK_RESPONSE_OK) {
+		const gchar *cur_pass, *new_pass1, *new_pass2;
+
+		cur_pass = gtk_entry_get_text (GTK_ENTRY (current_pass_entry));
+		new_pass1 = gtk_entry_get_text (GTK_ENTRY (new_pass_entry));
+		new_pass2 = gtk_entry_get_text (GTK_ENTRY (confirm_pass_entry));
+
+		if (existing_password) {
+			if (g_strcmp0 (cur_pass, existing_password) != 0) {
+				/* User entered a wrong existing
+				 * password. Prompt him again.
+				 */
+				gtk_label_set_text (GTK_LABEL (pass_label), "The current password should not match the existing password for your account. Please enter the correct password");
+				gtk_widget_show (pass_label);
+				goto run_dialog_again;
+			}
+		}
+
+		if (g_strcasecmp (new_pass1, new_pass2) != 0) {
+			gtk_label_set_text (GTK_LABEL (pass_label), "The two passwords do not match. Please re-enter the passwords.");
+			gtk_widget_show (pass_label);
+			goto run_dialog_again;
+		}
+
+		if (g_strcasecmp (existing_password, new_pass1) == 0)
+		{
+			gtk_label_set_text (GTK_LABEL (pass_label), "The new password matches old password. Please re-enter the passwords.");
+			gtk_widget_show (pass_label);
+			goto run_dialog_again;
+		}
+
+		new_pass = g_strdup (new_pass1);
+	} else
+		new_pass = g_strdup(""); /*Don't use NULL it crashes on kerberos libraries*/
+
+	gtk_widget_destroy (pass_dialog);
+#endif
+
+	return new_pass;
+}
+
+
+static void
+btn_chpass_clicked (GtkButton *button,
+                    gpointer data)
+{
+#ifdef HAVE_KRB5
+	EMConfigTargetSettings *target_account = (EMConfigTargetSettings *) data;
+	gchar *password, *new_password;
+	password = get_password(target_account);
+	new_password = e_ews_get_new_password ( password, TRUE);
+	g_print("Password is %s \n New password is %s", password, new_password);
+
+	if(e_ews_set_password(target_account, password, new_password))
+		e_notice(button, GTK_MESSAGE_INFO, "Password changed successfully. Please remember the same.");
+	else
+#endif
+		e_notice(button, GTK_MESSAGE_ERROR, "Could not reset password. Please try again.");
+}
+
+GtkWidget *
+ews_get_change_pwd_widget (EMConfigTargetSettings *target_account)
+{
+	GtkFrame *frame;
+	GtkWidget *label;
+	GtkVBox *vbox_auth;
+	GtkTable *tbl_auth;
+	GtkLabel *lbl_chpass;
+	GtkButton *btn_chpass;
+
+	gchar *txt;
+
+	txt = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>", "Security Settings");
+	label = gtk_label_new (NULL);
+	gtk_label_set_markup ((GtkLabel *) label, txt);
+	g_free (txt);
+	frame = (GtkFrame*) g_object_new (GTK_TYPE_FRAME, "label-widget", label, NULL);
+	
+	/*Create a VBox*/
+	vbox_auth = (GtkVBox*) g_object_new (GTK_TYPE_VBOX, "homogeneous", FALSE, "spacing", 6, NULL);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox_auth), 6);
+	gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (vbox_auth));
+
+	/*Table for authentication*/
+	tbl_auth = (GtkTable*) g_object_new (GTK_TYPE_TABLE, "n-rows", 2, "n-columns", 2, "homogeneous", FALSE, "row-spacing", 6, "column-spacing", 6, NULL);
+
+	/*Define label and button for change password*/
+	lbl_chpass = (GtkLabel*) g_object_new (GTK_TYPE_LABEL, "label", "Change the password for Exchange EWS account", NULL);
+	gtk_misc_set_alignment (GTK_MISC (lbl_chpass), 0, 0.5);
+	btn_chpass = (GtkButton*) g_object_new (GTK_TYPE_BUTTON, "label", "Change Password", NULL);
+	g_signal_connect (btn_chpass, "clicked", G_CALLBACK (btn_chpass_clicked), target_account);
+
+	gtk_table_attach_defaults (tbl_auth, GTK_WIDGET (lbl_chpass), 0, 1, 0, 1);
+	gtk_table_attach (tbl_auth, GTK_WIDGET (btn_chpass), 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+
+	gtk_box_pack_start (GTK_BOX (vbox_auth), GTK_WIDGET (tbl_auth), FALSE, FALSE, 0);
+
+	return (GtkWidget *) frame;
+}
diff --git a/src/account-setup-eplugin/exchange-ews-change-password.h b/src/account-setup-eplugin/exchange-ews-change-password.h
new file mode 100644
index 0000000..3c71295
--- /dev/null
+++ b/src/account-setup-eplugin/exchange-ews-change-password.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Authors : Vibha Yadav <yvibha suse com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+#include <gtk/gtk.h>
+#include "mail/em-config.h"
+
+gchar *e_ews_get_new_password (const gchar *existing_password, gboolean voluntary);
+GtkWidget *ews_get_change_pwd_widget (EMConfigTargetSettings *target_account);
diff --git a/src/server/Makefile.am b/src/server/Makefile.am
index 3df8d3e..580967e 100644
--- a/src/server/Makefile.am
+++ b/src/server/Makefile.am
@@ -18,6 +18,14 @@ ews-marshal.c: ews-marshal.h
 
 e-ews-connection.c: $(MARSHAL_GENERATED)
 
+if ENABLE_KRB5
+KERBEROS_FILES = \
+	ews-kerberos.c \
+	ews-kerberos.h
+else
+KERBEROS_FILES =
+endif
+
 libeews_1_2_la_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
 	-DG_LOG_DOMAIN=\"libeews\" \
@@ -29,6 +37,7 @@ libeews_1_2_la_CPPFLAGS = \
 	$(LIBECAL_CFLAGS) \
 	$(LIBICAL_CFLAGS) \
 	$(LIBEDATASERVER_CFLAGS) \
+	$(KRB5_CFLAGS)	\
 	$(DEBUG_CFLAGS) \
 	$(NULL)
 
@@ -37,6 +46,7 @@ libeews_1_2_la_SOURCES = \
 	ews-errors.c \
 	ews-marshal.h \
 	ews-marshal.c \
+	$(KERBEROS_FILES) \
 	e-ews-connection.c \
 	e-ews-connection.h \
 	e-ews-folder.c \
@@ -54,6 +64,7 @@ libeews_1_2_la_LIBADD = \
 	$(LIBECAL_LIBS) \
 	$(LIBICAL_LIBS) \
 	$(LIBEDATASERVER_LIBS) \
+	$(KRB5_LIBS) \
 	$(SOCKET_LIBS) \
 	$(NULL)
 
diff --git a/src/server/ews-kerberos.c b/src/server/ews-kerberos.c
new file mode 100644
index 0000000..bbececd
--- /dev/null
+++ b/src/server/ews-kerberos.c
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* Copyright (C) 2004 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ews-kerberos.h"
+#include <krb5.h>
+
+static krb5_context
+ews_kerberos_context_new (const gchar *domain)
+{
+	krb5_context ctx;
+	gchar *realm;
+
+	if (krb5_init_context (&ctx) != 0)
+		return NULL;
+
+	realm = g_ascii_strup (domain, strlen (domain));
+	krb5_set_default_realm (ctx, realm);
+	g_free (realm);
+
+	return ctx;
+}
+
+static EwsKerberosResult
+krb5_result_to_ews_kerberos_result (gint result)
+{
+	switch (result) {
+	case 0:
+		return EWS_KERBEROS_OK;
+
+	case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+		return EWS_KERBEROS_USER_UNKNOWN;
+
+	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+	case KRB5KDC_ERR_PREAUTH_FAILED:
+	case KRB5KDC_ERR_CLIENT_REVOKED:
+		return EWS_KERBEROS_PASSWORD_INCORRECT;
+
+	case KRB5KDC_ERR_KEY_EXP:
+		return EWS_KERBEROS_PASSWORD_EXPIRED;
+
+	case KRB5_KDC_UNREACH:
+		return EWS_KERBEROS_KDC_UNREACHABLE;
+
+	case KRB5KRB_AP_ERR_SKEW:
+		return EWS_KERBEROS_TIME_SKEW;
+
+	default:
+		g_warning ("Unexpected kerberos error %d", result);
+
+	case KRB5_REALM_UNKNOWN:
+		return EWS_KERBEROS_FAILED;
+	}
+}
+
+static EwsKerberosResult
+get_init_cred (krb5_context ctx,
+               const gchar *usr_name,
+               const gchar *passwd,
+               const gchar *in_tkt_service,
+               krb5_creds *cred)
+{
+	krb5_principal principal;
+	krb5_get_init_creds_opt opt;
+	krb5_error_code result;
+
+	result = krb5_parse_name (ctx, usr_name, &principal);
+	if (result)
+		return EWS_KERBEROS_USER_UNKNOWN;
+
+	krb5_get_init_creds_opt_init (&opt);
+	krb5_get_init_creds_opt_set_tkt_life (&opt, 5 *60);
+	krb5_get_init_creds_opt_set_renew_life (&opt, 0);
+	krb5_get_init_creds_opt_set_forwardable (&opt, 0);
+	krb5_get_init_creds_opt_set_proxiable (&opt, 0);
+
+	result = krb5_get_init_creds_password (ctx, cred, principal,
+					       (gchar *) passwd,
+					       NULL, NULL, 0,
+					       (gchar *) in_tkt_service, &opt);
+	krb5_free_principal (ctx, principal);
+
+	return krb5_result_to_ews_kerberos_result (result);
+}
+
+/**
+ * ews_kerberos_change_password
+ * @user: username
+ * @domain: domain name
+ * @old_password: currrent password
+ * @new_password: password to be changed to
+ *
+ * Changes the password for the given user
+ *
+ * Return value: an #EwsKerberosResult
+ **/
+EwsKerberosResult
+ews_kerberos_change_password (const gchar *user,
+                              const gchar *domain,
+                              const gchar *old_password,
+                              const gchar *new_password)
+{
+	krb5_context ctx;
+	krb5_creds creds;
+	krb5_data res_code_string, res_string;
+	EwsKerberosResult result;
+	gint res_code;
+
+	ctx = ews_kerberos_context_new (domain);
+	if (!ctx)
+		return EWS_KERBEROS_FAILED;
+
+	result = get_init_cred (ctx, user, old_password,
+				"kadmin/changepw", &creds);
+	if (result != EWS_KERBEROS_OK) {
+		krb5_free_context (ctx);
+		return result;
+	}
+
+	result = krb5_change_password (ctx, &creds, (gchar *) new_password,
+				       &res_code, &res_code_string, &res_string);
+
+	g_print("%s", res_code_string.data);
+	krb5_free_cred_contents (ctx, &creds);
+	krb5_free_data_contents (ctx, &res_code_string);
+	krb5_free_data_contents (ctx, &res_string);
+	krb5_free_context (ctx);
+
+	if (result != 0)
+		return krb5_result_to_ews_kerberos_result (result);
+	else if (res_code != 0)
+		return EWS_KERBEROS_FAILED;
+	else
+		return EWS_KERBEROS_OK;
+	/*Check for res code and pop up res_string*/
+}
+
+/**
+ * ews_kerberos_check_password:
+ * @user: username
+ * @domain: domain name
+ * @password: current password
+ *
+ * Checks if the password is valid, invalid, or expired
+ *
+ * Return value: %EWS_KERBEROS_OK, %EWS_KERBEROS_USER_UNKNOWN,
+ * %EWS_KERBEROS_PASSWORD_INCORRECT, %EWS_KERBEROS_PASSWORD_EXPIRED,
+ * or %EWS_KERBEROS_FAILED (for unknown errors)
+ **/
+EwsKerberosResult
+ews_kerberos_check_password (const gchar *user,
+                             const gchar *domain,
+                             const gchar *password)
+{
+	krb5_context ctx;
+	krb5_creds creds;
+	EwsKerberosResult result;
+
+	ctx = ews_kerberos_context_new (domain);
+	if (!ctx)
+		return EWS_KERBEROS_FAILED;
+
+	result = get_init_cred (ctx, user, password, NULL, &creds);
+
+	krb5_free_context (ctx);
+	if (result == EWS_KERBEROS_OK)
+		krb5_free_cred_contents (ctx, &creds);
+
+	return result;
+}
diff --git a/src/server/ews-kerberos.h b/src/server/ews-kerberos.h
new file mode 100644
index 0000000..1c82117
--- /dev/null
+++ b/src/server/ews-kerberos.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* Copyright (C) 2004 Novell, Inc. */
+
+#ifndef __EWS_KERBEROS_H__
+#define __EWS_KERBEROS_H__
+
+G_BEGIN_DECLS
+
+typedef enum {
+	EWS_KERBEROS_OK,
+	EWS_KERBEROS_USER_UNKNOWN,
+	EWS_KERBEROS_PASSWORD_INCORRECT,
+	EWS_KERBEROS_PASSWORD_EXPIRED,
+	EWS_KERBEROS_PASSWORD_TOO_WEAK,
+
+	EWS_KERBEROS_KDC_UNREACHABLE,
+	EWS_KERBEROS_TIME_SKEW,
+
+	EWS_KERBEROS_FAILED
+} EwsKerberosResult;
+
+EwsKerberosResult ews_kerberos_check_password  (const gchar *user,
+						const gchar *domain,
+						const gchar *password);
+
+EwsKerberosResult ews_kerberos_change_password (const gchar *user,
+						const gchar *domain,
+						const gchar *old_password,
+						const gchar *new_password);
+
+G_END_DECLS
+
+#endif /* __EWS_KERBEROS_H__ */



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