about summary refs log tree commit diff stats
path: root/src/otr
diff options
context:
space:
mode:
Diffstat (limited to 'src/otr')
-rw-r--r--src/otr/otr.c119
-rw-r--r--src/otr/otr.h12
-rw-r--r--src/otr/otrlib.h5
-rw-r--r--src/otr/otrlibv3.c90
-rw-r--r--src/otr/otrlibv4.c96
5 files changed, 316 insertions, 6 deletions
diff --git a/src/otr/otr.c b/src/otr/otr.c
index e80086af..043dc30f 100644
--- a/src/otr/otr.c
+++ b/src/otr/otr.c
@@ -23,6 +23,7 @@
 #include <libotr/proto.h>
 #include <libotr/privkey.h>
 #include <libotr/message.h>
+#include <libotr/sm.h>
 #include <glib.h>
 
 #include "otr/otr.h"
@@ -40,6 +41,25 @@ static OtrlUserState user_state;
 static OtrlMessageAppOps ops;
 static char *jid;
 static gboolean data_loaded;
+static GHashTable *smp_initiators;
+
+OtrlUserState
+otr_userstate(void)
+{
+    return user_state;
+}
+
+OtrlMessageAppOps *
+otr_messageops(void)
+{
+    return &ops;
+}
+
+GHashTable *
+otr_smpinitators(void)
+{
+    return smp_initiators;
+}
 
 // ops callbacks
 static OtrlPolicy
@@ -134,10 +154,18 @@ _otr_init(void)
     ops.gone_secure = cb_gone_secure;
 
     otrlib_init_ops(&ops);
+    otrlib_init_timer();
+    smp_initiators = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
     data_loaded = FALSE;
 }
 
+void
+_otr_poll(void)
+{
+    otrlib_poll();
+}
+
 static void
 _otr_on_connect(ProfAccount *account)
 {
@@ -337,9 +365,14 @@ _otr_is_trusted(const char * const recipient)
         return TRUE;
     }
 
-    if (context->active_fingerprint &&
-                g_strcmp0(context->active_fingerprint->trust, "trusted") == 0) {
-        return TRUE;
+    if (context->active_fingerprint) {
+        if (context->active_fingerprint->trust == NULL) {
+            return FALSE;
+        } else if (context->active_fingerprint->trust[0] == '\0') {
+            return FALSE;
+        } else {
+            return TRUE;
+        }
     }
 
     return FALSE;
@@ -359,7 +392,10 @@ _otr_trust(const char * const recipient)
     }
 
     if (context->active_fingerprint) {
-        context->active_fingerprint->trust = "trusted";
+        if (context->active_fingerprint->trust != NULL) {
+            free(context->active_fingerprint->trust);
+        }
+        context->active_fingerprint->trust = strdup("trusted");
         cb_write_fingerprints(NULL);
     }
 
@@ -380,6 +416,9 @@ _otr_untrust(const char * const recipient)
     }
 
     if (context->active_fingerprint) {
+        if (context->active_fingerprint->trust != NULL) {
+            free(context->active_fingerprint->trust);
+        }
         context->active_fingerprint->trust = NULL;
         cb_write_fingerprints(NULL);
     }
@@ -388,6 +427,64 @@ _otr_untrust(const char * const recipient)
 }
 
 static void
