/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