/******************************************************************* * KWallet Password Plugin * * Copyright (C) 2008, C. Shaun Wagner , * Charles Tullock , * Jonathan Blount ******************************************************************* * COMPILING * This plugin saves account passwords in KWallet instead of the * plain text accounts.xml file. * * Before attempting to compile this plugin, ensure that you have * downloaded the pidgin development tree. Instructions for the * basics of doing this and compiling a plugin are found at: * http://developer.pidgin.im/wiki/CHowTo/BasicPluginHowto * Run the configure script from the source to create a default * Makefile and then place this plugin source in the * libpurple/plugins/ directory. Once done, you can run make with * the following instructions. * * This plugin must be compiled with g++, not gcc. * This plugin requries the header locations for KDE and Qt. * They are commonly in: * /usr/include/kde * /usr/lib/qt-3.3/include * This plugin must link to lkwalletclient. * When compiling, the default Makefile may be used using the make * command with the following flags: * make \ * CC=g++ \ * CFLAGS="-I/usr/include/kde -I/usr/lib/qt-3.3/include" \ * LDFLAGS="-lkwalletclient" \ * kwallet_password.so * Ignore the warnings about options that are in the default * makefile but not used by C++. ******************************************************************* * INSTALLATION * As with all libpurple plugins, copy kwallet_password.so to the * libpurple plugin directory, such as: * ~/.purple/plugins ******************************************************************* * USAGE * Create the accounts that you want to use in the chat program that * uses libpurple. Save the passwords and check the "remember * passwords" checkbox. * In Tools->KWallet Passwords, select Encrypt Passwords. * All passwords will be moved from accounts.xml to KWallet. * * If you create a new account, check the "remember passwords" * checkbox on it and select Encrypt Passwords again. It will * encrypt any accounts that have a password saved in accounts.xml. * * To put the passwords back in accounts.xml, select Decrypt * Passwords instead of Encrypt Passwords. All passwords will be * put in the accounts.xml file and removed from KWallet. ******************************************************************* * LICENSE * 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. *******************************************************************/ /* Just in case there is an external config header. */ #ifdef HAVE_CONFIG_H # include #endif /* config.h may define PURPLE_PLUGINS; protect the definition here so that we don't get complaints about redefinition when it's not necessary. */ #ifndef PURPLE_PLUGINS # define PURPLE_PLUGINS #endif /* Libpurple is a glib application. */ #include /* This will prevent compiler errors in some instances and is better explained in the how-to documents on the wiki */ #ifndef G_GNUC_NULL_TERMINATED # if __GNUC__ >= 4 # define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) # else # define G_GNUC_NULL_TERMINATED # endif #endif /* Include the required libpurple headers. */ #include #include #include /* Include the requried KDE headers. */ #include #include #include #include PurplePlugin *kwalletpassword_plugin = NULL; //A handle to our plugin - will be initiated in plugin_load(). KWallet::Wallet *wallet = NULL; // A pointer to KWallet - it doesn't like be declared over and over inside a function. KApplication *app; // A pointer to the KApplication app - can only declare it once or we'll core dump! /* Encrypt a password for a specific account */ static void plugin_encrypt_password_cb (gpointer data, gpointer user_data) { PurpleAccount *account; // The account to manage char protouser[100]; // A name for KWallet (the protocol and username) account = (PurpleAccount*)data; sprintf(protouser, "%s:%s", purple_account_get_protocol_id(account), purple_account_get_username(account)); /* Only save passwords for accounts that are remembering passwords in accounts.xml. */ if(purple_account_get_remember_password(account)) { /* Open KWallet and select the libpurple folder. */ if(not wallet) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the standard wallet.", NULL, NULL, NULL); return; } if(not wallet->hasFolder("libpurple")) { if(not wallet->createFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not create a password folder.", NULL, NULL, NULL); return; } } if (not wallet->setFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the password folder.", NULL, NULL, NULL); return; } /* Attempt to save the password for strcat(protocol,username). */ if(wallet->writePassword(protouser, purple_account_get_password(account)) == 0) { /* KWallet has the password now - so accounts.xml can forget it. */ purple_account_set_remember_password(account, FALSE); } else { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not save password in KWallet.", NULL, NULL, NULL); } } } /* Fetch a password for a specific account */ static void plugin_fetch_password_cb (gpointer data, gpointer user_data) { PurpleAccount *account; // The account to manage char protouser[100]; // A key for KWallet (account protocol and username) QString password; // A holder for the password from KWallet account = (PurpleAccount*)data; sprintf(protouser, "%s:%s", purple_account_get_protocol_id(account), purple_account_get_username(account)); /* Only fetch passwords for accounts that are not remembering passwords in accounts.xml. */ if(not purple_account_get_remember_password(account)) { /* Open KWallet and select the libpurple folder. */ if(not wallet) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the standard wallet.", NULL, NULL, NULL); return; } if(not wallet->hasFolder("libpurple")) { if(not wallet->createFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not create a password folder.", NULL, NULL, NULL); return; } } if (not wallet->setFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the password folder.", NULL, NULL, NULL); return; } /* Place the password in the account in memory. */ if(wallet->readPassword(protouser, password) != 0) { // Don't print an error here - it could just be that the password isn't saved. return; } purple_account_set_password(account, password.latin1()); } } /* Decrypt a password for a specific account */ static void plugin_decrypt_password_cb (gpointer data, gpointer user_data) { PurpleAccount *account; // The account to manage char protouser[100]; // A key for KWallet (account protocol and username) QString password; // A holder for the password from KWallet account = (PurpleAccount*)data; sprintf(protouser, "%s:%s", purple_account_get_protocol_id(account), purple_account_get_username(account)); /* Only decrypt passwords for accounts that are not remembering passwords in accounts.xml. */ if(not purple_account_get_remember_password(account)) { /* Open KWallet and select the libpurple folder. */ if(not wallet) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the standard wallet.", NULL, NULL, NULL); return; } if(not wallet->hasFolder("libpurple")) { if(not wallet->createFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not create a password folder.", NULL, NULL, NULL); return; } } if (not wallet->setFolder("libpurple")) { purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_ERROR, "KWallet Error", "Could not open the password folder.", NULL, NULL, NULL); return; } /* Place the password in the account in accounts.xml and remove it from KWallet. */ if(wallet->readPassword(protouser, password) != 0) { // Don't print an error here - it could just be that the password isn't saved. return; } purple_account_set_password(account, password.latin1()); purple_account_set_remember_password(account, TRUE); wallet->removeEntry(protouser); } } /* Encrypt all saved passwords in accounts.xml */ static void plugin_encrypt_passwords_cb (PurplePluginAction * action) { GList *accounts = NULL; accounts = purple_accounts_get_all(); g_list_foreach(accounts, plugin_encrypt_password_cb, NULL); // You cannot g_list_free(accounts) here without segfaulting Pidgin. purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_INFO, "KWallet Password", "All saved passwords are now in KWallet.", NULL, NULL, NULL); } /* Decrypt all passwords in KWallet and put them in teh accounts.xml file. */ static void plugin_decrypt_passwords_cb (PurplePluginAction * action) { GList *accounts = NULL; accounts = purple_accounts_get_all(); g_list_foreach(accounts, plugin_decrypt_password_cb, NULL); // You cannot g_list_free(accounts) here without segfaulting Pidgin. purple_notify_message (kwalletpassword_plugin, PURPLE_NOTIFY_MSG_INFO, "KWallet Password", "All saved passwords are now in accounts.xml as plain text.", NULL, NULL, NULL); } /* Register plugin actions */ static GList * plugin_actions (PurplePlugin * plugin, gpointer context) { GList *list = NULL; // The action list. PurplePluginAction *action = NULL; // A action temp pointer. action = purple_plugin_action_new ("Encrypt Passwords", plugin_encrypt_passwords_cb); list = g_list_append (list, action); action = purple_plugin_action_new ("Decrypt Passwords", plugin_decrypt_passwords_cb); list = g_list_append (list, action); return list; } /* Called when the plugin loads (after plugin_init()) */ static gboolean plugin_load (PurplePlugin * plugin) { kwalletpassword_plugin = plugin; /* assign this here so we have a valid handle later */ /* Set the passwords for the accounts before they try to connect. */ GList *accounts = NULL; accounts = purple_accounts_get_all(); g_list_foreach(accounts, plugin_fetch_password_cb, NULL); // You cannot g_list_free(accounts) here without segfaulting Pidgin. return TRUE; } /* For specific notes on the meanings of each of these members, consult the C Plugin Howto on the website. */ static PurplePluginInfo info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_PLUGIN_STANDARD, NULL, 0, NULL, PURPLE_PRIORITY_DEFAULT, "core-kwallet_password", "KWallet Password", "1.0", "KWallet Password Plugin", "KWallet Password Plugin", "C. Shaun Wagner , Charles Tullock , Jonathan Blount ", "http://kainaw.com/libpurple", plugin_load, NULL, NULL, NULL, NULL, NULL, plugin_actions, /* this tells libpurple the address of the function to call to get the list of plugin actions. */ NULL, NULL, NULL, NULL }; /* Initialize the plugin. Add a KApplication and open KWallet. */ static void init_plugin (PurplePlugin * plugin) { /* KWallet requries a functioning KApplication or it will segfault */ KAboutData aboutData("libpurple_plugin", I18N_NOOP("LibPurple KWallet Plugin"), "", "", KAboutData::License_GPL, ""); KCmdLineArgs::init( &aboutData ); app = new KApplication(false, false); wallet = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet()); } /* This has to be extern or the plugin will not be loadable */ extern "C" { PURPLE_INIT_PLUGIN (kwalletpassword_world, init_plugin, info) }