+_otr_smp_secret(const char * const recipient, const char *secret)
+{
+    ConnContext *context = otrlib_context_find(user_state, recipient, jid);
+
+    if (context == NULL) {
+        return;
+    }
+
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+        return;
+    }
+
+    // if recipient initiated SMP, send response, else initialise
+    if (g_hash_table_contains(smp_initiators, recipient)) {
+        otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret));
+        ui_otr_authenticating(recipient);
+        g_hash_table_remove(smp_initiators, context->username);
+    } else {
+        otrl_message_initiate_smp(user_state, &ops, NULL, context, (const unsigned char*)secret, strlen(secret));
+        ui_otr_authetication_waiting(recipient);
+    }
+}
+
+static void
+_otr_smp_question(const char * const recipient, const char *question, const char *answer)
+{
+    ConnContext *context = otrlib_context_find(user_state, recipient, jid);
+
+    if (context == NULL) {
+        return;
+    }
+
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+        return;
+    }
+
+    otrl_message_initiate_smp_q(user_state, &ops, NULL, context, question, (const unsigned char*)answer, strlen(answer));
+    ui_otr_authetication_waiting(recipient);
+}
+
+static void
+_otr_smp_answer(const char * const recipient, const char *answer)
+{
+    ConnContext *context = otrlib_context_find(user_state, recipient, jid);
+
+    if (context == NULL) {
+        return;
+    }
+
+    if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+        return;
+    }
+
+    // if recipient initiated SMP, send response, else initialise
+    otrl_message_respond_smp(user_state, &ops, NULL, context, (const unsigned char*)answer, strlen(answer));
+}
+
+static void
 _otr_end_session(const char * const recipient)
 {
     otrlib_end_session(user_state, recipient, jid, &ops);
@@ -424,7 +521,7 @@ _otr_encrypt_message(const char * const to, const char * const message)
     char *newmessage = NULL;
     gcry_error_t err = otrlib_encrypt_message(user_state, &ops, jid, to, message, &newmessage);
 
-    if (!err == GPG_ERR_NO_ERROR) {
+    if (err != 0) {
         return NULL;
     } else {
         return newmessage;
@@ -441,15 +538,21 @@ _otr_decrypt_message(const char * const from, const char * const message, gboole
 
     // internal libotr message
     if (result == 1) {
+        ConnContext *context = otrlib_context_find(user_state, from, jid);
+
+        // common tlv handling
         OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
         if (tlv) {
-            ConnContext *context = otrlib_context_find(user_state, from, jid);
 
             if (context != NULL) {
                 otrl_context_force_plaintext(context);
                 ui_gone_insecure(from);
             }
         }
+
+        // library version specific tlv handling
+        otrlib_handle_tlvs(user_state, &ops, context, tlvs, smp_initiators);
+
         return NULL;
 
     // message was decrypted, return to user
@@ -476,6 +579,7 @@ otr_init_module(void)
     otr_init = _otr_init;
     otr_libotr_version = _otr_libotr_version;
     otr_start_query = _otr_start_query;
+    otr_poll = _otr_poll;
     otr_on_connect = _otr_on_connect;
     otr_keygen = _otr_keygen;
     otr_key_loaded = _otr_key_loaded;
@@ -489,4 +593,7 @@ otr_init_module(void)
     otr_encrypt_message = _otr_encrypt_message;
     otr_decrypt_message = _otr_decrypt_message;
     otr_free_message = _otr_free_message;
+    otr_smp_secret = _otr_smp_secret;
+    otr_smp_question = _otr_smp_question;
+    otr_smp_answer = _otr_smp_answer;
 }
diff --git a/src/otr/otr.h b/src/otr/otr.h
index 5239c033..87b34b45 100644
--- a/src/otr/otr.h
+++ b/src/otr/otr.h
@@ -23,13 +23,21 @@
 #ifndef OTR_H
 #define OTR_H
 
+#include <libotr/proto.h>
+#include <libotr/message.h>
+
 #include "config/accounts.h"
 
 void otr_init_module(void);
 
+OtrlUserState otr_userstate(void);
+OtrlMessageAppOps* otr_messageops(void);
+GHashTable* otr_smpinitators(void);
+
 void (*otr_init)(void);
 char* (*otr_libotr_version)(void);
 char* (*otr_start_query)(void);
+void (*otr_poll)(void);
 void (*otr_on_connect)(ProfAccount *account);
 void (*otr_keygen)(ProfAccount *account);
 
@@ -40,6 +48,10 @@ gboolean (*otr_is_trusted)(const char * const recipient);
 void (*otr_trust)(const char * const recipient);
 void (*otr_untrust)(const char * const recipient);
 
+void (*otr_smp_secret)(const char * const recipient, const char *secret);
+void (*otr_smp_question)(const char * const recipient, const char *question, const char *answer);
+void (*otr_smp_answer)(const char * const recipient, const char *answer);
+
 void (*otr_end_session)(const char * const recipient);
 
 char * (*otr_get_my_fingerprint)(void);
diff --git a/src/otr/otrlib.h b/src/otr/otrlib.h
index 0986c59b..c0ca518f 100644
--- a/src/otr/otrlib.h
+++ b/src/otr/otrlib.h
@@ -29,6 +29,9 @@ char* otrlib_start_query(void);
 
 void otrlib_init_ops(OtrlMessageAppOps *ops);
 
+void otrlib_init_timer(void);
+void otrlib_poll(void);
+
 ConnContext * otrlib_context_find(OtrlUserState user_state, const char * const recipient, char *jid);
 
 void otrlib_end_session(OtrlUserState user_state, const char * const recipient, char *jid, OtrlMessageAppOps *ops);
@@ -39,4 +42,6 @@ gcry_error_t otrlib_encrypt_message(OtrlUserState user_state, OtrlMessageAppOps
 int otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *jid, const char * const from,
     const char * const message, char **decrypted, OtrlTLV **tlvs);
 
+void otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators);
+
 #endif
diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c
index d1495c9a..92ca3602 100644
--- a/src/otr/otrlibv3.c
+++ b/src/otr/otrlibv3.c
@@ -24,6 +24,8 @@
 #include <libotr/message.h>
 
 #include "ui/ui.h"
+#include "otr/otr.h"
+#include "otr/otrlib.h"
 
 OtrlPolicy
 otrlib_policy(void)
@@ -31,6 +33,16 @@ otrlib_policy(void)
     return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2 ;
 }
 
+void
+otrlib_init_timer(void)
+{
+}
+
+void
+otrlib_poll(void)
+{
+}
+
 char *
 otrlib_start_query(void)
 {
@@ -106,3 +118,81 @@ otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *j
         NULL,
         NULL);
 }
+
+void
+otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators)
+{
+    NextExpectedSMP nextMsg = context->smstate->nextExpected;
+    OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT1) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            ui_smp_recipient_initiated(context->username);
+            g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username));
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT1) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            char *question = (char *)tlv->data;
+            char *eoq = memchr(question, '\0', tlv->len);
+            if (eoq) {
+                ui_smp_recipient_initiated_q(context->username, question);
+            }
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT2) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            context->smstate->nextExpected = OTRL_SMP_EXPECT4;
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT3) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+            if (context->smstate->received_question == 0) {
+                if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) {
+                    ui_smp_successful(context->username);
+                    ui_trust(context->username);
+                    otr_trust(context->username);
+                } else {
+                    ui_smp_unsuccessful_sender(context->username);
+                    ui_untrust(context->username);
+                    otr_untrust(context->username);
+                }
+            }
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
+    if (tlv) {
+        if (nextMsg != OTRL_SMP_EXPECT4) {
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+        } else {
+            context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+            if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) {
+                ui_smp_successful(context->username);
+                ui_trust(context->username);
+                otr_trust(context->username);
+            } else {
+                ui_smp_unsuccessful_receiver(context->username);
+                ui_untrust(context->username);
+                otr_untrust(context->username);
+            }
+        }
+    }
+    tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
+    if (tlv) {
+        context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+        ui_smp_aborted(context->username);
+        ui_untrust(context->username);
+        otr_untrust(context->username);
+    }
+}
diff --git a/src/otr/otrlibv4.c b/src/otr/otrlibv4.c
index c55d2972..d9e7ce01 100644
--- a/src/otr/otrlibv4.c
+++ b/src/otr/otrlibv4.c
@@ -25,6 +25,12 @@
 #include <libotr/message.h>
 
 #include "ui/ui.h"
