Changes in otr.c [51f937e:0e788f5]
Legend:
- Unmodified
- Added
- Removed
-
otr.c
r51f937e r0e788f5 8 8 OTR support (cf. http://www.cypherpunks.ca/otr/) 9 9 10 (c) 2008-2011 ,2013Sven Moritz Hallberg <pesco@khjk.org>11 funded by stonedcoder.org10 (c) 2008-2011 Sven Moritz Hallberg <pesco@khjk.org> 11 (c) 2008 funded by stonedcoder.org 12 12 13 13 files used to store OTR data: 14 14 <configdir>/<nick>.otr_keys 15 15 <configdir>/<nick>.otr_fprints 16 <configdir>/<nick>.otr_instags <- don't copy this one between hosts17 16 18 17 top-level todos: (search for TODO for more ;-)) … … 20 19 per-account policy settings 21 20 per-user policy settings 22 add a way to select recipient instance23 21 */ 24 22 … … 62 60 const char *recipient, const char *message); 63 61 62 int op_display_otr_message(void *opdata, const char *accountname, const char *protocol, 63 const char *username, const char *msg); 64 64 65 void op_new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, 65 66 const char *protocol, const char *username, unsigned char fingerprint[20]); … … 79 80 const char *op_account_name(void *opdata, const char *account, const char *protocol); 80 81 81 void op_create_instag(void *opdata, const char *account, const char *protocol);82 83 void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ,84 char **dst, const char *src);85 void op_convert_free(void *opdata, ConnContext *ctx, char *msg);86 87 void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,88 unsigned short percent, char *question);89 90 void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx,91 const char *message, gcry_error_t err);92 93 const char *op_otr_error_message(void *opdata, ConnContext *ctx,94 OtrlErrorCode err_code);95 82 96 83 /** otr sub-command handlers: **/ … … 154 141 void yes_forget_key(void *data); 155 142 156 /* timeout handler that calls otrl_message_poll */157 gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond);158 159 143 /* helper to make sure accountname and protocol match the incoming "opdata" */ 160 144 struct im_connection *check_imc(void *opdata, const char *accountname, … … 172 156 irc_user_t *peeruser(irc_t *irc, const char *handle, const char *protocol); 173 157 174 /* show an otr-related message to the user */ 175 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...); 176 177 /* write an otr-related message to the system log */ 178 void log_otr_message(void *opdata, const char *fmt, ...); 158 /* handle SMP TLVs from a received message */ 159 void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs); 179 160 180 161 /* combined handler for the 'otr smp' and 'otr smpq' commands */ … … 227 208 otr_ops.is_logged_in = &op_is_logged_in; 228 209 otr_ops.inject_message = &op_inject_message; 210 otr_ops.notify = NULL; 211 otr_ops.display_otr_message = &op_display_otr_message; 229 212 otr_ops.update_context_list = NULL; 213 otr_ops.protocol_name = NULL; 214 otr_ops.protocol_name_free = NULL; 230 215 otr_ops.new_fingerprint = &op_new_fingerprint; 231 216 otr_ops.write_fingerprints = &op_write_fingerprints; … … 233 218 otr_ops.gone_insecure = &op_gone_insecure; 234 219 otr_ops.still_secure = &op_still_secure; 220 otr_ops.log_message = &op_log_message; 235 221 otr_ops.max_message_size = &op_max_message_size; 236 222 otr_ops.account_name = &op_account_name; 237 223 otr_ops.account_name_free = NULL; 238 239 /* stuff added with libotr 4.0.0 */ 240 otr_ops.received_symkey = NULL; /* we don't use the extra key */ 241 otr_ops.otr_error_message = &op_otr_error_message; 242 otr_ops.otr_error_message_free = NULL; 243 otr_ops.resent_msg_prefix = NULL; /* default: [resent] */ 244 otr_ops.resent_msg_prefix_free = NULL; 245 otr_ops.handle_smp_event = &op_handle_smp_event; 246 otr_ops.handle_msg_event = &op_handle_msg_event; 247 otr_ops.create_instag = &op_create_instag; 248 otr_ops.convert_msg = &op_convert_msg; 249 otr_ops.convert_free = &op_convert_free; 250 otr_ops.timer_control = NULL; /* we just poll */ 251 224 252 225 root_command_add( "otr", 1, cmd_otr, 0 ); 253 226 register_irc_plugin( &otr_plugin ); … … 273 246 s = set_add( &irc->b->set, "otr_does_html", "true", set_eval_bool, irc ); 274 247 275 /* regularly call otrl_message_poll */276 gint definterval = otrl_message_poll_get_default_interval(irc->otr->us);277 irc->otr->timer = b_timeout_add(definterval, ev_message_poll, irc->otr);278 279 248 return TRUE; 280 249 } … … 283 252 { 284 253 otr_t *otr = irc->otr; 285 b_event_remove(otr->timer);286 254 otrl_userstate_free(otr->us); 287 255 if(otr->keygen) { … … 318 286 g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->user->nick); 319 287 e = otrl_privkey_read_fingerprints(irc->otr->us, s, NULL, NULL); 320 if(e && e!=enoent) {321 irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e));322 }323 g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir, irc->user->nick);324 e = otrl_instag_read(irc->otr->us, s);325 288 if(e && e!=enoent) { 326 289 irc_rootmsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); … … 423 386 ignore_msg = otrl_message_receiving(irc->otr->us, &otr_ops, ic, 424 387 ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg, 425 &tlvs, NULL, NULL, NULL); 426 388 &tlvs, NULL, NULL); 389 390 otr_handle_smp(ic, iu->bu->handle, tlvs); 391 427 392 if(ignore_msg) { 428 393 /* this was an internal OTR protocol message */ … … 432 397 return msg; 433 398 } else { 399 /* OTR has processed this message */ 400 ConnContext *context = otrl_context_find(irc->otr->us, iu->bu->handle, 401 ic->acc->user, ic->acc->prpl->name, 0, NULL, NULL, NULL); 402 434 403 /* we're done with the original msg, which will be caller-freed. */ 435 return newmsg; 404 /* NB: must not change the newmsg pointer, since we free it. */ 405 msg = newmsg; 406 407 if(context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { 408 /* HTML decoding */ 409 /* perform any necessary stripping that the top level would miss */ 410 if(set_getbool(&ic->bee->set, "otr_does_html") && 411 !(ic->flags & OPT_DOES_HTML) && 412 set_getbool(&ic->bee->set, "strip_html")) { 413 strip_html(msg); 414 } 415 416 /* coloring */ 417 if(set_getbool(&ic->bee->set, "otr_color_encrypted")) { 418 int color; /* color according to f'print trust */ 419 char *pre="", *sep=""; /* optional parts */ 420 const char *trust = context->active_fingerprint->trust; 421 422 if(trust && trust[0] != '\0') 423 color=3; /* green */ 424 else 425 color=5; /* red */ 426 427 /* in a query window, keep "/me " uncolored at the beginning */ 428 if(g_strncasecmp(msg, "/me ", 4) == 0 429 && irc_user_msgdest(iu) == irc->user->nick) { 430 msg += 4; /* skip */ 431 pre = "/me "; 432 } 433 434 /* comma in first place could mess with the color code */ 435 if(msg[0] == ',') { 436 /* insert a space between color spec and message */ 437 sep = " "; 438 } 439 440 msg = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre, 441 color, sep, msg); 442 } 443 } 444 445 if(msg == newmsg) { 446 msg = g_strdup(newmsg); 447 } 448 otrl_message_free(newmsg); 449 return msg; 436 450 } 437 451 } … … 445 459 irc_t *irc = iu->irc; 446 460 struct im_connection *ic = iu->bu->ic; 447 otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX?448 461 449 462 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ … … 452 465 } 453 466 467 ctx = otrl_context_find(irc->otr->us, 468 iu->bu->handle, ic->acc->user, ic->acc->prpl->name, 469 1, NULL, NULL, NULL); 470 471 /* HTML encoding */ 472 /* consider OTR plaintext to be HTML if otr_does_html is set */ 473 if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED && 474 set_getbool(&ic->bee->set, "otr_does_html") && 475 (g_strncasecmp(msg, "<html>", 6) != 0)) { 476 emsg = escape_html(msg); 477 } 478 454 479 st = otrl_message_sending(irc->otr->us, &otr_ops, ic, 455 ic->acc->user, ic->acc->prpl->name, iu->bu->handle, instag, 456 emsg, NULL, &otrmsg, OTRL_FRAGMENT_SEND_ALL, &ctx, NULL, NULL); 457 /* in libotr 4.0.0 with OTRL_FRAGMENT_SEND_ALL, otrmsg must be passed 458 * but the value it gets carries no meaning. it can be set even though 459 * the message has been injected. */ 460 480 ic->acc->user, ic->acc->prpl->name, iu->bu->handle, 481 emsg, NULL, &otrmsg, NULL, NULL); 461 482 if(emsg != msg) { 462 483 g_free(emsg); /* we're done with this one */ 463 484 } 464 485 if(st) { 465 /* TODO: Error reporting? */ 466 } 486 return NULL; 487 } 488 489 if(otrmsg) { 490 if(!ctx) { 491 otrl_message_free(otrmsg); 492 return NULL; 493 } 494 st = otrl_message_fragment_and_send(&otr_ops, ic, ctx, 495 otrmsg, OTRL_FRAGMENT_SEND_ALL, NULL); 496 otrl_message_free(otrmsg); 497 } else { 498 /* note: otrl_message_sending handles policy, so that if REQUIRE_ENCRYPTION is set, 499 this case does not occur */ 500 return msg; 501 } 502 503 /* TODO: Error reporting should be done here now (if st!=0), probably. */ 467 504 468 505 return NULL; … … 583 620 } 584 621 622 int op_display_otr_message(void *opdata, const char *accountname, 623 const char *protocol, const char *username, const char *message) 624 { 625 struct im_connection *ic = check_imc(opdata, accountname, protocol); 626 char *msg = g_strdup(message); 627 irc_t *irc = ic->bee->ui_data; 628 irc_user_t *u = peeruser(irc, username, protocol); 629 630 strip_html(msg); 631 if(u) { 632 /* display as a notice from this particular user */ 633 irc_usernotice(u, "%s", msg); 634 } else { 635 irc_rootmsg(irc, "[otr] %s", msg); 636 } 637 638 g_free(msg); 639 return 0; 640 } 641 585 642 void op_new_fingerprint(void *opdata, OtrlUserState us, 586 643 const char *accountname, const char *protocol, … … 634 691 void op_gone_insecure(void *opdata, ConnContext *context) 635 692 { 636 /* XXX on 'otr disconnect', this gets called for every instance and we637 * get the message multiple times... */638 639 693 struct im_connection *ic = 640 694 check_imc(opdata, context->accountname, context->protocol); … … 676 730 } 677 731 732 void op_log_message(void *opdata, const char *message) 733 { 734 char *msg = g_strdup(message); 735 736 strip_html(msg); 737 log_message(LOGLVL_INFO, "otr: %s", msg); 738 g_free(msg); 739 } 740 678 741 int op_max_message_size(void *opdata, ConnContext *context) 679 742 { 680 743 struct im_connection *ic = 681 744 check_imc(opdata, context->accountname, context->protocol); 682 745 683 746 return ic->acc->prpl->mms; 684 747 } … … 691 754 return peernick(irc, account, protocol); 692 755 } 693 694 void op_create_instag(void *opdata, const char *account, const char *protocol)695 {696 struct im_connection *ic =697 check_imc(opdata, account, protocol);698 irc_t *irc = ic->bee->ui_data;699 gcry_error_t e;700 char s[512];701 702 g_snprintf(s, 511, "%s%s.otr_instags", global.conf->configdir,703 irc->user->nick);704 e = otrl_instag_generate(irc->otr->us, s, account, protocol);705 if(e) {706 irc_rootmsg(irc, "otr: %s/%s: otrl_instag_generate failed: %s",707 account, protocol, gcry_strerror(e));708 }709 }710 711 void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ,712 char **dst, const char *src)713 {714 struct im_connection *ic =715 check_imc(opdata, ctx->accountname, ctx->protocol);716 irc_t *irc = ic->bee->ui_data;717 irc_user_t *iu = peeruser(irc, ctx->username, ctx->protocol);718 719 if(typ == OTRL_CONVERT_RECEIVING) {720 char *msg = g_strdup(src);721 722 /* HTML decoding */723 if(set_getbool(&ic->bee->set, "otr_does_html") &&724 !(ic->flags & OPT_DOES_HTML) &&725 set_getbool(&ic->bee->set, "strip_html")) {726 strip_html(msg);727 *dst = msg;728 }729 730 /* coloring */731 if(set_getbool(&ic->bee->set, "otr_color_encrypted")) {732 int color; /* color according to f'print trust */733 char *pre="", *sep=""; /* optional parts */734 const char *trust = ctx->active_fingerprint->trust;735 736 if(trust && trust[0] != '\0')737 color=3; /* green */738 else739 color=5; /* red */740 741 /* in a query window, keep "/me " uncolored at the beginning */742 if(g_strncasecmp(msg, "/me ", 4) == 0743 && irc_user_msgdest(iu) == irc->user->nick) {744 msg += 4; /* skip */745 pre = "/me ";746 }747 748 /* comma in first place could mess with the color code */749 if(msg[0] == ',') {750 /* insert a space between color spec and message */751 sep = " ";752 }753 754 *dst = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre,755 color, sep, msg);756 g_free(msg);757 }758 } else {759 /* HTML encoding */760 /* consider OTR plaintext to be HTML if otr_does_html is set */761 if(ctx && ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED &&762 set_getbool(&ic->bee->set, "otr_does_html") &&763 (g_strncasecmp(src, "<html>", 6) != 0)) {764 *dst = escape_html(src);765 }766 }767 }768 769 void op_convert_free(void *opdata, ConnContext *ctx, char *msg)770 {771 g_free(msg);772 }773 774 /* Socialist Millionaires' Protocol */775 void op_handle_smp_event(void *opdata, OtrlSMPEvent ev, ConnContext *ctx,776 unsigned short percent, char *question)777 {778 struct im_connection *ic =779 check_imc(opdata, ctx->accountname, ctx->protocol);780 irc_t *irc = ic->bee->ui_data;781 OtrlUserState us = irc->otr->us;782 irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol);783 784 if(!u) return;785 786 switch(ev) {787 case OTRL_SMPEVENT_ASK_FOR_SECRET:788 irc_rootmsg(irc, "smp: initiated by %s"789 " - respond with \x02otr smp %s <secret>\x02",790 u->nick, u->nick);791 break;792 case OTRL_SMPEVENT_ASK_FOR_ANSWER:793 irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick,794 question);795 irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02",796 u->nick);797 break;798 case OTRL_SMPEVENT_CHEATED:799 irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting",800 u->nick);801 otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);802 otrl_sm_state_free(ctx->smstate);803 break;804 case OTRL_SMPEVENT_NONE:805 break;806 case OTRL_SMPEVENT_IN_PROGRESS:807 break;808 case OTRL_SMPEVENT_SUCCESS:809 if(ctx->smstate->received_question) {810 irc_rootmsg(irc, "smp %s: correct answer, you are trusted",811 u->nick);812 } else {813 irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted",814 u->nick);815 }816 otrl_sm_state_free(ctx->smstate);817 break;818 case OTRL_SMPEVENT_FAILURE:819 if(ctx->smstate->received_question) {820 irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted",821 u->nick);822 } else {823 irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted",824 u->nick);825 }826 otrl_sm_state_free(ctx->smstate);827 break;828 case OTRL_SMPEVENT_ABORT:829 irc_rootmsg(irc, "smp: received abort from %s", u->nick);830 otrl_sm_state_free(ctx->smstate);831 break;832 case OTRL_SMPEVENT_ERROR:833 irc_rootmsg(irc, "smp %s: protocol error, aborting",834 u->nick);835 otrl_message_abort_smp(us, &otr_ops, u->bu->ic, ctx);836 otrl_sm_state_free(ctx->smstate);837 break;838 }839 }840 841 void op_handle_msg_event(void *opdata, OtrlMessageEvent ev, ConnContext *ctx,842 const char *message, gcry_error_t err)843 {844 switch(ev) {845 case OTRL_MSGEVENT_ENCRYPTION_REQUIRED:846 display_otr_message(opdata, ctx,847 "policy requires encryption - message not sent");848 break;849 case OTRL_MSGEVENT_ENCRYPTION_ERROR:850 display_otr_message(opdata, ctx,851 "error during encryption - message not sent");852 break;853 case OTRL_MSGEVENT_CONNECTION_ENDED:854 display_otr_message(opdata, ctx,855 "other end has disconnected OTR - "856 "close connection or reconnect!");857 break;858 case OTRL_MSGEVENT_SETUP_ERROR:859 display_otr_message(opdata, ctx,860 "OTR connection failed: %s", gcry_strerror(err));861 break;862 case OTRL_MSGEVENT_MSG_REFLECTED:863 display_otr_message(opdata, ctx,864 "received our own OTR message (!?)");865 break;866 case OTRL_MSGEVENT_MSG_RESENT:867 display_otr_message(opdata, ctx,868 "the previous message was resent");869 break;870 case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE:871 display_otr_message(opdata, ctx,872 "unexpected encrypted message received");873 break;874 case OTRL_MSGEVENT_RCVDMSG_UNREADABLE:875 display_otr_message(opdata, ctx,876 "unreadable encrypted message received");877 break;878 case OTRL_MSGEVENT_RCVDMSG_MALFORMED:879 display_otr_message(opdata, ctx,880 "malformed OTR message received");881 break;882 case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD:883 if(global.conf->verbose) {884 log_otr_message(opdata, "%s/%s: heartbeat received",885 ctx->accountname, ctx->protocol);886 }887 break;888 case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT:889 if(global.conf->verbose) {890 log_otr_message(opdata, "%s/%s: heartbeat sent",891 ctx->accountname, ctx->protocol);892 }893 break;894 case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR:895 display_otr_message(opdata, ctx,896 "OTR error message received: %s", message);897 break;898 case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED:899 display_otr_message(opdata, ctx,900 "unencrypted message received: %s", message);901 break;902 case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED:903 display_otr_message(opdata, ctx,904 "unrecognized OTR message received");905 break;906 case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE:907 display_otr_message(opdata, ctx,908 "OTR message for a different instance received");909 break;910 default:911 /* shouldn't happen */912 break;913 }914 }915 916 const char *op_otr_error_message(void *opdata, ConnContext *ctx,917 OtrlErrorCode err_code)918 {919 switch(err_code) {920 case OTRL_ERRCODE_ENCRYPTION_ERROR:921 return "i failed to encrypt a message";922 case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE:923 return "you sent an encrypted message i didn't expect";924 case OTRL_ERRCODE_MSG_UNREADABLE:925 return "could not read encrypted message";926 case OTRL_ERRCODE_MSG_MALFORMED:927 return "you sent a malformed OTR message";928 default:929 return "i suffered an unexpected OTR error";930 }931 }932 933 756 934 757 … … 951 774 } 952 775 953 /* XXX we disconnect all instances; is that what we want? */ 954 otrl_message_disconnect_all_instances(irc->otr->us, &otr_ops, 776 otrl_message_disconnect(irc->otr->us, &otr_ops, 955 777 u->bu->ic, u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, u->bu->handle); 956 778 957 /* for some reason, libotr (4.0.0) doesn't do this itself: */ 958 if(!(u->flags & IRC_USER_OTR_ENCRYPTED)) 959 return; 960 961 ConnContext *ctx, *p; 962 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, 963 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); 964 if(!ctx) { /* huh? */ 965 u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED ); 966 return; 967 } 968 969 for(p=ctx; p && p->m_context == ctx->m_context; p=p->next) 970 op_gone_insecure(u->bu->ic, p); 779 /* for some reason, libotr (3.1.0) doesn't do this itself: */ 780 if(u->flags & IRC_USER_OTR_ENCRYPTED) { 781 ConnContext *ctx; 782 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, 783 u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 784 if(ctx) 785 op_gone_insecure(u->bu->ic, ctx); 786 else /* huh? */ 787 u->flags &= ( IRC_USER_OTR_ENCRYPTED | IRC_USER_OTR_TRUSTED ); 788 } 971 789 } 972 790 … … 985 803 } 986 804 987 /* passing this through the filter so it goes through libotr which 988 * will replace the simple query string with a proper one */ 989 otr_filter_msg_out(u, "?OTR?", 0); 805 bee_user_msg(irc->b, u->bu, "?OTR?v2?", 0); 990 806 } 991 807 … … 1015 831 1016 832 ctx = otrl_context_find(irc->otr->us, u->bu->handle, 1017 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER,0, NULL, NULL, NULL);833 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 1018 834 if(!ctx) { 1019 835 irc_rootmsg(irc, "%s: no otr context with user", args[1]); … … 1079 895 *(myhandle++) = '\0'; 1080 896 handle = arg; 1081 ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, OTRL_INSTAG_MASTER,0, NULL, NULL, NULL);897 ctx = otrl_context_find(irc->otr->us, handle, myhandle, protocol, 0, NULL, NULL, NULL); 1082 898 if(!ctx) { 1083 899 irc_rootmsg(irc, "no such context"); … … 1093 909 } 1094 910 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, 1095 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER,0, NULL, NULL, NULL);911 u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 1096 912 if(!ctx) { 1097 913 irc_rootmsg(irc, "no otr context with %s", args[1]); … … 1166 982 1167 983 g_free(p); 1168 1169 // XXX forget all contexts1170 984 1171 985 if(ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) { … … 1214 1028 1215 1029 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, 1216 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER,0, NULL, NULL, NULL);1030 u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 1217 1031 if(!ctx) { 1218 1032 irc_rootmsg(irc, "no otr context with %s", args[2]); … … 1257 1071 1258 1072 ctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user, 1259 u->bu->ic->acc->prpl->name, OTRL_INSTAG_MASTER,0, NULL, NULL, NULL);1073 u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 1260 1074 if(!ctx) { 1261 1075 irc_rootmsg(irc, "no otr context with %s", args[2]); … … 1305 1119 /*** local helpers / subroutines: ***/ 1306 1120 1307 void log_otr_message(void *opdata, const char *fmt, ...) 1308 { 1309 va_list va; 1310 1311 va_start(va, fmt); 1312 char *msg = g_strdup_vprintf(fmt, va); 1313 va_end(va); 1314 1315 log_message(LOGLVL_INFO, "otr: %s", msg); 1316 } 1317 1318 void display_otr_message(void *opdata, ConnContext *ctx, const char *fmt, ...) 1319 { 1320 struct im_connection *ic = 1321 check_imc(opdata, ctx->accountname, ctx->protocol); 1121 /* Socialist Millionaires' Protocol */ 1122 void otr_handle_smp(struct im_connection *ic, const char *handle, OtrlTLV *tlvs) 1123 { 1322 1124 irc_t *irc = ic->bee->ui_data; 1323 irc_user_t *u = peeruser(irc, ctx->username, ctx->protocol); 1324 va_list va; 1325 1326 va_start(va, fmt); 1327 char *msg = g_strdup_vprintf(fmt, va); 1328 va_end(va); 1329 1330 if(u) { 1331 /* display as a notice from this particular user */ 1332 irc_usernotice(u, "%s", msg); 1333 } else { 1334 irc_rootmsg(irc, "[otr] %s", msg); 1335 } 1336 1337 g_free(msg); 1125 OtrlUserState us = irc->otr->us; 1126 OtrlMessageAppOps *ops = &otr_ops; 1127 OtrlTLV *tlv = NULL; 1128 ConnContext *context; 1129 NextExpectedSMP nextMsg; 1130 irc_user_t *u; 1131 bee_user_t *bu; 1132 1133 bu = bee_user_by_handle(ic->bee, ic, handle); 1134 if(!bu || !(u = bu->ui_data)) return; 1135 context = otrl_context_find(us, handle, 1136 ic->acc->user, ic->acc->prpl->name, 1, NULL, NULL, NULL); 1137 if(!context) { 1138 /* huh? out of memory or what? */ 1139 irc_rootmsg(irc, "smp: failed to get otr context for %s", u->nick); 1140 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1141 otrl_sm_state_free(context->smstate); 1142 return; 1143 } 1144 nextMsg = context->smstate->nextExpected; 1145 1146 if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) { 1147 irc_rootmsg(irc, "smp %s: opponent violated protocol, aborting", 1148 u->nick); 1149 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1150 otrl_sm_state_free(context->smstate); 1151 return; 1152 } 1153 1154 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); 1155 if (tlv) { 1156 if (nextMsg != OTRL_SMP_EXPECT1) { 1157 irc_rootmsg(irc, "smp %s: spurious SMP1Q received, aborting", u->nick); 1158 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1159 otrl_sm_state_free(context->smstate); 1160 } else { 1161 char *question = g_strndup((char *)tlv->data, tlv->len); 1162 irc_rootmsg(irc, "smp: initiated by %s with question: \x02\"%s\"\x02", u->nick, 1163 question); 1164 irc_rootmsg(irc, "smp: respond with \x02otr smp %s <answer>\x02", 1165 u->nick); 1166 g_free(question); 1167 /* smp stays in EXPECT1 until user responds */ 1168 } 1169 } 1170 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); 1171 if (tlv) { 1172 if (nextMsg != OTRL_SMP_EXPECT1) { 1173 irc_rootmsg(irc, "smp %s: spurious SMP1 received, aborting", u->nick); 1174 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1175 otrl_sm_state_free(context->smstate); 1176 } else { 1177 irc_rootmsg(irc, "smp: initiated by %s" 1178 " - respond with \x02otr smp %s <secret>\x02", 1179 u->nick, u->nick); 1180 /* smp stays in EXPECT1 until user responds */ 1181 } 1182 } 1183 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); 1184 if (tlv) { 1185 if (nextMsg != OTRL_SMP_EXPECT2) { 1186 irc_rootmsg(irc, "smp %s: spurious SMP2 received, aborting", u->nick); 1187 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1188 otrl_sm_state_free(context->smstate); 1189 } else { 1190 /* SMP2 received, otrl_message_receiving will have sent SMP3 */ 1191 context->smstate->nextExpected = OTRL_SMP_EXPECT4; 1192 } 1193 } 1194 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); 1195 if (tlv) { 1196 if (nextMsg != OTRL_SMP_EXPECT3) { 1197 irc_rootmsg(irc, "smp %s: spurious SMP3 received, aborting", u->nick); 1198 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1199 otrl_sm_state_free(context->smstate); 1200 } else { 1201 /* SMP3 received, otrl_message_receiving will have sent SMP4 */ 1202 if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) { 1203 if(context->smstate->received_question) { 1204 irc_rootmsg(irc, "smp %s: correct answer, you are trusted", 1205 u->nick); 1206 } else { 1207 irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted", 1208 u->nick); 1209 } 1210 } else { 1211 if(context->smstate->received_question) { 1212 irc_rootmsg(irc, "smp %s: wrong answer, you are not trusted", 1213 u->nick); 1214 } else { 1215 irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted", 1216 u->nick); 1217 } 1218 } 1219 otrl_sm_state_free(context->smstate); 1220 /* smp is in back in EXPECT1 */ 1221 } 1222 } 1223 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); 1224 if (tlv) { 1225 if (nextMsg != OTRL_SMP_EXPECT4) { 1226 irc_rootmsg(irc, "smp %s: spurious SMP4 received, aborting", u->nick); 1227 otrl_message_abort_smp(us, ops, u->bu->ic, context); 1228 otrl_sm_state_free(context->smstate); 1229 } else { 1230 /* SMP4 received, otrl_message_receiving will have set fp trust */ 1231 if(context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED) { 1232 irc_rootmsg(irc, "smp %s: secrets proved equal, fingerprint trusted", 1233 u->nick); 1234 } else { 1235 irc_rootmsg(irc, "smp %s: secrets did not match, fingerprint not trusted", 1236 u->nick); 1237 } 1238 otrl_sm_state_free(context->smstate); 1239 /* smp is in back in EXPECT1 */ 1240 } 1241 } 1242 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); 1243 if (tlv) { 1244 irc_rootmsg(irc, "smp: received abort from %s", u->nick); 1245 otrl_sm_state_free(context->smstate); 1246 /* smp is in back in EXPECT1 */ 1247 } 1338 1248 } 1339 1249 … … 1344 1254 irc_user_t *u; 1345 1255 ConnContext *ctx; 1346 otrl_instag_t instag = OTRL_INSTAG_RECENT; // XXX1347 1256 1348 1257 u = irc_user_by_name(irc, nick); … … 1357 1266 1358 1267 ctx = otrl_context_find(irc->otr->us, u->bu->handle, 1359 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, instag,0, NULL, NULL, NULL);1268 u->bu->ic->acc->user, u->bu->ic->acc->prpl->name, 0, NULL, NULL, NULL); 1360 1269 if(!ctx || ctx->msgstate != OTRL_MSGSTATE_ENCRYPTED) { 1361 1270 irc_rootmsg(irc, "smp: otr inactive with %s, try \x02otr connect" … … 1398 1307 } 1399 1308 1400 /* timeout handler that calls otrl_message_poll */1401 gboolean ev_message_poll(gpointer data, gint fd, b_input_condition cond)1402 {1403 otr_t *otr = data;1404 1405 if(otr && otr->us)1406 otrl_message_poll(otr->us, &otr_ops, NULL);1407 1408 return TRUE; /* cycle timer */1409 }1410 1411 1309 /* helper to assert that account and protocol names given to ops below always 1412 1310 match the im_connection passed through as opdata */ … … 1415 1313 { 1416 1314 struct im_connection *ic = (struct im_connection *)opdata; 1417 1418 /* libotr 4.0.0 has a bug where it doesn't set opdata, so we catch1419 * that and try to find the desired connection in the global list. */1420 if(!ic) {1421 GSList *l;1422 for(l=get_connections(); l; l=l->next) {1423 ic = l->data;1424 if(strcmp(accountname, ic->acc->user) == 0 &&1425 strcmp(protocol, ic->acc->prpl->name) == 0)1426 break;1427 }1428 assert(l != NULL); /* a match should always be found */1429 if(!l)1430 return NULL;1431 }1432 1315 1433 1316 if (strcmp(accountname, ic->acc->user) != 0) { … … 1711 1594 1712 1595 /* list all contexts */ 1713 /* XXX remove this, or split off as its own command */1714 /* XXX show instags? */1715 1596 irc_rootmsg(irc, "%s", ""); 1716 1597 irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)"); … … 1741 1622 void show_otr_context_info(irc_t *irc, ConnContext *ctx) 1742 1623 { 1743 // XXX show all instags/subcontexts1744 1745 1624 switch(ctx->otr_offer) { 1746 1625 case OFFER_NOT:
Note: See TracChangeset
for help on using the changeset viewer.