1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2010 Wilmer van der Gaast and others *
5 \********************************************************************/
8 OTR support (cf. http://www.cypherpunks.ca/otr/)
10 (c) 2008-2011 Sven Moritz Hallberg <pesco@khjk.org>
11 (c) 2008 funded by stonedcoder.org
13 files used to store OTR data:
14 <configdir>/<nick>.otr_keys
15 <configdir>/<nick>.otr_fprints
17 top-level todos: (search for TODO for more ;-))
18 integrate otr_load/otr_save with existing storage backends
19 per-account policy settings
20 per-user policy settings
24 This program is free software; you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation; either version 2 of the License, or
27 (at your option) any later version.
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
34 You should have received a copy of the GNU General Public License with
35 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
36 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
37 Suite 330, Boston, MA 02111-1307 USA
43 #include <sys/types.h>
50 /** OTR interface routines for the OtrlMessageAppOps struct: **/
52 OtrlPolicy
op_policy(void *opdata
, ConnContext
*context
);
54 void op_create_privkey(void *opdata
, const char *accountname
, const char *protocol
);
56 int op_is_logged_in(void *opdata
, const char *accountname
, const char *protocol
,
57 const char *recipient
);
59 void op_inject_message(void *opdata
, const char *accountname
, const char *protocol
,
60 const char *recipient
, const char *message
);
62 int op_display_otr_message(void *opdata
, const char *accountname
, const char *protocol
,
63 const char *username
, const char *msg
);
65 void op_new_fingerprint(void *opdata
, OtrlUserState us
, const char *accountname
,
66 const char *protocol
, const char *username
, unsigned char fingerprint
[20]);
68 void op_write_fingerprints(void *opdata
);
70 void op_gone_secure(void *opdata
, ConnContext
*context
);
72 void op_gone_insecure(void *opdata
, ConnContext
*context
);
74 void op_still_secure(void *opdata
, ConnContext
*context
, int is_reply
);
76 void op_log_message(void *opdata
, const char *message
);
78 int op_max_message_size(void *opdata
, ConnContext
*context
);
80 const char *op_account_name(void *opdata
, const char *account
, const char *protocol
);
83 /** otr sub-command handlers: **/
85 static void cmd_otr(irc_t
*irc
, char **args
);
86 void cmd_otr_connect(irc_t
*irc
, char **args
);
87 void cmd_otr_disconnect(irc_t
*irc
, char **args
);
88 void cmd_otr_reconnect(irc_t
*irc
, char **args
);
89 void cmd_otr_smp(irc_t
*irc
, char **args
);
90 void cmd_otr_smpq(irc_t
*irc
, char **args
);
91 void cmd_otr_trust(irc_t
*irc
, char **args
);
92 void cmd_otr_info(irc_t
*irc
, char **args
);
93 void cmd_otr_keygen(irc_t
*irc
, char **args
);
94 void cmd_otr_forget(irc_t
*irc
, char **args
);
96 const command_t otr_commands
[] = {
97 { "connect", 1, &cmd_otr_connect
, 0 },
98 { "disconnect", 1, &cmd_otr_disconnect
, 0 },
99 { "reconnect", 1, &cmd_otr_reconnect
, 0 },
100 { "smp", 2, &cmd_otr_smp
, 0 },
101 { "smpq", 3, &cmd_otr_smpq
, 0 },
102 { "trust", 6, &cmd_otr_trust
, 0 },
103 { "info", 0, &cmd_otr_info
, 0 },
104 { "keygen", 1, &cmd_otr_keygen
, 0 },
105 { "forget", 2, &cmd_otr_forget
, 0 },
114 static OtrlMessageAppOps otr_ops
; /* collects interface functions required by OTR */
117 /** misc. helpers/subroutines: **/
119 /* check whether we are already generating a key for a given account */
120 int keygen_in_progress(irc_t
*irc
, const char *handle
, const char *protocol
);
122 /* start background process to generate a (new) key for a given account */
123 void otr_keygen(irc_t
*irc
, const char *handle
, const char *protocol
);
125 /* main function for the forked keygen slave */
126 void keygen_child_main(OtrlUserState us
, int infd
, int outfd
);
128 /* mainloop handler for when a keygen finishes */
129 gboolean
keygen_finish_handler(gpointer data
, gint fd
, b_input_condition cond
);
131 /* copy the contents of file a to file b, overwriting it if it exists */
132 void copyfile(const char *a
, const char *b
);
134 /* read one line of input from a stream, excluding trailing newline */
135 void myfgets(char *s
, int size
, FILE *stream
);
137 /* some yes/no handlers */
138 void yes_keygen(void *data
);
139 void yes_forget_fingerprint(void *data
);
140 void yes_forget_context(void *data
);
141 void yes_forget_key(void *data
);
143 /* helper to make sure accountname and protocol match the incoming "opdata" */
144 struct im_connection
*check_imc(void *opdata
, const char *accountname
,
145 const char *protocol
);
147 /* determine the nick for a given handle/protocol pair
148 returns "handle/protocol" if not found */
149 const char *peernick(irc_t
*irc
, const char *handle
, const char *protocol
);
151 /* turn a hexadecimal digit into its numerical value */
154 /* determine the irc_user_t for a given handle/protocol pair
155 returns NULL if not found */
156 irc_user_t
*peeruser(irc_t
*irc
, const char *handle
, const char *protocol
);
158 /* handle SMP TLVs from a received message */
159 void otr_handle_smp(struct im_connection
*ic
, const char *handle
, OtrlTLV
*tlvs
);
161 /* combined handler for the 'otr smp' and 'otr smpq' commands */
162 void otr_smp_or_smpq(irc_t
*irc
, const char *nick
, const char *question
,
165 /* update flags within the irc_user structure to reflect OTR status of context */
166 void otr_update_uflags(ConnContext
*context
, irc_user_t
*u
);
168 /* update op/voice flag of given user according to encryption state and settings
169 returns 0 if neither op_buddies nor voice_buddies is set to "encrypted",
170 i.e. msgstate should be announced seperately */
171 int otr_update_modeflags(irc_t
*irc
, irc_user_t
*u
);
173 /* show general info about the OTR subsystem; called by 'otr info' */
174 void show_general_otr_info(irc_t
*irc
);
176 /* show info about a given OTR context */
177 void show_otr_context_info(irc_t
*irc
, ConnContext
*ctx
);
179 /* show the list of fingerprints associated with a given context */
180 void show_fingerprints(irc_t
*irc
, ConnContext
*ctx
);
182 /* find a fingerprint by prefix (given as any number of hex strings) */
183 Fingerprint
*match_fingerprint(irc_t
*irc
, ConnContext
*ctx
, const char **args
);
185 /* find a private key by fingerprint prefix (given as any number of hex strings) */
186 OtrlPrivKey
*match_privkey(irc_t
*irc
, const char **args
);
188 /* check whether a string is safe to use in a path component */
189 int strsane(const char *s
);
191 /* functions to be called for certain events */
192 static const struct irc_plugin otr_plugin
;
195 /*** routines declared in otr.h: ***/
198 #define init_plugin otr_init
201 void init_plugin(void)
205 /* fill global OtrlMessageAppOps */
206 otr_ops
.policy
= &op_policy
;
207 otr_ops
.create_privkey
= &op_create_privkey
;
208 otr_ops
.is_logged_in
= &op_is_logged_in
;
209 otr_ops
.inject_message
= &op_inject_message
;
210 otr_ops
.notify
= NULL
;
211 otr_ops
.display_otr_message
= &op_display_otr_message
;
212 otr_ops
.update_context_list
= NULL
;
213 otr_ops
.protocol_name
= NULL
;
214 otr_ops
.protocol_name_free
= NULL
;
215 otr_ops
.new_fingerprint
= &op_new_fingerprint
;
216 otr_ops
.write_fingerprints
= &op_write_fingerprints
;
217 otr_ops
.gone_secure
= &op_gone_secure
;
218 otr_ops
.gone_insecure
= &op_gone_insecure
;
219 otr_ops
.still_secure
= &op_still_secure
;
220 otr_ops
.log_message
= &op_log_message
;
221 otr_ops
.max_message_size
= &op_max_message_size
;
222 otr_ops
.account_name
= &op_account_name
;
223 otr_ops
.account_name_free
= NULL
;
225 root_command_add( "otr", 1, cmd_otr
, 0 );
226 register_irc_plugin( &otr_plugin
);
229 gboolean
otr_irc_new(irc_t
*irc
)
234 irc
->otr
= g_new0(otr_t
, 1);
235 irc
->otr
->us
= otrl_userstate_create();
237 s
= set_add( &irc
->b
->set
, "otr_color_encrypted", "true", set_eval_bool
, irc
);
239 s
= set_add( &irc
->b
->set
, "otr_policy", "oppurtunistic", set_eval_list
, irc
);
240 l
= g_slist_prepend( NULL
, "never" );
241 l
= g_slist_prepend( l
, "opportunistic" );
242 l
= g_slist_prepend( l
, "manual" );
243 l
= g_slist_prepend( l
, "always" );
246 s
= set_add( &irc
->b
->set
, "otr_does_html", "true", set_eval_bool
, irc
);
251 void otr_irc_free(irc_t
*irc
)
253 otr_t
*otr
= irc
->otr
;
254 otrl_userstate_free(otr
->us
);
256 kill(otr
->keygen
, SIGTERM
);
257 waitpid(otr
->keygen
, NULL
, 0);
258 /* TODO: remove stale keygen tempfiles */
272 void otr_load(irc_t
*irc
)
277 gcry_error_t enoent
= gcry_error_from_errno(ENOENT
);
280 if(strsane(irc
->user
->nick
)) {
281 g_snprintf(s
, 511, "%s%s.otr_keys", global
.conf
->configdir
, irc
->user
->nick
);
282 e
= otrl_privkey_read(irc
->otr
->us
, s
);
284 irc_rootmsg(irc
, "otr load: %s: %s", s
, gcry_strerror(e
));
286 g_snprintf(s
, 511, "%s%s.otr_fprints", global
.conf
->configdir
, irc
->user
->nick
);
287 e
= otrl_privkey_read_fingerprints(irc
->otr
->us
, s
, NULL
, NULL
);
289 irc_rootmsg(irc
, "otr load: %s: %s", s
, gcry_strerror(e
));
293 /* check for otr keys on all accounts */
294 for(a
=irc
->b
->accounts
; a
; a
=a
->next
) {
295 kg
= otr_check_for_key(a
) || kg
;
298 irc_rootmsg(irc
, "Notice: "
299 "The accounts above do not have OTR encryption keys associated with them, yet. "
300 "These keys are now being generated in the background. "
301 "You will be notified as they are completed. "
302 "It is not necessary to wait; "
303 "BitlBee can be used normally during key generation. "
304 "You may safely ignore this message if you don't know what OTR is. ;)");
308 void otr_save(irc_t
*irc
)
313 if(strsane(irc
->user
->nick
)) {
314 g_snprintf(s
, 511, "%s%s.otr_fprints", global
.conf
->configdir
, irc
->user
->nick
);
315 e
= otrl_privkey_write_fingerprints(irc
->otr
->us
, s
);
317 irc_rootmsg(irc
, "otr save: %s: %s", s
, gcry_strerror(e
));
323 void otr_remove(const char *nick
)
328 g_snprintf(s
, 511, "%s%s.otr_keys", global
.conf
->configdir
, nick
);
330 g_snprintf(s
, 511, "%s%s.otr_fprints", global
.conf
->configdir
, nick
);
335 void otr_rename(const char *onick
, const char *nnick
)
339 if(strsane(nnick
) && strsane(onick
)) {
340 g_snprintf(s
, 511, "%s%s.otr_keys", global
.conf
->configdir
, onick
);
341 g_snprintf(t
, 511, "%s%s.otr_keys", global
.conf
->configdir
, nnick
);
343 g_snprintf(s
, 511, "%s%s.otr_fprints", global
.conf
->configdir
, onick
);
344 g_snprintf(t
, 511, "%s%s.otr_fprints", global
.conf
->configdir
, nnick
);
349 int otr_check_for_key(account_t
*a
)
351 irc_t
*irc
= a
->bee
->ui_data
;
354 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */
355 if(a
->prpl
->options
& OPT_NOOTR
) {
359 k
= otrl_privkey_find(irc
->otr
->us
, a
->user
, a
->prpl
->name
);
361 irc_rootmsg(irc
, "otr: %s/%s ready", a
->user
, a
->prpl
->name
);
363 } if(keygen_in_progress(irc
, a
->user
, a
->prpl
->name
)) {
364 irc_rootmsg(irc
, "otr: keygen for %s/%s already in progress", a
->user
, a
->prpl
->name
);
367 irc_rootmsg(irc
, "otr: starting background keygen for %s/%s", a
->user
, a
->prpl
->name
);
368 otr_keygen(irc
, a
->user
, a
->prpl
->name
);
373 char *otr_filter_msg_in(irc_user_t
*iu
, char *msg
, int flags
)
377 OtrlTLV
*tlvs
= NULL
;
378 irc_t
*irc
= iu
->irc
;
379 struct im_connection
*ic
= iu
->bu
->ic
;
381 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */
382 if(ic
->acc
->prpl
->options
& OPT_NOOTR
) {
386 ignore_msg
= otrl_message_receiving(irc
->otr
->us
, &otr_ops
, ic
,
387 ic
->acc
->user
, ic
->acc
->prpl
->name
, iu
->bu
->handle
, msg
, &newmsg
,
390 otr_handle_smp(ic
, iu
->bu
->handle
, tlvs
);
393 /* this was an internal OTR protocol message */
396 /* this was a non-OTR message */
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
);
403 /* we're done with the original msg, which will be caller-freed. */
404 /* NB: must not change the newmsg pointer, since we free it. */
407 if(context
&& context
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
) {
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")) {
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
;
422 if(trust
&& trust
[0] != '\0')
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
) {
434 /* comma in first place could mess with the color code */
436 /* insert a space between color spec and message */
440 msg
= g_strdup_printf("%s\x03%.2d%s%s\x0F", pre
,
446 msg
= g_strdup(newmsg
);
448 otrl_message_free(newmsg
);
453 char *otr_filter_msg_out(irc_user_t
*iu
, char *msg
, int flags
)
457 char *emsg
= msg
; /* the message as we hand it to libotr */
458 ConnContext
*ctx
= NULL
;
459 irc_t
*irc
= iu
->irc
;
460 struct im_connection
*ic
= iu
->bu
->ic
;
462 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */
463 if(ic
->acc
->prpl
->options
& OPT_NOOTR
) {
467 ctx
= otrl_context_find(irc
->otr
->us
,
468 iu
->bu
->handle
, ic
->acc
->user
, ic
->acc
->prpl
->name
,
469 1, NULL
, NULL
, NULL
);
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
);
479 st
= otrl_message_sending(irc
->otr
->us
, &otr_ops
, ic
,
480 ic
->acc
->user
, ic
->acc
->prpl
->name
, iu
->bu
->handle
,
481 emsg
, NULL
, &otrmsg
, NULL
, NULL
);
483 g_free(emsg
); /* we're done with this one */
491 otrl_message_free(otrmsg
);
494 st
= otrl_message_fragment_and_send(&otr_ops
, ic
, ctx
,
495 otrmsg
, OTRL_FRAGMENT_SEND_ALL
, NULL
);
496 otrl_message_free(otrmsg
);
498 /* note: otrl_message_sending handles policy, so that if REQUIRE_ENCRYPTION is set,
499 this case does not occur */
503 /* TODO: Error reporting should be done here now (if st!=0), probably. */
508 static const struct irc_plugin otr_plugin
=
519 static void cmd_otr(irc_t
*irc
, char **args
)
521 const command_t
*cmd
;
529 for(cmd
=otr_commands
; cmd
->command
; cmd
++) {
530 if(strcmp(cmd
->command
, args
[1]) == 0)
535 irc_rootmsg(irc
, "%s: unknown subcommand \"%s\", see \x02help otr\x02",
540 if(!args
[cmd
->required_parameters
+1]) {
541 irc_rootmsg(irc
, "%s %s: not enough arguments (%d req.)",
542 args
[0], args
[1], cmd
->required_parameters
);
546 cmd
->execute(irc
, args
+1);
550 /*** OTR "MessageAppOps" callbacks for global.otr_ui: ***/
552 OtrlPolicy
op_policy(void *opdata
, ConnContext
*context
)
554 struct im_connection
*ic
= check_imc(opdata
, context
->accountname
, context
->protocol
);
555 irc_t
*irc
= ic
->bee
->ui_data
;
558 /* policy override during keygen: if we're missing the key for context but are currently
559 generating it, then that's as much as we can do. => temporarily return NEVER. */
560 if(keygen_in_progress(irc
, context
->accountname
, context
->protocol
) &&
561 !otrl_privkey_find(irc
->otr
->us
, context
->accountname
, context
->protocol
))
562 return OTRL_POLICY_NEVER
;
564 p
= set_getstr(&ic
->bee
->set
, "otr_policy");
565 if(!strcmp(p
, "never"))
566 return OTRL_POLICY_NEVER
;
567 if(!strcmp(p
, "opportunistic"))
568 return OTRL_POLICY_OPPORTUNISTIC
;
569 if(!strcmp(p
, "manual"))
570 return OTRL_POLICY_MANUAL
;
571 if(!strcmp(p
, "always"))
572 return OTRL_POLICY_ALWAYS
;
574 return OTRL_POLICY_OPPORTUNISTIC
;
577 void op_create_privkey(void *opdata
, const char *accountname
,
578 const char *protocol
)
580 struct im_connection
*ic
= check_imc(opdata
, accountname
, protocol
);
581 irc_t
*irc
= ic
->bee
->ui_data
;
583 /* will fail silently if keygen already in progress */
584 otr_keygen(irc
, accountname
, protocol
);
587 int op_is_logged_in(void *opdata
, const char *accountname
,
588 const char *protocol
, const char *recipient
)
590 struct im_connection
*ic
= check_imc(opdata
, accountname
, protocol
);
593 /* lookup the irc_user_t for the given recipient */
594 bu
= bee_user_by_handle(ic
->bee
, ic
, recipient
);
596 if(bu
->flags
& BEE_USER_ONLINE
)
605 void op_inject_message(void *opdata
, const char *accountname
,
606 const char *protocol
, const char *recipient
, const char *message
)
608 struct im_connection
*ic
= check_imc(opdata
, accountname
, protocol
);
609 irc_t
*irc
= ic
->bee
->ui_data
;
611 if (strcmp(accountname
, recipient
) == 0) {
612 /* huh? injecting messages to myself? */
613 irc_rootmsg(irc
, "note to self: %s", message
);
615 /* need to drop some consts here :-( */
616 /* TODO: get flags into op_inject_message?! */
617 ic
->acc
->prpl
->buddy_msg(ic
, (char *)recipient
, (char *)message
, 0);
618 /* ignoring return value :-/ */
622 int op_display_otr_message(void *opdata
, const char *accountname
,
623 const char *protocol
, const char *username
, const char *message
)
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
);
632 /* display as a notice from this particular user */
633 irc_usernotice(u
, "%s", msg
);
635 irc_rootmsg(irc
, "[otr] %s", msg
);
642 void op_new_fingerprint(void *opdata
, OtrlUserState us
,
643 const char *accountname
, const char *protocol
,
644 const char *username
, unsigned char fingerprint
[20])
646 struct im_connection
*ic
= check_imc(opdata
, accountname
, protocol
);
647 irc_t
*irc
= ic
->bee
->ui_data
;
648 irc_user_t
*u
= peeruser(irc
, username
, protocol
);
649 char hunam
[45]; /* anybody looking? ;-) */
651 otrl_privkey_hash_to_human(hunam
, fingerprint
);
653 irc_usernotice(u
, "new fingerprint: %s", hunam
);
655 /* this case shouldn't normally happen */
656 irc_rootmsg(irc
, "new fingerprint for %s/%s: %s",
657 username
, protocol
, hunam
);
661 void op_write_fingerprints(void *opdata
)
663 struct im_connection
*ic
= (struct im_connection
*)opdata
;
664 irc_t
*irc
= ic
->bee
->ui_data
;
669 void op_gone_secure(void *opdata
, ConnContext
*context
)
671 struct im_connection
*ic
=
672 check_imc(opdata
, context
->accountname
, context
->protocol
);
674 irc_t
*irc
= ic
->bee
->ui_data
;
676 u
= peeruser(irc
, context
->username
, context
->protocol
);
678 log_message(LOGLVL_ERROR
,
679 "BUG: otr.c: op_gone_secure: irc_user_t for %s/%s/%s not found!",
680 context
->username
, context
->protocol
, context
->accountname
);
684 otr_update_uflags(context
, u
);
685 if(!otr_update_modeflags(irc
, u
)) {
686 char *trust
= u
->flags
& IRC_USER_OTR_TRUSTED
? "trusted" : "untrusted!";
687 irc_usernotice(u
, "conversation is now off the record (%s)", trust
);
691 void op_gone_insecure(void *opdata
, ConnContext
*context
)
693 struct im_connection
*ic
=
694 check_imc(opdata
, context
->accountname
, context
->protocol
);
695 irc_t
*irc
= ic
->bee
->ui_data
;
698 u
= peeruser(irc
, context
->username
, context
->protocol
);
700 log_message(LOGLVL_ERROR
,
701 "BUG: otr.c: op_gone_insecure: irc_user_t for %s/%s/%s not found!",
702 context
->username
, context
->protocol
, context
->accountname
);
705 otr_update_uflags(context
, u
);
706 if(!otr_update_modeflags(irc
, u
))
707 irc_usernotice(u
, "conversation is now in cleartext");
710 void op_still_secure(void *opdata
, ConnContext
*context
, int is_reply
)
712 struct im_connection
*ic
=
713 check_imc(opdata
, context
->accountname
, context
->protocol
);
714 irc_t
*irc
= ic
->bee
->ui_data
;
717 u
= peeruser(irc
, context
->username
, context
->protocol
);
719 log_message(LOGLVL_ERROR
,
720 "BUG: otr.c: op_still_secure: irc_user_t for %s/%s/%s not found!",
721 context
->username
, context
->protocol
, context
->accountname
);
725 otr_update_uflags(context
, u
);
726 if(!otr_update_modeflags(irc
, u
)) {
727 char *trust
= u
->flags
& IRC_USER_OTR_TRUSTED
? "trusted" : "untrusted!";
728 irc_usernotice(u
, "otr connection has been refreshed (%s)", trust
);
732 void op_log_message(void *opdata
, const char *message
)
734 char *msg
= g_strdup(message
);
737 log_message(LOGLVL_INFO
, "otr: %s", msg
);
741 int op_max_message_size(void *opdata
, ConnContext
*context
)
743 struct im_connection
*ic
=
744 check_imc(opdata
, context
->accountname
, context
->protocol
);
746 return ic
->acc
->prpl
->mms
;
749 const char *op_account_name(void *opdata
, const char *account
, const char *protocol
)
751 struct im_connection
*ic
= (struct im_connection
*)opdata
;
752 irc_t
*irc
= ic
->bee
->ui_data
;
754 return peernick(irc
, account
, protocol
);
758 /*** OTR sub-command handlers ***/
760 void cmd_otr_reconnect(irc_t
*irc
, char **args
)
762 cmd_otr_disconnect(irc
, args
);
763 cmd_otr_connect(irc
, args
);
766 void cmd_otr_disconnect(irc_t
*irc
, char **args
)
770 u
= irc_user_by_name(irc
, args
[1]);
771 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
772 irc_rootmsg(irc
, "%s: unknown user", args
[1]);
776 otrl_message_disconnect(irc
->otr
->us
, &otr_ops
,
777 u
->bu
->ic
, u
->bu
->ic
->acc
->user
, u
->bu
->ic
->acc
->prpl
->name
, u
->bu
->handle
);
779 /* for some reason, libotr (3.1.0) doesn't do this itself: */
780 if(u
->flags
& IRC_USER_OTR_ENCRYPTED
) {
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
);
785 op_gone_insecure(u
->bu
->ic
, ctx
);
787 u
->flags
&= ( IRC_USER_OTR_ENCRYPTED
| IRC_USER_OTR_TRUSTED
);
791 void cmd_otr_connect(irc_t
*irc
, char **args
)
795 u
= irc_user_by_name(irc
, args
[1]);
796 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
797 irc_rootmsg(irc
, "%s: unknown user", args
[1]);
800 if(!(u
->bu
->flags
& BEE_USER_ONLINE
)) {
801 irc_rootmsg(irc
, "%s is offline", args
[1]);
805 bee_user_msg(irc
->b
, u
->bu
, "?OTR?v2?", 0);
808 void cmd_otr_smp(irc_t
*irc
, char **args
)
810 otr_smp_or_smpq(irc
, args
[1], NULL
, args
[2]); /* no question */
813 void cmd_otr_smpq(irc_t
*irc
, char **args
)
815 otr_smp_or_smpq(irc
, args
[1], args
[2], args
[3]);
818 void cmd_otr_trust(irc_t
*irc
, char **args
)
822 unsigned char raw
[20];
826 u
= irc_user_by_name(irc
, args
[1]);
827 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
828 irc_rootmsg(irc
, "%s: unknown user", args
[1]);
832 ctx
= otrl_context_find(irc
->otr
->us
, u
->bu
->handle
,
833 u
->bu
->ic
->acc
->user
, u
->bu
->ic
->acc
->prpl
->name
, 0, NULL
, NULL
, NULL
);
835 irc_rootmsg(irc
, "%s: no otr context with user", args
[1]);
839 /* convert given fingerprint to raw representation */
842 char *p
= args
[2+i
]+(2*j
);
847 irc_rootmsg(irc
, "failed: truncated fingerprint block %d", i
+1);
854 irc_rootmsg(irc
, "failed: %d. hex digit of block %d out of range", 2*j
+1, i
+1);
858 irc_rootmsg(irc
, "failed: %d. hex digit of block %d out of range", 2*j
+2, i
+1);
862 raw
[i
*4+j
] = x
*16 + y
;
865 fp
= otrl_context_find_fingerprint(ctx
, raw
, 0, NULL
);
867 irc_rootmsg(irc
, "failed: no such fingerprint for %s", args
[1]);
869 char *trust
= args
[7] ? args
[7] : "affirmed";
870 otrl_context_set_trust(fp
, trust
);
871 irc_rootmsg(irc
, "fingerprint match, trust set to \"%s\"", trust
);
872 if(u
->flags
& IRC_USER_OTR_ENCRYPTED
)
873 u
->flags
|= IRC_USER_OTR_TRUSTED
;
874 otr_update_modeflags(irc
, u
);
878 void cmd_otr_info(irc_t
*irc
, char **args
)
881 show_general_otr_info(irc
);
883 char *arg
= g_strdup(args
[1]);
884 char *myhandle
, *handle
=NULL
, *protocol
;
887 /* interpret arg as 'user/protocol/account' if possible */
888 protocol
= strchr(arg
, '/');
891 *(protocol
++) = '\0';
892 myhandle
= strchr(protocol
, '/');
894 if(protocol
&& myhandle
) {
895 *(myhandle
++) = '\0';
897 ctx
= otrl_context_find(irc
->otr
->us
, handle
, myhandle
, protocol
, 0, NULL
, NULL
, NULL
);
899 irc_rootmsg(irc
, "no such context");
904 irc_user_t
*u
= irc_user_by_name(irc
, args
[1]);
905 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
906 irc_rootmsg(irc
, "%s: unknown user", args
[1]);
910 ctx
= otrl_context_find(irc
->otr
->us
, u
->bu
->handle
, u
->bu
->ic
->acc
->user
,
911 u
->bu
->ic
->acc
->prpl
->name
, 0, NULL
, NULL
, NULL
);
913 irc_rootmsg(irc
, "no otr context with %s", args
[1]);
919 /* show how we resolved the (nick) argument, if we did */
921 irc_rootmsg(irc
, "%s is %s/%s; we are %s/%s to them", args
[1],
922 ctx
->username
, ctx
->protocol
, ctx
->accountname
, ctx
->protocol
);
924 show_otr_context_info(irc
, ctx
);
929 void cmd_otr_keygen(irc_t
*irc
, char **args
)
935 if(n
<0 || (!n
&& strcmp(args
[1], "0"))) {
936 irc_rootmsg(irc
, "%s: invalid account number", args
[1]);
940 a
= irc
->b
->accounts
;
941 for(i
=0; i
<n
&& a
; i
++, a
=a
->next
);
943 irc_rootmsg(irc
, "%s: no such account", args
[1]);
947 if(keygen_in_progress(irc
, a
->user
, a
->prpl
->name
)) {
948 irc_rootmsg(irc
, "keygen for account %d already in progress", n
);
952 if(otrl_privkey_find(irc
->otr
->us
, a
->user
, a
->prpl
->name
)) {
953 char *s
= g_strdup_printf("account %d already has a key, replace it?", n
);
954 query_add(irc
, NULL
, s
, yes_keygen
, NULL
, NULL
, a
);
957 otr_keygen(irc
, a
->user
, a
->prpl
->name
);
961 void yes_forget_fingerprint(void *data
)
963 pair_t
*p
= (pair_t
*)data
;
964 irc_t
*irc
= (irc_t
*)p
->fst
;
965 Fingerprint
*fp
= (Fingerprint
*)p
->snd
;
969 if(fp
== fp
->context
->active_fingerprint
) {
970 irc_rootmsg(irc
, "that fingerprint is active, terminate otr connection first");
974 otrl_context_forget_fingerprint(fp
, 0);
977 void yes_forget_context(void *data
)
979 pair_t
*p
= (pair_t
*)data
;
980 irc_t
*irc
= (irc_t
*)p
->fst
;
981 ConnContext
*ctx
= (ConnContext
*)p
->snd
;
985 if(ctx
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
) {
986 irc_rootmsg(irc
, "active otr connection with %s, terminate it first",
987 peernick(irc
, ctx
->username
, ctx
->protocol
));
991 if(ctx
->msgstate
== OTRL_MSGSTATE_FINISHED
)
992 otrl_context_force_plaintext(ctx
);
993 otrl_context_forget(ctx
);
996 void yes_forget_key(void *data
)
998 OtrlPrivKey
*key
= (OtrlPrivKey
*)data
;
1000 otrl_privkey_forget(key
);
1001 /* Hm, libotr doesn't seem to offer a function for explicitly /writing/
1002 keyfiles. So the key will be back on the next load... */
1003 /* TODO: Actually erase forgotten keys from storage? */
1006 void cmd_otr_forget(irc_t
*irc
, char **args
)
1008 if(!strcmp(args
[1], "fingerprint"))
1018 irc_rootmsg(irc
, "otr %s %s: not enough arguments (2 req.)", args
[0], args
[1]);
1022 /* TODO: allow context specs ("user/proto/account") in 'otr forget fingerprint'? */
1023 u
= irc_user_by_name(irc
, args
[2]);
1024 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
1025 irc_rootmsg(irc
, "%s: unknown user", args
[2]);
1029 ctx
= otrl_context_find(irc
->otr
->us
, u
->bu
->handle
, u
->bu
->ic
->acc
->user
,
1030 u
->bu
->ic
->acc
->prpl
->name
, 0, NULL
, NULL
, NULL
);
1032 irc_rootmsg(irc
, "no otr context with %s", args
[2]);
1036 fp
= match_fingerprint(irc
, ctx
, ((const char **)args
)+3);
1038 /* match_fingerprint does error messages */
1042 if(fp
== ctx
->active_fingerprint
) {
1043 irc_rootmsg(irc
, "that fingerprint is active, terminate otr connection first");
1047 otrl_privkey_hash_to_human(human
, fp
->fingerprint
);
1048 s
= g_strdup_printf("about to forget fingerprint %s, are you sure?", human
);
1049 p
= g_malloc(sizeof(pair_t
));
1054 query_add(irc
, NULL
, s
, yes_forget_fingerprint
, NULL
, NULL
, p
);
1058 else if(!strcmp(args
[1], "context"))
1065 /* TODO: allow context specs ("user/proto/account") in 'otr forget contex'? */
1066 u
= irc_user_by_name(irc
, args
[2]);
1067 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
1068 irc_rootmsg(irc
, "%s: unknown user", args
[2]);
1072 ctx
= otrl_context_find(irc
->otr
->us
, u
->bu
->handle
, u
->bu
->ic
->acc
->user
,
1073 u
->bu
->ic
->acc
->prpl
->name
, 0, NULL
, NULL
, NULL
);
1075 irc_rootmsg(irc
, "no otr context with %s", args
[2]);
1079 if(ctx
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
) {
1080 irc_rootmsg(irc
, "active otr connection with %s, terminate it first", args
[2]);
1084 s
= g_strdup_printf("about to forget otr data about %s, are you sure?", args
[2]);
1085 p
= g_malloc(sizeof(pair_t
));
1090 query_add(irc
, NULL
, s
, yes_forget_context
, NULL
, NULL
, p
);
1094 else if(!strcmp(args
[1], "key"))
1099 key
= match_privkey(irc
, ((const char **)args
)+2);
1101 /* match_privkey does error messages */
1105 s
= g_strdup_printf("about to forget the private key for %s/%s, are you sure?",
1106 key
->accountname
, key
->protocol
);
1107 query_add(irc
, NULL
, s
, yes_forget_key
, NULL
, NULL
, key
);
1113 irc_rootmsg(irc
, "otr %s: unknown subcommand \"%s\", see \x02help otr forget\x02",
1119 /*** local helpers / subroutines: ***/
1121 /* Socialist Millionaires' Protocol */
1122 void otr_handle_smp(struct im_connection
*ic
, const char *handle
, OtrlTLV
*tlvs
)
1124 irc_t
*irc
= ic
->bee
->ui_data
;
1125 OtrlUserState us
= irc
->otr
->us
;
1126 OtrlMessageAppOps
*ops
= &otr_ops
;
1127 OtrlTLV
*tlv
= NULL
;
1128 ConnContext
*context
;
1129 NextExpectedSMP nextMsg
;
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
);
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
);
1144 nextMsg
= context
->smstate
->nextExpected
;
1146 if (context
->smstate
->sm_prog_state
== OTRL_SMP_PROG_CHEATED
) {
1147 irc_rootmsg(irc
, "smp %s: opponent violated protocol, aborting",
1149 otrl_message_abort_smp(us
, ops
, u
->bu
->ic
, context
);
1150 otrl_sm_state_free(context
->smstate
);
1154 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP1Q
);
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
);
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
,
1164 irc_rootmsg(irc
, "smp: respond with \x02otr smp %s <answer>\x02",
1167 /* smp stays in EXPECT1 until user responds */
1170 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP1
);
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
);
1177 irc_rootmsg(irc
, "smp: initiated by %s"
1178 " - respond with \x02otr smp %s <secret>\x02",
1180 /* smp stays in EXPECT1 until user responds */
1183 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP2
);
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
);
1190 /* SMP2 received, otrl_message_receiving will have sent SMP3 */
1191 context
->smstate
->nextExpected
= OTRL_SMP_EXPECT4
;
1194 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP3
);
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
);
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",
1207 irc_rootmsg(irc
, "smp %s: secrets proved equal, fingerprint trusted",
1211 if(context
->smstate
->received_question
) {
1212 irc_rootmsg(irc
, "smp %s: wrong answer, you are not trusted",
1215 irc_rootmsg(irc
, "smp %s: secrets did not match, fingerprint not trusted",
1219 otrl_sm_state_free(context
->smstate
);
1220 /* smp is in back in EXPECT1 */
1223 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP4
);
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
);
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",
1235 irc_rootmsg(irc
, "smp %s: secrets did not match, fingerprint not trusted",
1238 otrl_sm_state_free(context
->smstate
);
1239 /* smp is in back in EXPECT1 */
1242 tlv
= otrl_tlv_find(tlvs
, OTRL_TLV_SMP_ABORT
);
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 */
1250 /* combined handler for the 'otr smp' and 'otr smpq' commands */
1251 void otr_smp_or_smpq(irc_t
*irc
, const char *nick
, const char *question
,
1257 u
= irc_user_by_name(irc
, nick
);
1258 if(!u
|| !u
->bu
|| !u
->bu
->ic
) {
1259 irc_rootmsg(irc
, "%s: unknown user", nick
);
1262 if(!(u
->bu
->flags
& BEE_USER_ONLINE
)) {
1263 irc_rootmsg(irc
, "%s is offline", nick
);
1267 ctx
= otrl_context_find(irc
->otr
->us
, u
->bu
->handle
,
1268 u
->bu
->ic
->acc
->user
, u
->bu
->ic
->acc
->prpl
->name
, 0, NULL
, NULL
, NULL
);
1269 if(!ctx
|| ctx
->msgstate
!= OTRL_MSGSTATE_ENCRYPTED
) {
1270 irc_rootmsg(irc
, "smp: otr inactive with %s, try \x02otr connect"
1271 " %s\x02", nick
, nick
);
1275 if(ctx
->smstate
->nextExpected
!= OTRL_SMP_EXPECT1
) {
1276 log_message(LOGLVL_INFO
,
1277 "SMP already in phase %d, sending abort before reinitiating",
1278 ctx
->smstate
->nextExpected
+1);
1279 otrl_message_abort_smp(irc
->otr
->us
, &otr_ops
, u
->bu
->ic
, ctx
);
1280 otrl_sm_state_free(ctx
->smstate
);
1284 /* this was 'otr smpq', just initiate */
1285 irc_rootmsg(irc
, "smp: initiating with %s...", u
->nick
);
1286 otrl_message_initiate_smp_q(irc
->otr
->us
, &otr_ops
, u
->bu
->ic
, ctx
,
1287 question
, (unsigned char *)secret
, strlen(secret
));
1288 /* smp is now in EXPECT2 */
1290 /* this was 'otr smp', initiate or reply */
1291 /* warning: the following assumes that smstates are cleared whenever an SMP
1292 is completed or aborted! */
1293 if(ctx
->smstate
->secret
== NULL
) {
1294 irc_rootmsg(irc
, "smp: initiating with %s...", u
->nick
);
1295 otrl_message_initiate_smp(irc
->otr
->us
, &otr_ops
,
1296 u
->bu
->ic
, ctx
, (unsigned char *)secret
, strlen(secret
));
1297 /* smp is now in EXPECT2 */
1299 /* if we're still in EXPECT1 but smstate is initialized, we must have
1300 received the SMP1, so let's issue a response */
1301 irc_rootmsg(irc
, "smp: responding to %s...", u
->nick
);
1302 otrl_message_respond_smp(irc
->otr
->us
, &otr_ops
,
1303 u
->bu
->ic
, ctx
, (unsigned char *)secret
, strlen(secret
));
1304 /* smp is now in EXPECT3 */
1309 /* helper to assert that account and protocol names given to ops below always
1310 match the im_connection passed through as opdata */
1311 struct im_connection
*check_imc(void *opdata
, const char *accountname
,
1312 const char *protocol
)
1314 struct im_connection
*ic
= (struct im_connection
*)opdata
;
1316 if (strcmp(accountname
, ic
->acc
->user
) != 0) {
1317 log_message(LOGLVL_WARNING
,
1318 "otr: internal account name mismatch: '%s' vs '%s'",
1319 accountname
, ic
->acc
->user
);
1321 if (strcmp(protocol
, ic
->acc
->prpl
->name
) != 0) {
1322 log_message(LOGLVL_WARNING
,
1323 "otr: internal protocol name mismatch: '%s' vs '%s'",
1324 protocol
, ic
->acc
->prpl
->name
);
1330 irc_user_t
*peeruser(irc_t
*irc
, const char *handle
, const char *protocol
)
1334 for(l
=irc
->b
->users
; l
; l
= l
->next
) {
1335 bee_user_t
*bu
= l
->data
;
1337 if(!bu
->ui_data
|| !bu
->ic
|| !bu
->handle
)
1339 prpl
= bu
->ic
->acc
->prpl
;
1340 if(strcmp(prpl
->name
, protocol
) == 0
1341 && prpl
->handle_cmp(bu
->handle
, handle
) == 0) {
1353 if(x
>='a' && x
<='f')
1355 else if(x
>='0' && x
<='9')
1363 const char *peernick(irc_t
*irc
, const char *handle
, const char *protocol
)
1365 static char fallback
[512];
1367 irc_user_t
*u
= peeruser(irc
, handle
, protocol
);
1371 g_snprintf(fallback
, 511, "%s/%s", handle
, protocol
);
1376 void otr_update_uflags(ConnContext
*context
, irc_user_t
*u
)
1380 if(context
->active_fingerprint
) {
1381 u
->flags
|= IRC_USER_OTR_ENCRYPTED
;
1383 trust
= context
->active_fingerprint
->trust
;
1384 if(trust
&& trust
[0])
1385 u
->flags
|= IRC_USER_OTR_TRUSTED
;
1387 u
->flags
&= ~IRC_USER_OTR_TRUSTED
;
1389 u
->flags
&= ~IRC_USER_OTR_ENCRYPTED
;
1393 int otr_update_modeflags(irc_t
*irc
, irc_user_t
*u
)
1398 void show_fingerprints(irc_t
*irc
, ConnContext
*ctx
)
1405 for(fp
=&ctx
->fingerprint_root
; fp
; fp
=fp
->next
) {
1406 if(!fp
->fingerprint
)
1409 otrl_privkey_hash_to_human(human
, fp
->fingerprint
);
1410 if(!fp
->trust
|| fp
->trust
[0] == '\0') {
1415 if(fp
== ctx
->active_fingerprint
) {
1416 irc_rootmsg(irc
, " \x02%s (%s)\x02", human
, trust
);
1418 irc_rootmsg(irc
, " %s (%s)", human
, trust
);
1422 irc_rootmsg(irc
, " (none)");
1425 Fingerprint
*match_fingerprint(irc_t
*irc
, ConnContext
*ctx
, const char **args
)
1427 Fingerprint
*fp
, *fp2
;
1429 char prefix
[45], *p
;
1433 /* assemble the args into a prefix in standard "human" form */
1436 for(i
=0; args
[i
]; i
++) {
1437 for(j
=0; args
[i
][j
]; j
++) {
1438 char c
= toupper(args
[i
][j
]);
1441 irc_rootmsg(irc
, "too many fingerprint digits given, expected at most 40");
1445 if( (c
>='A' && c
<='F') || (c
>='0' && c
<='9') ) {
1448 irc_rootmsg(irc
, "invalid hex digit '%c' in block %d", args
[i
][j
], i
+1);
1459 /* find first fingerprint with the given prefix */
1461 for(fp
=&ctx
->fingerprint_root
; fp
; fp
=fp
->next
) {
1462 if(!fp
->fingerprint
)
1464 otrl_privkey_hash_to_human(human
, fp
->fingerprint
);
1465 if(!strncmp(prefix
, human
, n
))
1469 irc_rootmsg(irc
, "%s: no match", prefix
);
1473 /* make sure the match, if any, is unique */
1474 for(fp2
=fp
->next
; fp2
; fp2
=fp2
->next
) {
1475 if(!fp2
->fingerprint
)
1477 otrl_privkey_hash_to_human(human
, fp2
->fingerprint
);
1478 if(!strncmp(prefix
, human
, n
))
1482 irc_rootmsg(irc
, "%s: multiple matches", prefix
);
1489 OtrlPrivKey
*match_privkey(irc_t
*irc
, const char **args
)
1491 OtrlPrivKey
*k
, *k2
;
1493 char prefix
[45], *p
;
1497 /* assemble the args into a prefix in standard "human" form */
1500 for(i
=0; args
[i
]; i
++) {
1501 for(j
=0; args
[i
][j
]; j
++) {
1502 char c
= toupper(args
[i
][j
]);
1505 irc_rootmsg(irc
, "too many fingerprint digits given, expected at most 40");
1509 if( (c
>='A' && c
<='F') || (c
>='0' && c
<='9') ) {
1512 irc_rootmsg(irc
, "invalid hex digit '%c' in block %d", args
[i
][j
], i
+1);
1523 /* find first key which matches the given prefix */
1525 for(k
=irc
->otr
->us
->privkey_root
; k
; k
=k
->next
) {
1526 p
= otrl_privkey_fingerprint(irc
->otr
->us
, human
, k
->accountname
, k
->protocol
);
1527 if(!p
) /* gah! :-P */
1529 if(!strncmp(prefix
, human
, n
))
1533 irc_rootmsg(irc
, "%s: no match", prefix
);
1537 /* make sure the match, if any, is unique */
1538 for(k2
=k
->next
; k2
; k2
=k2
->next
) {
1539 p
= otrl_privkey_fingerprint(irc
->otr
->us
, human
, k2
->accountname
, k2
->protocol
);
1540 if(!p
) /* gah! :-P */
1542 if(!strncmp(prefix
, human
, n
))
1546 irc_rootmsg(irc
, "%s: multiple matches", prefix
);
1553 void show_general_otr_info(irc_t
*irc
)
1560 /* list all privkeys (including ones being generated) */
1561 irc_rootmsg(irc
, "\x1fprivate keys:\x1f");
1562 for(key
=irc
->otr
->us
->privkey_root
; key
; key
=key
->next
) {
1565 switch(key
->pubkey_type
) {
1566 case OTRL_PUBKEY_TYPE_DSA
:
1567 irc_rootmsg(irc
, " %s/%s - DSA", key
->accountname
, key
->protocol
);
1570 irc_rootmsg(irc
, " %s/%s - type %d", key
->accountname
, key
->protocol
,
1574 /* No, it doesn't make much sense to search for the privkey again by
1575 account/protocol, but libotr currently doesn't provide a direct routine
1576 for hashing a given 'OtrlPrivKey'... */
1577 hash
= otrl_privkey_fingerprint(irc
->otr
->us
, human
, key
->accountname
, key
->protocol
);
1578 if(hash
) /* should always succeed */
1579 irc_rootmsg(irc
, " %s", human
);
1581 if(irc
->otr
->sent_accountname
) {
1582 irc_rootmsg(irc
, " %s/%s - DSA", irc
->otr
->sent_accountname
,
1583 irc
->otr
->sent_protocol
);
1584 irc_rootmsg(irc
, " (being generated)");
1586 for(kg
=irc
->otr
->todo
; kg
; kg
=kg
->next
) {
1587 irc_rootmsg(irc
, " %s/%s - DSA", kg
->accountname
, kg
->protocol
);
1588 irc_rootmsg(irc
, " (queued)");
1590 if(key
== irc
->otr
->us
->privkey_root
&&
1591 !irc
->otr
->sent_accountname
&&
1592 kg
== irc
->otr
->todo
)
1593 irc_rootmsg(irc
, " (none)");
1595 /* list all contexts */
1596 irc_rootmsg(irc
, "%s", "");
1597 irc_rootmsg(irc
, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
1598 for(ctx
=irc
->otr
->us
->context_root
; ctx
; ctx
=ctx
->next
) {\
1602 u
= peeruser(irc
, ctx
->username
, ctx
->protocol
);
1604 userstring
= g_strdup_printf("%s/%s/%s (%s)",
1605 ctx
->username
, ctx
->protocol
, ctx
->accountname
, u
->nick
);
1607 userstring
= g_strdup_printf("%s/%s/%s",
1608 ctx
->username
, ctx
->protocol
, ctx
->accountname
);
1610 if(ctx
->msgstate
== OTRL_MSGSTATE_ENCRYPTED
) {
1611 irc_rootmsg(irc
, " \x02%s\x02", userstring
);
1613 irc_rootmsg(irc
, " %s", userstring
);
1618 if(ctx
== irc
->otr
->us
->context_root
)
1619 irc_rootmsg(irc
, " (none)");
1622 void show_otr_context_info(irc_t
*irc
, ConnContext
*ctx
)
1624 switch(ctx
->otr_offer
) {
1626 irc_rootmsg(irc
, " otr offer status: none sent");
1629 irc_rootmsg(irc
, " otr offer status: awaiting reply");
1631 case OFFER_ACCEPTED
:
1632 irc_rootmsg(irc
, " otr offer status: accepted our offer");
1634 case OFFER_REJECTED
:
1635 irc_rootmsg(irc
, " otr offer status: ignored our offer");
1638 irc_rootmsg(irc
, " otr offer status: %d", ctx
->otr_offer
);
1641 switch(ctx
->msgstate
) {
1642 case OTRL_MSGSTATE_PLAINTEXT
:
1643 irc_rootmsg(irc
, " connection state: cleartext");
1645 case OTRL_MSGSTATE_ENCRYPTED
:
1646 irc_rootmsg(irc
, " connection state: encrypted (v%d)", ctx
->protocol_version
);
1648 case OTRL_MSGSTATE_FINISHED
:
1649 irc_rootmsg(irc
, " connection state: shut down");
1652 irc_rootmsg(irc
, " connection state: %d", ctx
->msgstate
);
1655 irc_rootmsg(irc
, " fingerprints: (bold=active)");
1656 show_fingerprints(irc
, ctx
);
1659 int keygen_in_progress(irc_t
*irc
, const char *handle
, const char *protocol
)
1663 if(!irc
->otr
->sent_accountname
|| !irc
->otr
->sent_protocol
)
1666 /* are we currently working on this key? */
1667 if(!strcmp(handle
, irc
->otr
->sent_accountname
) &&
1668 !strcmp(protocol
, irc
->otr
->sent_protocol
))
1671 /* do we have it queued for later? */
1672 for(kg
=irc
->otr
->todo
; kg
; kg
=kg
->next
) {
1673 if(!strcmp(handle
, kg
->accountname
) &&
1674 !strcmp(protocol
, kg
->protocol
))
1681 void otr_keygen(irc_t
*irc
, const char *handle
, const char *protocol
)
1683 /* do nothing if a key for the requested account is already being generated */
1684 if(keygen_in_progress(irc
, handle
, protocol
))
1687 /* see if we already have a keygen child running. if not, start one and put a
1688 handler on its output. */
1689 if(!irc
->otr
->keygen
|| waitpid(irc
->otr
->keygen
, NULL
, WNOHANG
)) {
1694 if(pipe(to
) < 0 || pipe(from
) < 0) {
1695 irc_rootmsg(irc
, "otr keygen: couldn't create pipe: %s", strerror(errno
));
1699 tof
= fdopen(to
[1], "w");
1700 fromf
= fdopen(from
[0], "r");
1701 if(!tof
|| !fromf
) {
1702 irc_rootmsg(irc
, "otr keygen: couldn't streamify pipe: %s", strerror(errno
));
1708 irc_rootmsg(irc
, "otr keygen: couldn't fork: %s", strerror(errno
));
1714 signal(SIGTERM
, exit
);
1715 keygen_child_main(irc
->otr
->us
, to
[0], from
[1]);
1719 irc
->otr
->keygen
= p
;
1721 irc
->otr
->from
= fromf
;
1722 irc
->otr
->sent_accountname
= NULL
;
1723 irc
->otr
->sent_protocol
= NULL
;
1724 irc
->otr
->todo
= NULL
;
1725 b_input_add(from
[0], B_EV_IO_READ
, keygen_finish_handler
, irc
);
1728 /* is the keygen slave currently working? */
1729 if(irc
->otr
->sent_accountname
) {
1730 /* enqueue our job for later transmission */
1731 kg_t
**kg
= &irc
->otr
->todo
;
1734 *kg
= g_new0(kg_t
, 1);
1735 (*kg
)->accountname
= g_strdup(handle
);
1736 (*kg
)->protocol
= g_strdup(protocol
);
1738 /* send our job over and remember it */
1739 fprintf(irc
->otr
->to
, "%s\n%s\n", handle
, protocol
);
1740 fflush(irc
->otr
->to
);
1741 irc
->otr
->sent_accountname
= g_strdup(handle
);
1742 irc
->otr
->sent_protocol
= g_strdup(protocol
);
1746 void keygen_child_main(OtrlUserState us
, int infd
, int outfd
)
1748 FILE *input
, *output
;
1749 char filename
[128], accountname
[512], protocol
[512];
1753 input
= fdopen(infd
, "r");
1754 output
= fdopen(outfd
, "w");
1756 while(!feof(input
) && !ferror(input
) && !feof(output
) && !ferror(output
)) {
1757 myfgets(accountname
, 512, input
);
1758 myfgets(protocol
, 512, input
);
1760 strncpy(filename
, "/tmp/bitlbee-XXXXXX", 128);
1761 tempfd
= mkstemp(filename
);
1764 e
= otrl_privkey_generate(us
, filename
, accountname
, protocol
);
1766 fprintf(output
, "\n"); /* this means failure */
1767 fprintf(output
, "otr keygen: %s\n", gcry_strerror(e
));
1770 fprintf(output
, "%s\n", filename
);
1771 fprintf(output
, "otr keygen for %s/%s complete\n", accountname
, protocol
);
1780 gboolean
keygen_finish_handler(gpointer data
, gint fd
, b_input_condition cond
)
1782 irc_t
*irc
= (irc_t
*)data
;
1783 char filename
[512], msg
[512];
1785 myfgets(filename
, 512, irc
->otr
->from
);
1786 myfgets(msg
, 512, irc
->otr
->from
);
1788 irc_rootmsg(irc
, "%s", msg
);
1790 if(strsane(irc
->user
->nick
)) {
1791 char *kf
= g_strdup_printf("%s%s.otr_keys", global
.conf
->configdir
, irc
->user
->nick
);
1792 char *tmp
= g_strdup_printf("%s.new", kf
);
1793 copyfile(filename
, tmp
);
1796 otrl_privkey_read(irc
->otr
->us
, kf
);
1800 otrl_privkey_read(irc
->otr
->us
, filename
);
1805 /* forget this job */
1806 g_free(irc
->otr
->sent_accountname
);
1807 g_free(irc
->otr
->sent_protocol
);
1808 irc
->otr
->sent_accountname
= NULL
;
1809 irc
->otr
->sent_protocol
= NULL
;
1811 /* see if there are any more in the queue */
1812 if(irc
->otr
->todo
) {
1813 kg_t
*p
= irc
->otr
->todo
;
1814 /* send the next one over */
1815 fprintf(irc
->otr
->to
, "%s\n%s\n", p
->accountname
, p
->protocol
);
1816 fflush(irc
->otr
->to
);
1817 irc
->otr
->sent_accountname
= p
->accountname
;
1818 irc
->otr
->sent_protocol
= p
->protocol
;
1819 irc
->otr
->todo
= p
->next
;
1821 return TRUE
; /* keep watching */
1823 /* okay, the slave is idle now, so kill him */
1824 fclose(irc
->otr
->from
);
1825 fclose(irc
->otr
->to
);
1826 irc
->otr
->from
= irc
->otr
->to
= NULL
;
1827 kill(irc
->otr
->keygen
, SIGTERM
);
1828 waitpid(irc
->otr
->keygen
, NULL
, 0);
1829 irc
->otr
->keygen
= 0;
1830 return FALSE
; /* unregister ourselves */
1834 void copyfile(const char *a
, const char *b
)
1840 fda
= open(a
, O_RDONLY
);
1841 fdb
= open(b
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
1843 while((n
=read(fda
, buf
, 1024)) > 0)
1850 void myfgets(char *s
, int size
, FILE *stream
)
1852 if(!fgets(s
, size
, stream
)) {
1856 if(n
>0 && s
[n
-1] == '\n')
1861 void yes_keygen(void *data
)
1863 account_t
*acc
= (account_t
*)data
;
1864 irc_t
*irc
= acc
->bee
->ui_data
;
1866 if(keygen_in_progress(irc
, acc
->user
, acc
->prpl
->name
)) {
1867 irc_rootmsg(irc
, "keygen for %s/%s already in progress",
1868 acc
->user
, acc
->prpl
->name
);
1870 irc_rootmsg(irc
, "starting background keygen for %s/%s",
1871 acc
->user
, acc
->prpl
->name
);
1872 irc_rootmsg(irc
, "you will be notified when it completes");
1873 otr_keygen(irc
, acc
->user
, acc
->prpl
->name
);
1877 /* check whether a string is safe to use in a path component */
1878 int strsane(const char *s
)
1880 return strpbrk(s
, "/\\") == NULL
;
1883 /* vim: set noet ts=4 sw=4: */