[Commits] [SCM] claws branch, master, updated. 3.13.2-64-gcaa44e5

ticho at claws-mail.org ticho at claws-mail.org
Tue Mar 1 21:02:54 CET 2016


The branch, master has been updated
       via  caa44e52c9f535bd0f2ebe5214fb601c63373bcc (commit)
       via  2a6f8d16b275c63c5daa373d58d5ae867f1f6ba2 (commit)
      from  1b1298656654a49f69f538e89021fc77749c8e9b (commit)

Summary of changes:
 src/Makefile.am     |    2 +
 src/common/defs.h   |    1 +
 src/common/ssl.c    |    6 +-
 src/common/ssl.h    |    2 +-
 src/imap.c          |    5 +-
 src/main.c          |    3 +
 src/news.c          |    7 +-
 src/password.c      |   46 +-----
 src/passwordstore.c |  411 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/passwordstore.h |   75 ++++++++++
 src/prefs_account.c |   97 ++++++++++--
 src/prefs_gtk.c     |   23 +--
 src/send_message.c  |    8 +-
 src/wizard.c        |   35 +++--
 14 files changed, 625 insertions(+), 96 deletions(-)
 create mode 100644 src/passwordstore.c
 create mode 100644 src/passwordstore.h


- Log -----------------------------------------------------------------
commit caa44e52c9f535bd0f2ebe5214fb601c63373bcc
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Feb 28 23:42:56 2016 +0100

    Make accounts use new password store for their passwords.

diff --git a/src/common/ssl.c b/src/common/ssl.c
index 7355b65..c8b1b3d 100644
--- a/src/common/ssl.c
+++ b/src/common/ssl.c
@@ -83,8 +83,10 @@ static int gnutls_cert_cb(gnutls_session_t session,
 	hookdata.is_smtp = sockinfo->is_smtp;
 	hooks_invoke(SSLCERT_GET_CLIENT_CERT_HOOKLIST, &hookdata);	
 
-	if (hookdata.cert_path == NULL)
+	if (hookdata.cert_path == NULL) {
+		g_free(hookdata.password);
 		return 0;
+	}
 
 	sockinfo->client_crt = ssl_certificate_get_x509_from_pem_file(hookdata.cert_path);
 	sockinfo->client_key = ssl_certificate_get_pkey_from_pem_file(hookdata.cert_path);
@@ -106,8 +108,10 @@ static int gnutls_cert_cb(gnutls_session_t session,
 		st->cert.x509 = &(sockinfo->client_crt);
 		st->key.x509 = sockinfo->client_key;
 		st->deinit_all = 0;
+		g_free(hookdata.password);
 		return 0;
 	}
+	g_free(hookdata.password);
 	return 0;
 }
 
diff --git a/src/common/ssl.h b/src/common/ssl.h
index 185faca..3d6523a 100644
--- a/src/common/ssl.h
+++ b/src/common/ssl.h
@@ -47,7 +47,7 @@ struct _SSLClientCertHookData
 {
 	const void *account;
 	const gchar *cert_path;
-	const gchar *password;
+	gchar *password;
 	gboolean is_smtp;
 };
 
diff --git a/src/imap.c b/src/imap.c
index 4307d05..68865dc 100644
--- a/src/imap.c
+++ b/src/imap.c
@@ -71,7 +71,7 @@
 #include "account.h"
 #include "tags.h"
 #include "main.h"
-#include "password.h"
+#include "passwordstore.h"
 
 typedef struct _IMAPFolder	IMAPFolder;
 typedef struct _IMAPSession	IMAPSession;
@@ -1288,7 +1288,8 @@ static gint imap_session_authenticate(IMAPSession *session,
 		Xstrdup_a(acc_pass, pass, {g_free(pass); return MAILIMAP_NO_ERROR;});
 		g_free(pass);
 	} else {
-		acc_pass = password_decrypt(account->passwd, NULL);
+		acc_pass = passwd_store_get(PWS_ACCOUNT, account->account_name,
+				PWS_ACCOUNT_RECV);
 	}
 try_again:
 	pass = acc_pass;
diff --git a/src/main.c b/src/main.c
index c657e8f..19f96f3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -126,6 +126,7 @@
 #include "quicksearch.h"
 #include "advsearch.h"
 #include "avatars.h"
+#include "passwordstore.h"
 
 #ifdef HAVE_LIBETPAN
 #include "imap-thread.h"
@@ -1301,6 +1302,7 @@ int main(int argc, char *argv[])
 	gtk_cmclist_freeze(GTK_CMCLIST(mainwin->folderview->ctree));
 	folder_item_update_freeze();
 
+	passwd_store_read_config();
 	prefs_account_init();
 	account_read_config_all();
 
@@ -1644,6 +1646,7 @@ static void exit_claws(MainWindow *mainwin)
 
 	prefs_common_write_config();
 	account_write_config_all();
+	passwd_store_write_config();
 #ifndef USE_ALT_ADDRBOOK
 	addressbook_export_to_file();
 #endif
diff --git a/src/news.c b/src/news.c
index ead70cb..cc07d17 100644
--- a/src/news.c
+++ b/src/news.c
@@ -48,7 +48,7 @@
 #include "statusbar.h"
 #include "codeconv.h"
 #include "utils.h"
-#include "password.h"
+#include "passwordstore.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
 #include "inputdialog.h"
