/cpw/tomkiewicz/masterpassword: a23f3228c465: New keyring: store...

Tomasz Wasilczyk tomkiewicz at cpw.pidgin.im
Sun Apr 28 21:36:04 EDT 2013


Changeset: a23f3228c465d7a7deb0dd719c735cef293d5bcf
Author:	 Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date:	 2013-04-29 03:35 +0200
Branch:	 soc.2008.masterpassword
URL: https://hg.pidgin.im/cpw/tomkiewicz/masterpassword/rev/a23f3228c465

Description:

New keyring: store passwords using Windows credentials

diffstat:

 libpurple/plugins/keyrings/Makefile.mingw |   11 +-
 libpurple/plugins/keyrings/wincred.c      |  307 ++++++++++++++++++++++++++++++
 libpurple/util.c                          |   26 ++
 libpurple/util.h                          |   18 +
 4 files changed, 361 insertions(+), 1 deletions(-)

diffs (truncated from 439 to 300 lines):

diff --git a/libpurple/plugins/keyrings/Makefile.mingw b/libpurple/plugins/keyrings/Makefile.mingw
--- a/libpurple/plugins/keyrings/Makefile.mingw
+++ b/libpurple/plugins/keyrings/Makefile.mingw
@@ -11,6 +11,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win
 ## VARIABLE DEFINITIONS
 ##
 TARGET_INTERNAL = internalkeyring
+TARGET_WINCRED = wincred
 
 ##
 ## INCLUDE PATHS
@@ -34,6 +35,9 @@ LIB_PATHS += \
 C_SRC_INTERNAL = internalkeyring.c
 OBJECTS_INTERNAL = $(C_SRC_INTERNAL:%.c=%.o)
 
+C_SRC_WINCRED = wincred.c
+OBJECTS_WINCRED = $(C_SRC_WINCRED:%.c=%.o)
+
 ##
 ## LIBRARIES
 ##
@@ -50,10 +54,11 @@ include $(PIDGIN_COMMON_RULES)
 ##
 .PHONY: all install clean
 
-all: $(TARGET_INTERNAL).dll
+all: $(TARGET_INTERNAL).dll $(TARGET_WINCRED).dll
 
 install: all $(PURPLE_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_DIR)
 	cp $(TARGET_INTERNAL).dll $(PURPLE_INSTALL_PLUGINS_DIR)
+	cp $(TARGET_WINCRED).dll $(PURPLE_INSTALL_PLUGINS_DIR)
 
 $(OBJECTS_INTERNAL): $(PURPLE_CONFIG_H)
 
@@ -63,10 +68,14 @@ install: all $(PURPLE_INSTALL_PLUGINS_DI
 $(TARGET_INTERNAL).dll: $(PURPLE_DLL) $(OBJECTS_INTERNAL)
 	$(CC) -shared $(OBJECTS_INTERNAL) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET_INTERNAL).dll
 
+$(TARGET_WINCRED).dll: $(PURPLE_DLL) $(OBJECTS_WINCRED)
+	$(CC) -shared $(OBJECTS_WINCRED) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET_WINCRED).dll
+
 ##
 ## CLEAN RULES
 ##
 clean:
 	rm -f $(OBJECTS_INTERNAL) $(TARGET_INTERNAL).dll
+	rm -f $(OBJECTS_WINCRED) $(TARGET_WINCRED).dll
 
 include $(PIDGIN_COMMON_TARGETS)
