Initial PGP support (decrypt)
This patch initialize the PGP (GPG) sub-system, and adds a few PGP-related
options to the configuration file. Encrypted messages can be processed.
Presence is signed when the status message is non-empty.
--- a/mcabber/mcabberrc.example Sun Nov 26 10:30:52 2006 +0100
+++ b/mcabber/mcabberrc.example Sun Nov 26 10:42:25 2006 +0100
@@ -38,6 +38,17 @@
#set ssl_capath =
#set ssl_ciphers =
+# PGP support
+# Set pgp to 1 to enable OpenPGP.
+# To sign outgoing messages, select your private key id with
+# the pgp_private_key option. You cannot change these options once
+# mcabber is running.
+#set pgp = 0
+#set pgp_private_key = "B0B92210"
+#
+# You can set your PGP passhrase here, although it's NOT advised.
+#set pgp_passphrase = "PGPpassword"
+
# Conference nickname
# This nickname is used when joining a room, when no nick is explicitly
# specified by the user. Note that when the nickname option is not set,
--- a/mcabber/src/jabglue.c Sun Nov 26 10:30:52 2006 +0100
+++ b/mcabber/src/jabglue.c Sun Nov 26 10:42:25 2006 +0100
@@ -32,6 +32,7 @@
#include "hbuf.h"
#include "histolog.h"
#include "commands.h"
+#include "pgp.h"
#define JABBERPORT 5222
#define JABBERSSLPORT 5223
@@ -429,7 +430,20 @@
// (But we want to update internal status even when disconnected,
// in order to avoid some problems during network failures)
if (online) {
- x = presnew(st, recipient, (st != invisible ? msg : NULL));
+ const char *s_msg = (st != invisible ? msg : NULL);
+ x = presnew(st, recipient, s_msg);
+#ifdef HAVE_GPGME
+ if (s_msg && *s_msg && gpg_enabled()) {
+ char *signature = gpg_sign(s_msg);
+ if (signature) {
+ xmlnode y;
+ y = xmlnode_insert_tag(x, "x");
+ xmlnode_put_attrib(y, "xmlns", NS_SIGNED);
+ xmlnode_insert_cdata(y, signature, (unsigned) -1);
+ g_free(signature);
+ }
+ }
+#endif
jab_send(jc, x);
xmlnode_free(x);
}
@@ -1393,12 +1407,21 @@
{
char *jid;
const char *rname, *s;
+ char *decrypted = NULL;
jid = jidtodisp(from);
rname = strchr(from, JID_RESOURCE_SEPARATOR);
if (rname) rname++;
+#ifdef HAVE_GPGME
+ if (enc && gpg_enabled()) {
+ decrypted = gpg_decrypt(enc);
+ if (decrypted)
+ body = decrypted;
+ }
+#endif
+
// Check for unexpected groupchat messages
// If we receive a groupchat message from a room we're not a member of,
// this is probably a server issue and the best we can do is to send
@@ -1426,6 +1449,7 @@
}
g_free(jid);
+ g_free(decrypted);
buddylist_build();
scr_DrawRoster();
@@ -1444,6 +1468,7 @@
scr_LogPrint(LPRINT_LOGNORM, "Blocked a message from <%s>", jid);
}
g_free(jid);
+ g_free(decrypted);
}
static const char *defaulterrormsg(int code)
--- a/mcabber/src/main.c Sun Nov 26 10:30:52 2006 +0100
+++ b/mcabber/src/main.c Sun Nov 26 10:42:25 2006 +0100
@@ -40,6 +40,7 @@
#include "histolog.h"
#include "hooks.h"
#include "utils.h"
+#include "pgp.h"
#ifdef ENABLE_HGCSET
# include "hgcset.h"
@@ -186,7 +187,10 @@
}
}
-static void ask_password(void)
+// ask_password(what)
+// Return the password, or NULL.
+// The string must be freed after use.
+static char *ask_password(const char *what)
{
char *password, *p;
size_t passsize = 128;
@@ -195,15 +199,15 @@
password = g_new0(char, passsize);
/* Turn echoing off and fail if we can't. */
- if (tcgetattr(fileno(stdin), &orig) != 0) return;
+ if (tcgetattr(fileno(stdin), &orig) != 0) return NULL;
backup_termios = &orig;
new = orig;
new.c_lflag &= ~ECHO;
- if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) return;
+ if (tcsetattr(fileno(stdin), TCSAFLUSH, &new) != 0) return NULL;
/* Read the password. */
- printf("Please enter password: ");
+ printf("Please enter %s: ", what);
fgets(password, passsize, stdin);
/* Restore terminal. */
@@ -216,9 +220,7 @@
for ( ; p > (char*)password ; p--)
if (*p == '\n' || *p == '\r') *p = 0;
- settings_set(SETTINGS_TYPE_OPTION, "password", password);
- g_free(password);
- return;
+ return password;
}
static void credits(void)
@@ -230,6 +232,59 @@
g_free(v);
}
+void main_init_pgp(void)
+{
+#ifdef HAVE_GPGME
+ const char *pk, *pp;
+ char *typed_passwd = NULL;
+ char *p;
+ bool pgp_invalid = FALSE;
+ bool pgp_agent;
+
+ p = getenv("GPG_AGENT_INFO");
+ pgp_agent = (p && strchr(p, ':'));
+
+ pk = settings_opt_get("pgp_private_key");
+ pp = settings_opt_get("pgp_passphrase");
+ if (!pk) {
+ scr_LogPrint(LPRINT_LOGNORM, "WARNING: unkown PGP private key");
+ pgp_invalid = TRUE;
+ } else if (!(pp || pgp_agent)) {
+ // Request PGP passphrase
+ pp = typed_passwd = ask_password("PGP passphrase");
+ }
+ gpg_init(pk, pp);
+ // Erase password from the settings array
+ if (pp) {
+ memset((char*)pp, 0, strlen(pp));
+ if (typed_passwd)
+ g_free(typed_passwd);
+ else
+ settings_set(SETTINGS_TYPE_OPTION, "pgp_passphrase", NULL);
+ }
+ if (!pgp_agent && pk && pp && gpg_test_passphrase()) {
+ // Let's check the pasphrase
+ int i;
+ for (i = 0; i < 2; i++) {
+ typed_passwd = ask_password("PGP passphrase"); // Ask again...
+ if (typed_passwd) {
+ gpg_set_passphrase(typed_passwd);
+ memset(typed_passwd, 0, strlen(typed_passwd));
+ g_free(typed_passwd);
+ }
+ if (!gpg_test_passphrase())
+ break; // Ok
+ }
+ if (i == 2)
+ pgp_invalid = TRUE;
+ }
+ if (pgp_invalid)
+ scr_LogPrint(LPRINT_LOGNORM, "WARNING: PGP key/pass invalid");
+#else /* not HAVE_GPGME */
+ scr_LogPrint(LPRINT_LOGNORM, "WARNING: not compiled with PGP support");
+#endif /* HAVE_GPGME */
+}
+
int main(int argc, char **argv)
{
char *configFile = NULL;
@@ -291,9 +346,16 @@
p = settings_opt_get("username");
if (p)
printf("Username: %s\n", p);
- ask_password();
+ settings_set(SETTINGS_TYPE_OPTION, "password",
+ ask_password("Jabber password"));
}
+ /* Initialize PGP system
+ We do it before ncurses initialization because we may need to request
+ a passphrase. */
+ if (settings_opt_get_int("pgp"))
+ main_init_pgp();
+
/* Initialize N-Curses */
scr_LogPrint(LPRINT_DEBUG, "Initializing N-Curses...");
scr_InitCurses();
@@ -346,6 +408,9 @@
}
jb_disconnect();
+#ifdef HAVE_GPGME
+ gpg_terminate();
+#endif
scr_TerminateCurses();
printf("\n\nThanks for using mcabber!\n");