aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-09-29 23:02:01 -0700
committerWilmer van der Gaast <wilmer@gaast.net>2010-09-29 23:02:01 -0700
commit6ce2240e6dd88d86e90ffbfff078bc55b3f49477 (patch)
treedee2b748d31b21a5b91b26d2e734b079e319c455
parent858ea0166108e9cfab3cc9290fc976f041411cce (diff)
parent475206376035daf797c59e94c1e945c5b499e1a2 (diff)
Merging some fixes from pesco. Adds support for the SMP flavour used by Pidgin
(otr smpq).
-rw-r--r--doc/user-guide/commands.xml19
-rw-r--r--irc.c8
-rw-r--r--otr.c133
3 files changed, 112 insertions, 48 deletions
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index f2b8f5f8..47e752af 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -374,7 +374,7 @@
<description>
<para>
- Available subcommands: connect, disconnect, smp, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
+ Available subcommands: connect, disconnect, smp, smpq, trust, info, keygen, and forget. See <emphasis>help otr &lt;subcommand&gt;</emphasis> for more information.
</para>
</description>
@@ -422,6 +422,23 @@
</bitlbee-command>
+ <bitlbee-command name="smpq">
+ <syntax>otr smpq &lt;nick&gt; &lt;question&gt; &lt;answer&gt;</syntax>
+
+ <description>
+
+ <para>
+ Attempts to authenticate the given user's active fingerprint via the Socialist Millionaires' Protocol, Q&amp;A style.
+ </para>
+
+ <para>
+ When initiating SMP, this is an alternative to the 'otr smp' command. The shared secret is provided as the answer to a specific question. The question is transmitted with the initial SMP packet and used to prompt the other party. If the protocol succeeds (i.e. they give the correct answer), the fingerprint will be trusted.
+ </para>
+
+ </description>
+
+ </bitlbee-command>
+
<bitlbee-command name="trust">
<syntax>otr trust &lt;nick&gt; &lt;fp1&gt; &lt;fp2&gt; &lt;fp3&gt; &lt;fp4&gt; &lt;fp5&gt;</syntax>
diff --git a/irc.c b/irc.c
index ed705caa..bc44c6e3 100644
--- a/irc.c
+++ b/irc.c
@@ -221,6 +221,10 @@ void irc_free( irc_t * irc )
log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
+ if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
+ if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
+ log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
+
for( l = irc_plugins; l; l = l->next )
{
irc_plugin_t *p = l->data;
@@ -228,10 +232,6 @@ void irc_free( irc_t * irc )
p->irc_free( irc );
}
- if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
- if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
- log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
-
irc_connection_list = g_slist_remove( irc_connection_list, irc );
while( irc->queries != NULL )
diff --git a/otr.c b/otr.c
index a9da9850..693c0ea0 100644
--- a/otr.c
+++ b/otr.c
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2008 Wilmer van der Gaast and others *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
\********************************************************************/
/*
@@ -86,6 +86,7 @@ static void cmd_otr(irc_t *irc, char **args);
void cmd_otr_connect(irc_t *irc, char **args);
void cmd_otr_disconnect(irc_t *irc, char **args);
void cmd_otr_smp(irc_t *irc, char **args);
+void cmd_otr_smpq(irc_t *irc, char **args);
void cmd_otr_trust(irc_t *irc, char **args);
void cmd_otr_info(irc_t *irc, char **args);
void cmd_otr_keygen(irc_t *irc, char **args);
@@ -95,6 +96,7 @@ const command_t otr_commands[] = {
{ "connect", 1, &cmd_otr_connect, 0 },
{ "disconnect", 1, &cmd_otr_disconnect, 0 },
{ "smp", 2, &cmd_otr_smp, 0 },
+ { "smpq", 3, &cmd_otr_smpq, 0 },
{ "trust", 6, &cmd_otr_trust, 0 },
{ "info", 0, &cmd_otr_info, 0 },
{ "keygen", 1, &cmd_otr_keygen, 0 },
@@ -154,6 +156,10 @@ irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol);
/* handle SMP TLVs from a received message */
void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs);
+/* combined handler for the 'otr smp' and 'otr smpq' commands */
+void otr_initiate_smp(irc_t *irc, const char *nick, const char *question,
+ const char *secret);
+
/* update op/voice flag of given user according to encryption state and settings
returns 0 if neither op_buddies nor voice_buddies is set to "encrypted",
i.e. msgstate should be announced seperately */
@@ -731,49 +737,12 @@ void cmd_otr_connect(irc_t *irc, char **args)
void cmd_otr_smp(irc_t *irc, char **args)
{
- irc_user_t *u;
- ConnContext *ctx;
-
- u = irc_user_by_name(irc, args[1]);
- if(!u || !u->bu || !u->bu->ic) {
- irc_usermsg(irc, "%s: unknown user", args[1]);
- return;
- }
- if(!(u->bu->flags & BEE_USER_ONLINE)) {
- irc_usermsg(irc, "%s is offline", args[1]);
- return;
- }
-
- ctx = otrl_context_find(irc->otr->us, u->bu->handle,
- u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 1, NULL, NULL, NULL);
- if(!ctx) {
- /* huh? out of memory or what? */
- return;
- }
+ otr_initiate_smp(irc, args[1], NULL, args[2]); /* no question */
+}
- if(ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
- log_message(LOGLVL_INFO,
- "SMP already in phase %d, sending abort before reinitiating",
- ctx->smstate->nextExpected+1);
- otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
- otrl_sm_state_free(ctx->smstate);
- }
-
- /* warning: the following assumes that smstates are cleared whenever an SMP
- is completed or aborted! */
- if(ctx->smstate->secret == NULL) {
- irc_usermsg(irc, "smp: initiating with %s...", u->nick);
- otrl_message_initiate_smp(irc->otr->us, &otr_ops,
- u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
- /* smp is now in EXPECT2 */
- } else {
- /* if we're still in EXPECT1 but smstate is initialized, we must have
- received the SMP1, so let's issue a response */
- irc_usermsg(irc, "smp: responding to %s...", u->nick);
- otrl_message_respond_smp(irc->otr->us, &otr_ops,
- u->bu->ic, ctx, (unsigned char *)args[2], strlen(args[2]));
- /* smp is now in EXPECT3 */
- }
+void cmd_otr_smpq(irc_t *irc, char **args)
+{
+ otr_initiate_smp(irc, args[1], args[2], args[3]);
}
void cmd_otr_trust(irc_t *irc, char **args)
@@ -1097,10 +1066,29 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
ic->acc->user, ic->acc->prpl->name, 1, NULL, NULL, NULL);
if(!context) {
/* huh? out of memory or what? */
+ irc_usermsg(irc, "smp: failed to get otr context for %s", u->nick);
+ otrl_message_abort_smp(us, ops, u->bu->ic, context);
+ otrl_sm_state_free(context->smstate);
return;
}
nextMsg = context->smstate->nextExpected;
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
+ if (tlv) {
+ if (nextMsg != OTRL_SMP_EXPECT1) {
+ irc_usermsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick);
+ otrl_message_abort_smp(us, ops, u->bu->ic, context);
+ otrl_sm_state_free(context->smstate);
+ } else {
+ char *question = g_strndup((char *)tlv->data, tlv->len);
+ irc_usermsg(irc, "smp: initiated by %s with question: \"%s\"", u->nick,
+ question);
+ irc_usermsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",
+ u->nick);
+ g_free(question);
+ /* smp stays in EXPECT1 until user responds */
+ }
+ }
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
if (tlv) {
if (nextMsg != OTRL_SMP_EXPECT1) {
@@ -1173,6 +1161,65 @@ void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs)
}
}
+/* combined handler for the 'otr smp' and 'otr smpq' commands */
+void otr_initiate_smp(irc_t *irc, const char *nick, const char *question,
+ const char *secret)
+{
+ irc_user_t *u;
+ ConnContext *ctx;
+
+ u = irc_user_by_name(irc, nick);
+ if(!u || !u->bu || !u->bu->ic) {
+ irc_usermsg(irc, "%s: unknown user", nick);
+ return;
+ }
+ if(!(u->bu->flags & BEE_USER_ONLINE)) {
+ irc_usermsg(irc, "%s is offline", nick);
+ return;
+ }
+
+ ctx = otrl_context_find(irc->otr->us, u->bu->handle,
+ u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL);
+ if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+ irc_usermsg(irc, "smp: otr inactive with %s, try \x02otr connect"
+ " %s\x02", nick, nick);
+ return;
+ }
+
+ if(ctx->smstate->nextExpected != OTRL_SMP_EXPECT1) {
+ log_message(LOGLVL_INFO,
+ "SMP already in phase %d, sending abort before reinitiating",
+ ctx->smstate->nextExpected+1);
+ otrl_message_abort_smp(irc->otr->us, &otr_ops, u->bu->ic, ctx);
+ otrl_sm_state_free(ctx->smstate);
+ }
+
+ if(question) {
+ /* this was 'otr smpq', just initiate */
+ irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+ otrl_message_initiate_smp_q(irc->otr->us, &otr_ops, u->bu->ic, ctx,
+ question, (unsigned char *)secret, strlen(secret));
+ /* smp is now in EXPECT2 */
+ } else {
+ /* this was 'otr smp', initiate or reply */
+ /* warning: the following assumes that smstates are cleared whenever an SMP
+ is completed or aborted! */
+ if(ctx->smstate->secret == NULL) {
+ irc_usermsg(irc, "smp: initiating with %s...", u->nick);
+ otrl_message_initiate_smp(irc->otr->us, &otr_ops,
+ u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
+ /* smp is now in EXPECT2 */
+ } else {
+ /* if we're still in EXPECT1 but smstate is initialized, we must have
+ received the SMP1, so let's issue a response */
+ irc_usermsg(irc, "smp: responding to %s...", u->nick);
+ otrl_message_respond_smp(irc->otr->us, &otr_ops,
+ u->bu->ic, ctx, (unsigned char *)secret, strlen(secret));
+ /* smp is now in EXPECT3 */
+ }
+ }
+}
+
/* helper to assert that account and protocol names given to ops below always
match the im_connection passed through as opdata */
struct im_connection *check_imc(void *opdata, const char *accountname,