+#include "log.h"
+#include "otr/otr.h"
+#include "otr/otrlib.h"
+
+static GTimer *timer;
+static unsigned int current_interval;
 
 OtrlPolicy
 otrlib_policy(void)
@@ -32,6 +38,27 @@ otrlib_policy(void)
     return OTRL_POLICY_ALLOW_V1 | OTRL_POLICY_ALLOW_V2;
 }
 
+void
+otrlib_init_timer(void)
+{
+    OtrlUserState user_state = otr_userstate();
+    timer = g_timer_new();
+    current_interval = otrl_message_poll_get_default_interval(user_state);
+}
+
+void
+otrlib_poll(void)
+{
+    gdouble elapsed = g_timer_elapsed(timer, NULL);
+
+    if (current_interval != 0 && elapsed > current_interval) {
+        OtrlUserState user_state = otr_userstate();
+        OtrlMessageAppOps *ops = otr_messageops();
+        otrl_message_poll(user_state, ops, NULL);
+        g_timer_start(timer);
+    }
+}
+
 char *
 otrlib_start_query(void)
 {
@@ -64,6 +91,12 @@ cb_otr_error_message_free(void *opdata, const char *err_msg)
 }
 
 static void
+cb_timer_control(void *opdata, unsigned int interval)
+{
+    current_interval = interval; 
+}
+
+static void
 cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
     ConnContext *context, const char *message,
     gcry_error_t err)