@@ -405,9 +405,8 @@ static Session *news_session_new_for_folder(Folder *folder)
 		userid = ac->userid;
 		if (password_get(userid, ac->nntp_server, "nntp", port, &passwd)) {
 			/* NOP */;
-		} else if (ac->passwd && ac->passwd[0])
-			passwd = password_decrypt(ac->passwd, NULL);
-		else
+		} else if ((passwd = passwd_store_get(PWS_ACCOUNT, ac->account_name,
+					PWS_ACCOUNT_RECV)) == NULL)
 			passwd = input_dialog_query_password_keep(ac->nntp_server,
 								  userid,
 								  &(ac->session_passwd));
diff --git a/src/password.c b/src/password.c
index 6119db2..9682a6a 100644
--- a/src/password.c
+++ b/src/password.c
@@ -45,6 +45,7 @@
 #include "alertpanel.h"
 #include "inputdialog.h"
 #include "password.h"
+#include "passwordstore.h"
 #include "prefs_common.h"
 
 #ifndef PASSWORD_CRYPTO_OLD
@@ -139,10 +140,6 @@ void master_password_forget()
 
 void master_password_change(const gchar *oldp, const gchar *newp)
 {
-	gchar *pwd, *newpwd;
-	GList *cur;
-	PrefsAccount *acc;
-
 	if (oldp == NULL) {
 		/* If oldp is NULL, make sure the user has to enter the
 		 * current master password before being able to change it. */
@@ -173,46 +170,7 @@ void master_password_change(const gchar *oldp, const gchar *newp)
 		newp = PASSCRYPT_KEY;
 
 	debug_print("Reencrypting all account passwords...\n");
-	for (cur = account_get_list(); cur != NULL; cur = cur->next) {
-		acc = (PrefsAccount *)cur->data;
-		debug_print("account %s\n", acc->account_name);
-
-		/* Password for receiving */
-		if (acc->passwd != NULL && strlen(acc->passwd) > 0) {
-			pwd = password_decrypt(acc->passwd, oldp);
-			if (pwd == NULL) {
-				debug_print("failed to decrypt recv password with old master password\n");
-			} else {
-				newpwd = password_encrypt(pwd, newp);
-				memset(pwd, 0, strlen(pwd));
-				g_free(pwd);
-				if (newpwd == NULL) {
-					debug_print("failed to encrypt recv password with new master password\n");
-				} else {
-					g_free(acc->passwd);
-					acc->passwd = newpwd;
-				}
-			}
-		}
-
-		/* Password for sending */
-		if (acc->smtp_passwd != NULL && strlen(acc->smtp_passwd) > 0) {
-			pwd = password_decrypt(acc->smtp_passwd, oldp);
-			if (pwd == NULL) {
-				debug_print("failed to decrypt smtp password with old master password\n");
-			} else {
-				newpwd = password_encrypt(pwd, newp);
-				memset(pwd, 0, strlen(pwd));
-				g_free(pwd);
-				if (newpwd == NULL) {
-					debug_print("failed to encrypt smtp password with new master password\n");
-				} else {
-					g_free(acc->smtp_passwd);
-					acc->smtp_passwd = newpwd;
-				}
-			}
-		}
-	}
+	passwd_store_reencrypt_all(oldp, newp);
 
 	/* Now reencrypt all plugins passwords fields 
 	 * FIXME: Unloaded plugins won't be able to update their stored passwords
diff --git a/src/prefs_account.c b/src/prefs_account.c
index 6bd3716..89b7a32 100644
--- a/src/prefs_account.c
+++ b/src/prefs_account.c
@@ -63,6 +63,7 @@
 #include "privacy.h"
 #include "inputdialog.h"
 #include "ssl_certificate.h"
+#include "passwordstore.h"
 
 static gboolean cancelled;
 static gboolean new_account;
@@ -432,7 +433,7 @@ static PrefParam basic_param[] = {
 	 &basic_page.uid_entry, prefs_set_data_from_entry, prefs_set_entry},
 
 	{"password", NULL, &tmp_ac_prefs.passwd, P_PASSWORD,
-	 &basic_page.pass_entry, prefs_set_data_from_entry, prefs_set_entry},
+	 NULL, NULL, NULL},
 
 	{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
 };
@@ -536,7 +537,7 @@ static PrefParam send_param[] = {
 	{"smtp_user_id", NULL, &tmp_ac_prefs.smtp_userid, P_STRING,
 	 &send_page.smtp_uid_entry, prefs_set_data_from_entry, prefs_set_entry},
 	{"smtp_password", NULL, &tmp_ac_prefs.smtp_passwd, P_PASSWORD,
-	 &send_page.smtp_pass_entry, prefs_set_data_from_entry, prefs_set_entry},
+	 NULL, NULL, NULL},
 
 	{"pop_before_smtp", "FALSE", &tmp_ac_prefs.pop_before_smtp, P_BOOL,
 	 &send_page.pop_bfr_smtp_checkbtn,
@@ -740,13 +741,13 @@ static PrefParam ssl_param[] = {
 	 &ssl_page.entry_in_cert_file, prefs_set_data_from_entry, prefs_set_entry},
 
 	{"in_ssl_client_cert_pass", "", &tmp_ac_prefs.in_ssl_client_cert_pass, P_PASSWORD,
-	 &ssl_page.entry_in_cert_pass, prefs_set_data_from_entry, prefs_set_entry},
+	 NULL, NULL, NULL},
 
 	{"out_ssl_client_cert_file", "", &tmp_ac_prefs.out_ssl_client_cert_file, P_STRING,
 	 &ssl_page.entry_out_cert_file, prefs_set_data_from_entry, prefs_set_entry},
 
 	{"out_ssl_client_cert_pass", "", &tmp_ac_prefs.out_ssl_client_cert_pass, P_PASSWORD,
-	 &ssl_page.entry_out_cert_pass, prefs_set_data_from_entry, prefs_set_entry},
+	 NULL, NULL, NULL},
 #else
 	{"ssl_pop", "0", &tmp_ac_prefs.ssl_pop, P_ENUM,
 	 NULL, NULL, NULL},
@@ -1018,6 +1019,7 @@ static void basic_create_widget_func(PrefsPage * _page,
 	GtkWidget *auto_configure_lbl;
 	GtkListStore *menu;
 	GtkTreeIter iter;
+	gchar *buf;
 
 	struct BasicProtocol *protocol_optmenu;
 	gint i;
@@ -1332,7 +1334,6 @@ static void basic_create_widget_func(PrefsPage * _page,
 
 	if (new_account) {
 		PrefsAccount *def_ac;
-		gchar *buf;
 
 		prefs_set_dialog_to_default(basic_param);
 		buf = g_strdup_printf(_("Account%d"), ac_prefs->account_id);
@@ -1359,9 +1360,16 @@ static void basic_create_widget_func(PrefsPage * _page,
 				g_free(id);
 			}
 		}
-	} else
+	} else {
 		prefs_set_dialog(basic_param);
 
+		/* Passwords are handled outside of PrefParams. */
+		buf = passwd_store_get(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_RECV);
+		gtk_entry_set_text(GTK_ENTRY(page->pass_entry), buf);
+		g_free(buf);
+	}
+
 	page->vbox = vbox1;
 
 	page->page.widget = vbox1;
@@ -1712,6 +1720,7 @@ static void send_create_widget_func(PrefsPage * _page,
 	GtkWidget *pop_bfr_smtp_tm_spinbtn;
 	GtkWidget *pop_auth_timeout_lbl;
 	GtkWidget *pop_auth_minutes_lbl;
+	gchar *buf;
 
 	vbox1 = gtk_vbox_new (FALSE, VSPACING);
 	gtk_widget_show (vbox1);
@@ -1888,9 +1897,16 @@ static void send_create_widget_func(PrefsPage * _page,
 
 	if (new_account) {
 		prefs_set_dialog_to_default(send_param);
-	} else
+	} else {
 		prefs_set_dialog(send_param);
 
+		/* Passwords are handled outside of PrefParams. */
+		buf = passwd_store_get(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_SEND);
+		gtk_entry_set_text(GTK_ENTRY(page->smtp_pass_entry), buf);
+		g_free(buf);
+	}
+
 	pop_bfr_smtp_tm_set_sens (NULL, NULL);
 
 	page->vbox = vbox1;
@@ -2428,6 +2444,7 @@ static void ssl_create_widget_func(PrefsPage * _page,
 	GtkWidget *hbox;
 	GtkWidget *hbox_spc;
 	GtkWidget *label;
+	gchar *buf;
 
 	vbox1 = gtk_vbox_new (FALSE, VSPACING);
 	gtk_widget_show (vbox1);
@@ -2608,9 +2625,20 @@ static void ssl_create_widget_func(PrefsPage * _page,
 
 	if (new_account) {
 		prefs_set_dialog_to_default(ssl_param);
-	} else
+	} else {
 		prefs_set_dialog(ssl_param);
 
+		/* Passwords are handled outside of PrefParams. */
+		buf = passwd_store_get(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_RECV_CERT);
+		gtk_entry_set_text(GTK_ENTRY(page->entry_in_cert_pass), buf);
+		g_free(buf);
+		buf = passwd_store_get(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_SEND_CERT);
+		gtk_entry_set_text(GTK_ENTRY(page->entry_out_cert_pass), buf);
+		g_free(buf);
+	}
+
 	page->vbox = vbox1;
 
 	page->page.widget = vbox1;
@@ -2944,6 +2972,12 @@ static gint prefs_basic_apply(void)
 				tmp_ac_prefs.account_name ? tmp_ac_prefs.account_name : "(null)");
 	
 	prefs_set_data_from_dialog(basic_param);
+
+	/* Passwords are stored outside of PrefParams. */
+	passwd_store_set(PWS_ACCOUNT, tmp_ac_prefs.account_name,
+			PWS_ACCOUNT_RECV,
+			gtk_entry_get_text(GTK_ENTRY(basic_page.pass_entry)),
+			FALSE);
 	
 	if (protocol == A_IMAP4 || protocol == A_NNTP) {
 		new_id = g_strdup_printf("#%s/%s",
@@ -2967,6 +3001,13 @@ static gint prefs_receive_apply(void)
 static gint prefs_send_apply(void)
 {
 	prefs_set_data_from_dialog(send_param);
+
+	/* Passwords are stored outside of PrefParams. */
+	passwd_store_set(PWS_ACCOUNT, tmp_ac_prefs.account_name,
+			PWS_ACCOUNT_SEND,
+			gtk_entry_get_text(GTK_ENTRY(send_page.smtp_pass_entry)),
+			FALSE);
+
 	return 0;
 }
 
@@ -2992,6 +3033,17 @@ static gint prefs_privacy_apply(void)
 static gint prefs_ssl_apply(void)
 {
 	prefs_set_data_from_dialog(ssl_param);
+
+	/* Passwords are stored outside of PrefParams. */
+	passwd_store_set(PWS_ACCOUNT, tmp_ac_prefs.account_name,
+			PWS_ACCOUNT_RECV_CERT,
+			gtk_entry_get_text(GTK_ENTRY(ssl_page.entry_in_cert_pass)),
+			FALSE);
+	passwd_store_set(PWS_ACCOUNT, tmp_ac_prefs.account_name,
+			PWS_ACCOUNT_SEND_CERT,
+			gtk_entry_get_text(GTK_ENTRY(ssl_page.entry_out_cert_pass)),
+			FALSE);
+
 	return 0;
 }
 #endif
@@ -3359,6 +3411,7 @@ static gboolean sslcert_get_client_cert_hook(gpointer source, gpointer data)
 {
 	SSLClientCertHookData *hookdata = (SSLClientCertHookData *)source;
 	PrefsAccount *account = (PrefsAccount *)hookdata->account;
+	gchar *pwd_id;
 
 	hookdata->cert_path = NULL;
 	hookdata->password = NULL;
@@ -3371,14 +3424,15 @@ static gboolean sslcert_get_client_cert_hook(gpointer source, gpointer data)
 	if (hookdata->is_smtp) {
 		if (account->out_ssl_client_cert_file && *account->out_ssl_client_cert_file)
 			hookdata->cert_path = account->out_ssl_client_cert_file;
-		if (account->out_ssl_client_cert_pass && *account->out_ssl_client_cert_pass)
-			hookdata->password = account->out_ssl_client_cert_pass;
+		pwd_id = PWS_ACCOUNT_SEND_CERT;
 	} else {
 		if (account->in_ssl_client_cert_file && *account->in_ssl_client_cert_file)
 			hookdata->cert_path = account->in_ssl_client_cert_file;
-		if (account->in_ssl_client_cert_pass && *account->in_ssl_client_cert_pass)
-			hookdata->password = account->in_ssl_client_cert_pass;
+		pwd_id = PWS_ACCOUNT_RECV_CERT;
 	}
+
+	hookdata->password = passwd_store_get(PWS_ACCOUNT,
+			account->account_name, pwd_id);
 	return TRUE;
 }
 
@@ -3544,6 +3598,25 @@ void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label)
 		privacy_prefs = NULL;
 	}
 
+	if (ac_prefs->passwd != NULL && strlen(ac_prefs->passwd) > 1) {
+		passwd_store_set(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_RECV, ac_prefs->passwd, TRUE);
+	}
+	if (ac_prefs->smtp_passwd != NULL && strlen(ac_prefs->smtp_passwd) > 1) {
+		passwd_store_set(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_SEND, ac_prefs->smtp_passwd, TRUE);
+	}
+	if (ac_prefs->in_ssl_client_cert_pass != NULL
+			&& strlen(ac_prefs->in_ssl_client_cert_pass) > 1) {
+		passwd_store_set(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_RECV_CERT, ac_prefs->in_ssl_client_cert_pass, TRUE);
+	}
+	if (ac_prefs->out_ssl_client_cert_pass != NULL
+			&& strlen(ac_prefs->out_ssl_client_cert_pass) > 1) {
+		passwd_store_set(PWS_ACCOUNT, ac_prefs->account_name,
+				PWS_ACCOUNT_SEND_CERT, ac_prefs->out_ssl_client_cert_pass, TRUE);
+	}
+
 	ac_prefs->receive_in_progress = FALSE;
 
 	prefs_custom_header_read_config(ac_prefs);
diff --git a/src/prefs_gtk.c b/src/prefs_gtk.c
index 3d6ddec..5fbeb1f 100644
--- a/src/prefs_gtk.c
+++ b/src/prefs_gtk.c
@@ -324,7 +324,6 @@ gint prefs_write_param(PrefParam *param, FILE *fp)
 	for (i = 0; param[i].name != NULL; i++) {
 		switch (param[i].type) {
 		case P_STRING:
-		case P_PASSWORD:
 		{
 			gchar *tmp = NULL;
 
@@ -346,6 +345,8 @@ gint prefs_write_param(PrefParam *param, FILE *fp)
 			g_free(tmp);
 			break;
 		}
+		case P_PASSWORD:
+			break;
 		case P_INT:
 			g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
 				   *((gint *)param[i].data));
@@ -630,17 +631,14 @@ void prefs_set_data_from_entry(PrefParam *pparam)
 		g_free(*str);
 		*str = entry_str[0] ? g_strdup(entry_str) : NULL;
 		break;
+	case P_PASSWORD:
+		break;
 	case P_USHORT:
 		*((gushort *)pparam->data) = atoi(entry_str);
 		break;
 	case P_INT:
 		*((gint *)pparam->data) = atoi(entry_str);
 		break;
-	case P_PASSWORD:
-		str = (gchar **)pparam->data;
-		g_free(*str);
-		*str = password_encrypt(entry_str, NULL);
-		break;
 	default:
 		g_warning("Invalid PrefType for GtkEntry widget: %d",
 			  pparam->type);
@@ -668,7 +666,6 @@ void prefs_set_escaped_data_from_entry(PrefParam *pparam)
 void prefs_set_entry(PrefParam *pparam)
 {
 	gchar **str;
-    char *decrypted_pass = NULL;
 	cm_return_if_fail(*pparam->widget != NULL);
 
 	switch (pparam->type) {
@@ -685,16 +682,6 @@ void prefs_set_entry(PrefParam *pparam)
 		gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
 				   itos(*((gushort *)pparam->data)));
 		break;
-	case P_PASSWORD:
-		str = (gchar **)pparam->data;
-		decrypted_pass = password_decrypt(*str, NULL);
-		gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
-			(decrypted_pass != NULL ? decrypted_pass : ""));
-		if (decrypted_pass != NULL) {
-			memset(decrypted_pass, 0, strlen(decrypted_pass));
-		}
-		g_free(decrypted_pass);
-		break;
 	default:
 		g_warning("Invalid PrefType for GtkEntry widget: %d",
 			  pparam->type);
@@ -729,7 +716,6 @@ void prefs_set_data_from_text(PrefParam *pparam)
 
 	switch (pparam->type) {
 	case P_STRING:
-	case P_PASSWORD:
 		str = (gchar **)pparam->data;
 		g_free(*str);
 		if (GTK_IS_EDITABLE(*pparam->widget)) {   /* need? */
@@ -802,7 +788,6 @@ void prefs_set_text(PrefParam *pparam)
 
 	switch (pparam->type) {
 	case P_STRING:
-	case P_PASSWORD:
 		str = (gchar **)pparam->data;
 		if (*str) {
 			bufp = buf = alloca(strlen(*str) + 1);
diff --git a/src/send_message.c b/src/send_message.c
index 07e3583..fc5a420 100644
--- a/src/send_message.c
+++ b/src/send_message.c
@@ -54,7 +54,7 @@
 #include "gtkutils.h"
 #include "inc.h"
 #include "log.h"
-#include "password.h"
+#include "passwordstore.h"
 
 typedef struct _SendProgressDialog	SendProgressDialog;
 
@@ -306,7 +306,8 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g
 					/* NOP */;
 				} else if (ac_prefs->smtp_passwd)
 					smtp_session->pass =
-						password_decrypt(ac_prefs->smtp_passwd, NULL);
+						passwd_store_get(PWS_ACCOUNT, ac_prefs->account_name,
+								PWS_ACCOUNT_SEND);
 				else {
 					smtp_session->pass =
 						input_dialog_query_password_keep
@@ -325,7 +326,8 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g
 							&(smtp_session->pass))) {
 					/* NOP */;
 				} else if (ac_prefs->passwd)
-					smtp_session->pass = password_decrypt(ac_prefs->passwd, NULL);
+					smtp_session->pass = passwd_store_get(PWS_ACCOUNT,
+							ac_prefs->account_name, PWS_ACCOUNT_RECV);
 				else {
 					smtp_session->pass =
 						input_dialog_query_password_keep
diff --git a/src/wizard.c b/src/wizard.c
index a13a4f2..8d6ba93 100644
--- a/src/wizard.c
+++ b/src/wizard.c
@@ -50,7 +50,7 @@
 #endif
 #include "prefs_common.h"
 #include "combobox.h"
-#include "password.h"
+#include "passwordstore.h"
 
 typedef enum
 {
@@ -757,13 +757,20 @@ static gboolean wizard_write_config(WizardWindow *wizard)
 
 	prefs_account->userid = g_strdup(
 				gtk_entry_get_text(GTK_ENTRY(wizard->recv_username)));
-	prefs_account->passwd = password_encrypt(
-				gtk_entry_get_text(GTK_ENTRY(wizard->recv_password)), NULL);
-
 	prefs_account->smtp_userid = g_strdup(
 				gtk_entry_get_text(GTK_ENTRY(wizard->smtp_username)));
-	prefs_account->smtp_passwd = password_encrypt(
-				gtk_entry_get_text(GTK_ENTRY(wizard->smtp_password)), NULL);
+
+	passwd_store_set(PWS_ACCOUNT,
+			prefs_account->account_name,
+			PWS_ACCOUNT_RECV,
+			gtk_entry_get_text(GTK_ENTRY(wizard->recv_password)),
+			FALSE);
+	passwd_store_set(PWS_ACCOUNT,
+			prefs_account->account_name,
+			PWS_ACCOUNT_SEND,
+			gtk_entry_get_text(GTK_ENTRY(wizard->smtp_password)),
+			FALSE);
+
 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wizard->smtp_auth))) {
 		prefs_account->use_smtp_auth = TRUE;
 	}
@@ -794,13 +801,21 @@ static gboolean wizard_write_config(WizardWindow *wizard)
 
 	prefs_account->out_ssl_client_cert_file = g_strdup(
 				gtk_entry_get_text(GTK_ENTRY(wizard->smtp_ssl_cert_file)));
-	prefs_account->out_ssl_client_cert_pass = g_strdup(
-				gtk_entry_get_text(GTK_ENTRY(wizard->smtp_ssl_cert_pass)));
 	prefs_account->in_ssl_client_cert_file = g_strdup(
 				gtk_entry_get_text(GTK_ENTRY(wizard->recv_ssl_cert_file)));
-	prefs_account->in_ssl_client_cert_pass = g_strdup(
-				gtk_entry_get_text(GTK_ENTRY(wizard->recv_ssl_cert_pass)));
+
+	passwd_store_set(PWS_ACCOUNT,
+			prefs_account->account_name,
+			PWS_ACCOUNT_SEND_CERT,
+			gtk_entry_get_text(GTK_ENTRY(wizard->smtp_ssl_cert_pass)),
+			FALSE);
+	passwd_store_set(PWS_ACCOUNT,
+			prefs_account->account_name,
+			PWS_ACCOUNT_RECV_CERT,
+			gtk_entry_get_text(GTK_ENTRY(wizard->recv_ssl_cert_pass)),
+			FALSE);
 #endif
+
 	if (prefs_account->protocol == A_IMAP4) {
 		gchar *directory = gtk_editable_get_chars(
 			GTK_EDITABLE(wizard->recv_imap_subdir), 0, -1);

commit 2a6f8d16b275c63c5daa373d58d5ae867f1f6ba2
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Thu Feb 18 22:25:55 2016 +0100

    Implement a password store.

diff --git a/src/Makefile.am b/src/Makefile.am
index f958fd5..00c2ae7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -178,6 +178,7 @@ claws_mail_SOURCES = \
 	partial_download.c \
 	password.c \
 	password_gtk.c \
+	passwordstore.c \
 	pop.c \
 	prefs_account.c \
 	prefs_actions.c \
@@ -295,6 +296,7 @@ claws_mailinclude_HEADERS = \
 	partial_download.h \
 	password.h \
 	password_gtk.h \
+	passwordstore.h \
 	pop.h \
 	prefs_account.h \
 	prefs_actions.h \
diff --git a/src/common/defs.h b/src/common/defs.h
index 722f386..c19a26e 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -61,6 +61,7 @@
 #define MENU_RC			"menurc"
 #define RENDERER_RC		"rendererrc"
 #define TAGS_RC			"tagsrc"
+#define PASSWORD_STORE_RC			"passwordstorerc"
 #define QUICKSEARCH_HISTORY	"quicksearch_history"
 #define SUMMARY_SEARCH_FROM_HISTORY	"summarysearch_from_history"
 #define SUMMARY_SEARCH_TO_HISTORY	"summarysearch_to_history"
diff --git a/src/passwordstore.c b/src/passwordstore.c
new file mode 100644
index 0000000..8e3942a
--- /dev/null
+++ b/src/passwordstore.c
@@ -0,0 +1,411 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2016 The Claws Mail Team
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#include "claws-features.h"
+#endif
+
+#ifdef PASSWORD_CRYPTO_GNUTLS
+# include <gnutls/gnutls.h>
+# include <gnutls/crypto.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "common/defs.h"
+#include "common/utils.h"
+#include "passwordstore.h"
+#include "password.h"
+#include "prefs_gtk.h"
+
+static GSList *_password_store;
+
+/* Finds password block of given type and name in the pwdstore. */
+static PasswordBlock *_get_block(PasswordBlockType block_type,
+		const gchar *block_name)
+{
+	GSList *item;
+	PasswordBlock *block;
+
+	g_return_val_if_fail(block_type >= 0 && block_type < NUM_PWS_TYPES,
+			NULL);
+	g_return_val_if_fail(block_name != NULL, NULL);
+
+	for (item = _password_store; item != NULL; item = item->next) {
+		block = (PasswordBlock *)item->data;
+		if (block->block_type == block_type &&
+				!strcmp(block->block_name, block_name))
+			return block;
+	}
+
+	return NULL;
+}
+
+static gboolean _hash_equal_func(gconstpointer a, gconstpointer b)
+{
+	if (g_strcmp0((const gchar *)a, (const gchar *)b) == 0)
+		return TRUE;
+	return FALSE;
+}
+
+/* Creates a new, empty block and adds it to the pwdstore. */
+static PasswordBlock *_new_block(PasswordBlockType block_type,
+		const gchar *block_name)
+{
+	PasswordBlock *block;
+
+	g_return_val_if_fail(block_type >= 0 && block_type < NUM_PWS_TYPES,
+			NULL);
+	g_return_val_if_fail(block_name != NULL, NULL);
+
+	/* First check to see if the block doesn't already exist. */
+	if (_get_block(block_type, block_name)) {
+		debug_print("Block (%d/%s) already exists.\n",
+				block_type, block_name);
+		return NULL;
+	}
+
+	/* Let's create an empty block, and add it to pwdstore. */
+	block = g_new0(PasswordBlock, 1);
+	block->block_type = block_type;
+	block->block_name = g_strdup(block_name);
+	block->entries = g_hash_table_new_full(g_str_hash,
+			(GEqualFunc)_hash_equal_func,
+			g_free, g_free);
+	debug_print("Created password block (%d/%s)\n",
+			block_type, block_name);
+
+	_password_store = g_slist_append(_password_store, block);
+
+	return block;
+}
+
+///////////////////////////////////////////////////////////////
+
+/* Stores a password. */
+gboolean passwd_store_set(PasswordBlockType block_type,
+		const gchar *block_name,
+		const gchar *password_id,
+		const gchar *password,
+		gboolean encrypted)
+{
+	PasswordBlock *block;
+	gchar *encrypted_password;
+
+	g_return_val_if_fail(block_type >= 0 && block_type < NUM_PWS_TYPES,
+			FALSE);
+	g_return_val_if_fail(block_name != NULL, FALSE);
+	g_return_val_if_fail(password_id != NULL, FALSE);
+
+	debug_print("%s password '%s' in block (%d/%s)%s\n",
+			(password == NULL ? "Deleting" : "Storing"),
+			password_id, block_type, block_name,
+			(encrypted ? ", already encrypted" : "") );
+
+	// find correct block (create if needed)
+	if ((block = _get_block(block_type, block_name)) == NULL &&
+			(block = _new_block(block_type, block_name)) == NULL) {
+		debug_print("Could not create password block (%d/%s)\n",
+				block_type, block_name);
+		return FALSE;
+	}
+
+	if (password == NULL) {
+		/* NULL password was passed to us, so delete the entry with
+		 * corresponding id */
+		g_hash_table_remove(block->entries, password_id);
+	} else {
+		if (!encrypted) {
+			/* encrypt password before saving it */
+			if ((encrypted_password =
+						password_encrypt(password, NULL)) == NULL) {
+				debug_print("Could not encrypt password '%s' for block (%d/%s).\n",
+						password_id, block_type, block_name);
+				return FALSE;
+			}
+		} else {
+			/* password is already in encrypted form already */
+			encrypted_password = g_strdup(password);
+		}
+
+		// add encrypted password to the block
+		g_hash_table_insert(block->entries,
+				g_strdup(password_id),
+				encrypted_password);
+	}
+
+	return TRUE;
+}
+
+/* Retrieves a password. */
+gchar *passwd_store_get(PasswordBlockType block_type,
+		const gchar *block_name,
+		const gchar *password_id)
+{
+	PasswordBlock *block;
+	gchar *encrypted_password, *password;
+
+	g_return_val_if_fail(block_type >= 0 && block_type < NUM_PWS_TYPES,
+			NULL);
+	g_return_val_if_fail(block_name != NULL, NULL);
+	g_return_val_if_fail(password_id != NULL, NULL);
+
+	debug_print("Getting password '%s' from block (%d/%s)\n",
+			password_id, block_type, block_name);
+
+	// find correct block
+	if ((block = _get_block(block_type, block_name)) == NULL) {
+		debug_print("Block (%d/%s) not found.\n", block_type, block_name);
+		return NULL;
+	}
+
+	// grab pointer to encrypted password
+	if ((encrypted_password =
+				g_hash_table_lookup(block->entries, password_id)) == NULL) {
+		debug_print("Password '%s' in block (%d/%s) not found.\n",
+				password_id, block_type, block_name);
+		return NULL;
+	}
+
+	// decrypt password
+	if ((password =
+				password_decrypt(encrypted_password, NULL)) == NULL) {
+		debug_print("Could not decrypt password '%s' for block (%d/%s).\n",
+				password_id, block_type, block_name);
+		return NULL;
+	}
+
+	// return decrypted password
+	return password;
+}
+
+/* Reencrypts all stored passwords. */
+void passwd_store_reencrypt_all(const gchar *old_mpwd,
+		const gchar *new_mpwd)
+{
+	PasswordBlock *block;
+	GSList *item;
+	GList *keys, *eitem;
+	gchar *encrypted_password, *decrypted_password, *key;
+
+	g_return_if_fail(old_mpwd != NULL);
+	g_return_if_fail(new_mpwd != NULL);
+
+	for (item = _password_store; item != NULL; item = item->next) {
+		block = (PasswordBlock *)item->data;
+		if (block == NULL)
+			continue; /* Just in case. */
+
+		debug_print("Reencrypting passwords in block (%d/%s).\n",
+				block->block_type, block->block_name);
+
+		if (g_hash_table_size(block->entries) == 0)
+			continue;
+
+		keys = g_hash_table_get_keys(block->entries);
+		for (eitem = keys; eitem != NULL; eitem = eitem->next) {
+			key = (gchar *)eitem->data;
+			if ((encrypted_password =
+						g_hash_table_lookup(block->entries, key)) == NULL)
+				continue;
+
+			if ((decrypted_password =
+						password_decrypt(encrypted_password, old_mpwd)) == NULL) {
+				debug_print("Reencrypt: couldn't decrypt password for '%s'.\n", key);
+				continue;
+			}
+
+			encrypted_password = password_encrypt(decrypted_password, new_mpwd);
+			memset(decrypted_password, 0, strlen(decrypted_password));
+			g_free(decrypted_password);
+			if (encrypted_password == NULL) {
+				debug_print("Reencrypt: couldn't encrypt password for '%s'.\n", key);
+				continue;
+			}
+
+			g_hash_table_insert(block->entries, g_strdup(key), encrypted_password);
+		}
+
+		g_list_free(keys);
+	}
+
+	debug_print("Reencrypting done.\n");
+}
+
+static gint _write_to_file(FILE *fp)
+{
+	PasswordBlock *block;
+	GSList *item;
+	GList *keys, *eitem;
+	gchar *typestr, *line, *key, *pwd;
+
+	for (item = _password_store; item != NULL; item = item->next) {
+		block = (PasswordBlock*)item->data;
+		if (block == NULL)
+			continue; /* Just in case. */
+
+		/* Do not save empty blocks. */
+		if (g_hash_table_size(block->entries) == 0)
+			continue;
+
+		/* Prepare the section header string and write it out. */
+		typestr = NULL;
+		if (block->block_type == PWS_CORE) {
+			typestr = "core";
+		} else if (block->block_type == PWS_ACCOUNT) {
+			typestr = "account";
+		} else if (block->block_type == PWS_PLUGIN) {
+			typestr = "plugin";
+		}
+		line = g_strdup_printf("[%s:%s]\n", typestr, block->block_name);
+
+		if (fputs(line, fp) == EOF) {
+			FILE_OP_ERROR("password store", "fputs");
+			g_free(line);
+			return -1;
+		}
+		g_free(line);
+
+		/* Now go through all passwords in the block and write each out. */
+		keys = g_hash_table_get_keys(block->entries);
+		for (eitem = keys; eitem != NULL; eitem = eitem->next) {
+			key = (gchar *)eitem->data;
+			if ((pwd = g_hash_table_lookup(block->entries, key)) == NULL)
+				continue;
+
+			line = g_strdup_printf("%s %s\n", key, pwd);
+			if (fputs(line, fp) == EOF) {
+				FILE_OP_ERROR("password store", "fputs");
+				g_free(line);
+				return -1;
+			}
+			g_free(line);
+		}
+		g_list_free(keys);
+
+		if (item->next != NULL && fputs("\n", fp) == EOF) {
+			FILE_OP_ERROR("password store", "fputs");
+			return -1;
+		}
+
+	}
+
+	return 1;
+}
+
+void passwd_store_write_config(void)
+{
+	gchar *rcpath;
+	PrefFile *pfile;
+
+	debug_print("Writing password store...\n");
+
+	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+			PASSWORD_STORE_RC, NULL);
+
+	if ((pfile = prefs_write_open(rcpath)) == NULL) {
+		g_warning("failed to open password store file for writing");
+		g_free(rcpath);
+		return;
+	}
+
+	g_free(rcpath);
+
+	if (_write_to_file(pfile->fp) < 0) {
+		g_warning("failed to write password store to file");
+		prefs_file_close_revert(pfile);
+	} else if (prefs_file_close(pfile) < 0) {
+		g_warning("failed to properly close password store file after writing");
+	}
+}
+
+void passwd_store_read_config(void)
+{
+	gchar *rcpath, *contents, **lines, **line, *typestr, *name;
+	GError *error = NULL;
+	guint i = 0;
+	PasswordBlock *block = NULL;
+	PasswordBlockType type;
+
+	// TODO: passwd_store_clear();
+
+	debug_print("Reading password store from file...\n");
+
+	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+			PASSWORD_STORE_RC, NULL);
+
+	if (!g_file_get_contents(rcpath, &contents, NULL, &error)) {
+		g_warning("couldn't read password store from file: %s\n", error->message);
+		g_error_free(error);
+		g_free(rcpath);
+		return;
+	}
+	g_free(rcpath);
+
+	lines = g_strsplit(contents, "\n", -1);
+
+	while (lines[i] != NULL) {
+		if (*lines[i] == '[') {
+			/* Beginning of a new block */
+			line = g_strsplit_set(lines[i], "[:]", -1);
+			if (line[0] != NULL && strlen(line[0]) == 0
+					&& line[1] != NULL && strlen(line[1]) > 0
+					&& line[2] != NULL && strlen(line[2]) > 0
+					&& line[3] != NULL && strlen(line[3]) == 0) {
+				typestr = line[1];
+				name = line[2];
+				if (!strcmp(typestr, "core")) {
+					type = PWS_CORE;
+				} else if (!strcmp(typestr, "account")) {
+					type = PWS_ACCOUNT;
+				} else if (!strcmp(typestr, "plugin")) {
+					type = PWS_PLUGIN;
+				} else {
+					debug_print("Uknown password block type: '%s'\n", typestr);
+					g_strfreev(line);
+					i++; continue;
+				}
+
+				if ((block = _new_block(type, name)) == NULL) {
+					debug_print("Duplicate password block, ignoring: (%d/%s)\n",
+							type, name);
+					g_strfreev(line);
+					i++; continue;
+				}
+			}
+			g_strfreev(line);
+		} else if (strlen(lines[i]) > 0 && block != NULL) {
+			/* If we have started a password block, test for a
+			 * "password_id = password" line. */
+			line = g_strsplit(lines[i], " ", -1);
+			if (line[0] != NULL && strlen(line[0]) > 0
+					&& line[1] != NULL && strlen(line[1]) > 0
+					&& line[2] == NULL) {
+				debug_print("Adding password '%s'\n", line[0]);
+				g_hash_table_insert(block->entries,
+						g_strdup(line[0]), g_strdup(line[1]));
+			}
+			g_strfreev(line);
+		}
+		i++;
+	}
+	g_strfreev(lines);
+}
diff --git a/src/passwordstore.h b/src/passwordstore.h
new file mode 100644
index 0000000..731027c
--- /dev/null
+++ b/src/passwordstore.h
@@ -0,0 +1,75 @@
+/*
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2016 Claws Mail team
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __PASSWORDSTORE_H
+#define __PASSWORDSTORE_H
+
+#include <glib.h>
+
+typedef enum {
+	PWS_CORE,
+	PWS_ACCOUNT,
+	PWS_PLUGIN,
+	NUM_PWS_TYPES
+} PasswordBlockType;
+
+typedef struct _PasswordBlock {
+	PasswordBlockType block_type;
+	gchar *block_name;
+	GHashTable *entries;
+} PasswordBlock;
+
+/* Saves a password into a chosen password block.
+ * The block is created if it doesn't exist.
+ * block_type - from PasswordBlockType
+ * block_name - name of the block
+ * password_id - ID of the saved password
+ * password - the actual password string
+ * encrypted - TRUE if the password string is in an already encrypted form
+ *             (useful mostly for migration from accountrc)
+ *
+ * Function will make a copy of the strings where necessary and doesn't
+ * take ownership of any of the passed arguments. */
+gboolean passwd_store_set(PasswordBlockType block_type,
+		const gchar *block_name,
+		const gchar *password_id,
+		const gchar *password,
+		gboolean encrypted);
+
+/* Retrieves a password. Returned string should be freed by the caller. */
+gchar *passwd_store_get(PasswordBlockType block_type,
+		const gchar *block_name,
+		const gchar *password_id);
+
+/* Reencrypts all stored passwords using new_mpwd as an encryption
+ * password. */
+void passwd_store_reencrypt_all(const gchar *old_mpwd,
+		const gchar *new_mpwd);
+
+/* Writes/reads password store to/from file. */
+void passwd_store_write_config(void);
+void passwd_store_read_config(void);
+
+/* Macros for standard, predefined password IDs. */
+#define PWS_ACCOUNT_RECV      "recv"
+#define PWS_ACCOUNT_SEND      "send"
+#define PWS_ACCOUNT_RECV_CERT "recv_cert"
+#define PWS_ACCOUNT_SEND_CERT "send_cert"
+
+#endif /* __PASSWORDSTORE_H */

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list