diff options
Diffstat (limited to 'otr.c')
-rw-r--r-- | otr.c | 133 |
1 files changed, 90 insertions, 43 deletions
@@ -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, |