@@ -77,12 +110,70 @@ cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
     }
 }
 
+static void
+cb_handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
+    ConnContext *context, unsigned short progress_percent,
+    char *question)
+{
+    NextExpectedSMP nextMsg = context->smstate->nextExpected;
+    OtrlUserState user_state = otr_userstate();
+    OtrlMessageAppOps *ops = otr_messageops();
+    GHashTable *smp_initiators = otr_smpinitators();
+
+    switch(smp_event)
+    {
+        case OTRL_SMPEVENT_ASK_FOR_SECRET:
+            ui_smp_recipient_initiated(context->username);
+            g_hash_table_insert(smp_initiators, strdup(context->username), strdup(context->username));
+            break;
+
+        case OTRL_SMPEVENT_SUCCESS:
+            ui_smp_successful(context->username);
+            ui_trust(context->username);
+            break;
+            
+        case OTRL_SMPEVENT_FAILURE:
+            if (nextMsg == OTRL_SMP_EXPECT3) {
+                ui_smp_unsuccessful_sender(context->username);
+                ui_untrust(context->username);
+            } else if (nextMsg == OTRL_SMP_EXPECT4) {
+                ui_smp_unsuccessful_receiver(context->username);
+                ui_untrust(context->username);
+            }
+            break;
+
+        case OTRL_SMPEVENT_ERROR:
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+            break;
+
+        case OTRL_SMPEVENT_CHEATED:
+            otrl_message_abort_smp(user_state, ops, NULL, context);
+            break;
+
+        case OTRL_SMPEVENT_ABORT:
+            ui_smp_aborted(context->username);
+            ui_untrust(context->username);
+            break;
+
+        case OTRL_SMPEVENT_ASK_FOR_ANSWER:
+            break;
+
+        case OTRL_SMPEVENT_IN_PROGRESS:
+            break;
+
+        default:
+            break;
+    }
+}
+
 void
 otrlib_init_ops(OtrlMessageAppOps *ops)
 {
     ops->otr_error_message = cb_otr_error_message;
     ops->otr_error_message_free = cb_otr_error_message_free;
     ops->handle_msg_event = cb_handle_msg_event;
+    ops->handle_smp_event = cb_handle_smp_event;
+    ops->timer_control = cb_timer_control;
 }
 
 ConnContext *
@@ -145,3 +236,8 @@ otrlib_decrypt_message(OtrlUserState user_state, OtrlMessageAppOps *ops, char *j
         NULL,
         NULL);
 }
+
+void
+otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext *context, OtrlTLV *tlvs, GHashTable *smp_initiators)
+{
+}