diff --git a/libpurple/plugins/keyrings/wincred.c b/libpurple/plugins/keyrings/wincred.c
new file mode 100644
--- /dev/null
+++ b/libpurple/plugins/keyrings/wincred.c
@@ -0,0 +1,307 @@
+/**
+ * @file wincred.c Passwords storage using Windows credentials
+ * @ingroup plugins
+ */
+
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program ; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "debug.h"
+#include "internal.h"
+#include "keyring.h"
+#include "plugin.h"
+#include "version.h"
+
+#include <wincred.h>
+
+#define WINCRED_NAME        N_("Windows credentials")
+#define WINCRED_SUMMARY     N_("Store passwords using Windows credentials")
+#define WINCRED_DESCRIPTION N_("This plugin stores passwords using Windows " \
+	"credentials.")
+#define WINCRED_AUTHOR      "Tomek Wasilczyk (tomkiewicz at cpw.pidgin.im)"
+#define WINCRED_ID          "keyring-wincred"
+
+#define WINCRED_MAX_TARGET_NAME 256
+
+static PurpleKeyring *keyring_handler = NULL;
+
+static gunichar2 *
+wincred_get_target_name(PurpleAccount *account)
+{
+	gchar target_name_utf8[WINCRED_MAX_TARGET_NAME];
+	gunichar2 *target_name_utf16;
+
+	g_return_val_if_fail(account != NULL, NULL);
+
+	g_snprintf(target_name_utf8, WINCRED_MAX_TARGET_NAME, "libpurple_%s_%s",
+		purple_account_get_protocol_id(account),
+		purple_account_get_username(account));
+
+	target_name_utf16 = g_utf8_to_utf16(target_name_utf8, -1,
+		NULL, NULL, NULL);
+
+	if (target_name_utf16 == NULL) {
+		purple_debug_fatal("keyring-wincred", "Couldn't convert target "
+			"name\n");
+	}
+
+	return target_name_utf16;
+}
+
+static void
+wincred_read(PurpleAccount *account, PurpleKeyringReadCallback cb,
+	gpointer data)
+{
+	GError *error = NULL;
+	gunichar2 *target_name = NULL;
+	gchar *password;
+	PCREDENTIALW credential;
+
+	g_return_if_fail(account != NULL);
+
+	target_name = wincred_get_target_name(account);
+	g_return_if_fail(target_name != NULL);
+
+	if (!CredReadW(target_name, CRED_TYPE_GENERIC, 0, &credential)) {
+		DWORD error_code = GetLastError();
+
+		if (error_code == ERROR_NOT_FOUND) {
+			if (purple_debug_is_verbose()) {
+				purple_debug_misc("keyring-wincred",
+					"No password found for account %s\n",
+					purple_account_get_username(account));
+			}
+			error = g_error_new(PURPLE_KEYRING_ERROR,
+				PURPLE_KEYRING_ERROR_NOPASSWORD,
+				"Password not found.");
+		} else if (error_code == ERROR_NO_SUCH_LOGON_SESSION) {
+			purple_debug_error("keyring-wincred",
+				"Cannot read password, no valid logon "
+				"session\n");
+			error = g_error_new(PURPLE_KEYRING_ERROR,
+				PURPLE_KEYRING_ERROR_ACCESSDENIED,
+				"Cannot read password, no valid logon session");
+		} else {
+			purple_debug_error("keyring-wincred",
+				"Cannot read password, error %lx\n",
+				error_code);
+			error = g_error_new(PURPLE_KEYRING_ERROR,
+				PURPLE_KEYRING_ERROR_BACKENDFAIL,
+				"Cannot read password, error %lx", error_code);
+		}
+
+		if (cb != NULL)
+			cb(account, NULL, error, data);
+		g_error_free(error);
+		return;
+	}
+
+	password = g_utf16_to_utf8((gunichar2*)credential->CredentialBlob,
+		credential->CredentialBlobSize / sizeof(gunichar2),
+		NULL, NULL, NULL);
+
+	memset(credential->CredentialBlob, 0, credential->CredentialBlobSize);
+	CredFree(credential);
+
+	if (password == NULL) {
+		purple_debug_error("keyring-wincred",
+			"Cannot convert password\n");
+		error = g_error_new(PURPLE_KEYRING_ERROR,
+			PURPLE_KEYRING_ERROR_BACKENDFAIL,
+			"Cannot convert password");
+	}
+
+	if (cb != NULL)
+		cb(account, password, error, data);
+	if (error != NULL)
+		g_error_free(error);
+
+	purple_str_wipe(password);
+}
+
+static void
+wincred_save(PurpleAccount *account, const gchar *password,
+	PurpleKeyringSaveCallback cb, gpointer data)
+{
+	GError *error = NULL;
+	gunichar2 *target_name = NULL;
+	gunichar2 *username_utf16 = NULL;
+	gunichar2 *password_utf16 = NULL;
+	CREDENTIALW credential;
+
+	g_return_if_fail(account != NULL);
+
+	target_name = wincred_get_target_name(account);
+	g_return_if_fail(target_name != NULL);
+
+	if (password == NULL)
+	{
+		if (CredDeleteW(target_name, CRED_TYPE_GENERIC, 0)) {
+			purple_debug_misc("keyring-wincred", "Password for "
+				"account %s removed\n",
+				purple_account_get_username(account));
+		} else {
+			DWORD error_code = GetLastError();
+
+			if (error_code == ERROR_NOT_FOUND) {
+				/* Pasword doesn't existed. */
+			} else if (error_code == ERROR_NO_SUCH_LOGON_SESSION) {
+				purple_debug_error("keyring-wincred",
+					"Cannot remove password, no valid "
+					"logon session\n");
+				error = g_error_new(PURPLE_KEYRING_ERROR,
+					PURPLE_KEYRING_ERROR_ACCESSDENIED,
+					"Cannot remove password, no valid "
+					"logon session");
+			} else {
+				purple_debug_error("keyring-wincred",
+					"Cannot remove password, error %lx\n",
+					error_code);
+				error = g_error_new(PURPLE_KEYRING_ERROR,
+					PURPLE_KEYRING_ERROR_BACKENDFAIL,
+					"Cannot remove password, error %lx",
+					error_code);
+			}
+		}
+
+		if (cb != NULL)
+			cb(account, error, data);
+		if (error != NULL)
+			g_error_free(error);
+		return;
+	}
+
+	username_utf16 = g_utf8_to_utf16(purple_account_get_username(account),
+		-1, NULL, NULL, NULL);
+	password_utf16 = g_utf8_to_utf16(password, -1, NULL, NULL, NULL);
+
+	if (username_utf16 == NULL || password_utf16 == NULL) {
+		g_free(username_utf16);
+		purple_utf16_wipe(password_utf16);
+
+		purple_debug_fatal("keyring-wincred", "Couldn't convert "
+			"username or password\n");
+		g_return_if_reached();
+	}
+
+	memset(&credential, 0, sizeof(CREDENTIALW));
+	credential.Type = CRED_TYPE_GENERIC;
+	credential.TargetName = target_name;
+	credential.CredentialBlobSize = purple_utf16_size(password_utf16) - 2;
+	credential.CredentialBlob = (LPBYTE)password_utf16;
+	credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
+	credential.UserName = username_utf16;
+
+	if (!CredWriteW(&credential, 0)) {
+		DWORD error_code = GetLastError();
+
+		if (error_code == ERROR_NO_SUCH_LOGON_SESSION) {
+			purple_debug_error("keyring-wincred",
+				"Cannot store password, no valid logon "
+				"session\n");
+			error = g_error_new(PURPLE_KEYRING_ERROR,
+				PURPLE_KEYRING_ERROR_ACCESSDENIED,
+				"Cannot remove password, no valid logon "
+				"session");
+		} else {
+			purple_debug_error("keyring-wincred",
+				"Cannot store password, error %lx\n",
+				error_code);
+			error = g_error_new(PURPLE_KEYRING_ERROR,
+				PURPLE_KEYRING_ERROR_BACKENDFAIL,
+				"Cannot store password, error %lx", error_code);
+		}
+	}
+
+	g_free(target_name);
+	g_free(username_utf16);
+	purple_utf16_wipe(password_utf16);
+
+	if (cb != NULL)
+		cb(account, error, data);
+	if (error != NULL)
+		g_error_free(error);
+}
+
+static gboolean
+wincred_load(PurplePlugin *plugin)
+{



More information about the Commits mailing list