changeset 1042:8a395c2cafc4

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.
author Mikael Berthe <mikael@lilotux.net>
date Sun, 26 Nov 2006 10:42:25 +0100
parents d4b97a2423eb
children ebbde723614b
files mcabber/mcabberrc.example mcabber/src/jabglue.c mcabber/src/main.c
diffstat 3 files changed, 110 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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");