1 /*
2 * Off-the-Record Messaging library
3 * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits,
4 * Chris Alexander, Willy Lew, Lisa Du,
5 * Nikita Borisov
6 * <otr@cypherpunks.ca>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of version 2.1 of the GNU Lesser General
10 * Public License as published by the Free Software Foundation.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /* system headers */
23 #include <stdlib.h>
24 #include <assert.h>
25
26 /* libgcrypt headers */
27 #include <gcrypt.h>
28
29 /* libotr headers */
30 #include "context.h"
31 #include "instag.h"
32
33 #if OTRL_DEBUGGING
34 #include <stdio.h>
35
36 void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth);
37 void otrl_sm_dump(FILE *f, const OtrlSMState *sm);
38
39 /* Dump the contents of a context to the FILE *f. */
otrl_context_dump(FILE * f,const ConnContext * context)40 void otrl_context_dump(FILE *f, const ConnContext *context)
41 {
42 const Fingerprint *fing;
43
44 fprintf(f, "Context %p:\n\n", context);
45
46 fprintf(f, " Username: %s\n", context->username);
47 fprintf(f, " Accountname: %s\n", context->accountname);
48 fprintf(f, " Protocol: %s\n\n", context->protocol);
49 fprintf(f, " Master context: %p%s\n", context->m_context,
50 context->m_context == context ? " IS MASTER" : "");
51 fprintf(f, " Recent recv child: %p\n", context->recent_rcvd_child);
52 fprintf(f, " Recent sent child: %p\n", context->recent_sent_child);
53 fprintf(f, " Recent child: %p\n\n", context->recent_child);
54 fprintf(f, " Our instance: %08x\n", context->our_instance);
55 fprintf(f, " Their instance: %08x\n\n", context->their_instance);
56 fprintf(f, " Msgstate: %d (%s)\n\n", context->msgstate,
57 context->msgstate == OTRL_MSGSTATE_PLAINTEXT ? "PLAINTEXT" :
58 context->msgstate == OTRL_MSGSTATE_ENCRYPTED ? "ENCRYPTED" :
59 context->msgstate == OTRL_MSGSTATE_FINISHED ? "FINISHED" :
60 "INVALID");
61 otrl_auth_dump(f, &context->auth);
62 fprintf(f, "\n Fingerprints:\n");
63 for (fing = context->fingerprint_root.next; fing; fing = fing->next) {
64 fprintf(f, " %p ", fing);
65 if (fing->fingerprint == NULL) {
66 fprintf(f, "(null)");
67 } else {
68 int i;
69 for (i=0;i<20;++i) {
70 fprintf(f, "%02x", fing->fingerprint[i]);
71 }
72 }
73 fprintf(f, " %p", fing->context);
74 if (fing->trust && fing->trust[0]) {
75 fprintf(f, " %s", fing->trust);
76 }
77 fprintf(f, "\n");
78 }
79 fprintf(f, "\n Active fingerprint: %p\n\n", context->active_fingerprint);
80 fprintf(f, " Protocol version: %d\n", context->protocol_version);
81 fprintf(f, " OTR offer: %d (%s)\n\n", context->otr_offer,
82 context->otr_offer == OFFER_NOT ? "NOT" :
83 context->otr_offer == OFFER_SENT ? "SENT" :
84 context->otr_offer == OFFER_REJECTED ? "REJECTED" :
85 context->otr_offer == OFFER_ACCEPTED ? "ACCEPTED" :
86 "INVALID");
87
88 fprintf(f, " Application data: %p\n", context->app_data);
89 if (context->smstate == NULL) {
90 fprintf(f, " SM state: NULL\n");
91 } else {
92 otrl_sm_dump(f, context->smstate);
93 }
94 fprintf(f, "\n");
95 }
96
97 /* Dump the master context of this context, and all of its children. */
otrl_context_siblings_dump(FILE * f,const ConnContext * context)98 void otrl_context_siblings_dump(FILE *f, const ConnContext *context)
99 {
100 const ConnContext *citer;
101 for (citer = context->m_context;
102 citer && citer->m_context == context->m_context;
103 citer = citer->next) {
104 if (citer == context) {
105 fprintf(f, "*** ");
106 }
107 otrl_context_dump(f, citer);
108 }
109 }
110
111 /* Dump all contexts. */
otrl_context_all_dump(FILE * f,OtrlUserState us)112 void otrl_context_all_dump(FILE *f, OtrlUserState us)
113 {
114 const ConnContext *citer;
115 unsigned int ctxnum = 1;
116 for (citer = us->context_root; citer; citer = citer->next, ++ctxnum) {
117 fprintf(f, "%u. ", ctxnum);
118 otrl_context_dump(f, citer);
119 }
120 }
121 #endif
122
123 /* Create a new connection context. */
new_context(const char * user,const char * accountname,const char * protocol)124 static ConnContext * new_context(const char * user, const char * accountname,
125 const char * protocol)
126 {
127 ConnContext * context;
128 OtrlSMState *smstate;
129
130 context = malloc(sizeof(ConnContext));
131 assert(context != NULL);
132
133 context->username = strdup(user);
134 context->accountname = strdup(accountname);
135 context->protocol = strdup(protocol);
136
137 context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
138 otrl_auth_new(context);
139
140 smstate = malloc(sizeof(OtrlSMState));
141 assert(smstate != NULL);
142 otrl_sm_state_new(smstate);
143 context->smstate = smstate;
144
145 context->our_instance = 0;
146 context->their_instance = OTRL_INSTAG_MASTER;
147 context->fingerprint_root.fingerprint = NULL;
148 context->fingerprint_root.context = context;
149 context->fingerprint_root.next = NULL;
150 context->fingerprint_root.tous = NULL;
151 context->active_fingerprint = NULL;
152 memset(context->sessionid, 0, 20);
153 context->sessionid_len = 0;
154 context->protocol_version = 0;
155 context->otr_offer = OFFER_NOT;
156 context->app_data = NULL;
157 context->app_data_free = NULL;
158 context->context_priv = otrl_context_priv_new();
159 assert(context->context_priv != NULL);
160 context->next = NULL;
161 context->m_context = context;
162 context->recent_rcvd_child = NULL;
163 context->recent_sent_child = NULL;
164 context->recent_child = NULL;
165
166 return context;
167 }
168
otrl_context_find_recent_instance(ConnContext * context,otrl_instag_t recent_instag)169 ConnContext * otrl_context_find_recent_instance(ConnContext * context,
170 otrl_instag_t recent_instag) {
171 ConnContext * m_context;
172
173 if (!context) return NULL;
174
175 m_context = context->m_context;
176
177 if (!m_context) return NULL;
178
179 switch(recent_instag) {
180 case OTRL_INSTAG_RECENT:
181 return m_context->recent_child;
182 case OTRL_INSTAG_RECENT_RECEIVED:
183 return m_context->recent_rcvd_child;
184 case OTRL_INSTAG_RECENT_SENT:
185 return m_context->recent_sent_child;
186 default:
187 return NULL;
188 }
189 }
190
191 /* Find the instance of this context that has the best security level,
192 and for which we have most recently received a message from. Note that most
193 recent in this case is limited to a one-second resolution. */
otrl_context_find_recent_secure_instance(ConnContext * context)194 ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context)
195 {
196 ConnContext *curp; /* for iteration */
197 ConnContext *m_context; /* master */
198 ConnContext *cresult = context; /* best so far */
199
200 if (!context) {
201 return cresult;
202 }
203
204 m_context = context->m_context;
205
206 for (curp = m_context; curp && curp->m_context == m_context;
207 curp = curp->next) {
208 int msgstate_improved = 0; /* 0 == same, 1 == improved */
209 int trust_improved = 0; /* (will immediately 'continue' if worse
210 * than) */
211
212 if (cresult->msgstate == curp->msgstate) {
213 msgstate_improved = 0;
214 } else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED ||
215 (cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
216 curp->msgstate == OTRL_MSGSTATE_FINISHED)) {
217 msgstate_improved = 1;
218 } else {
219 continue;
220 }
221
222
223 if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) ==
224 otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) {
225
226 trust_improved = 0;
227 } else if
228 (otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){
229
230 trust_improved = 1;
231 } else {
232 continue;
233 }
234
235 if (msgstate_improved || trust_improved ||
236 (!msgstate_improved && !trust_improved &&
237 curp->context_priv->lastrecv >=
238 cresult->context_priv->lastrecv)) {
239 cresult = curp;
240 }
241 }
242
243 return cresult;
244 }
245
246 /* Look up a connection context by name/account/protocol/instag from the given
247 * OtrlUserState. If add_if_missing is true, allocate and return a new
248 * context if one does not currently exist. In that event, call
249 * add_app_data(data, context) so that app_data and app_data_free can be
250 * filled in by the application, and set *addedp to 1.
251 * In the 'their_instance' field note that you can also specify a 'meta-
252 * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAG_RECENT,
253 * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */
otrl_context_find(OtrlUserState us,const char * user,const char * accountname,const char * protocol,otrl_instag_t their_instance,int add_if_missing,int * addedp,void (* add_app_data)(void * data,ConnContext * context),void * data)254 ConnContext * otrl_context_find(OtrlUserState us, const char *user,
255 const char *accountname, const char *protocol,
256 otrl_instag_t their_instance, int add_if_missing, int *addedp,
257 void (*add_app_data)(void *data, ConnContext *context), void *data)
258 {
259 ConnContext ** curp;
260 int usercmp = 1, acctcmp = 1, protocmp = 1;
261 if (addedp) *addedp = 0;
262 if (!user || !accountname || !protocol) return NULL;
263
264 for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
265 if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
266 (usercmp == 0 &&
267 (acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
268 (usercmp == 0 && acctcmp == 0 &&
269 (protocmp = strcmp((*curp)->protocol, protocol)) > 0) ||
270 (usercmp == 0 && acctcmp == 0 && protocmp == 0
271 && (their_instance < OTRL_MIN_VALID_INSTAG ||
272 ((*curp)->their_instance >= their_instance))))
273 /* We're at the right place in the list. We've either found
274 * it, or gone too far. */
275 break;
276 }
277
278 if (usercmp == 0 && acctcmp == 0 && protocmp == 0 && *curp &&
279 (their_instance < OTRL_MIN_VALID_INSTAG ||
280 (their_instance == (*curp)->their_instance))) {
281 /* Found one! */
282 if (their_instance >= OTRL_MIN_VALID_INSTAG ||
283 their_instance == OTRL_INSTAG_MASTER) {
284 return *curp;
285 }
286
287 /* We need to go back and check more values in the context */
288 switch(their_instance) {
289 case OTRL_INSTAG_BEST:
290 return otrl_context_find_recent_secure_instance(*curp);
291 case OTRL_INSTAG_RECENT:
292 case OTRL_INSTAG_RECENT_RECEIVED:
293 case OTRL_INSTAG_RECENT_SENT:
294 return otrl_context_find_recent_instance(*curp, their_instance);
295 default:
296 return NULL;
297 }
298 }
299
300 if (add_if_missing) {
301 ConnContext *newctx;
302 OtrlInsTag *our_instag = (OtrlInsTag *)otrl_instag_find(us, accountname,
303 protocol);
304
305 if (addedp) *addedp = 1;
306 newctx = new_context(user, accountname, protocol);
307 newctx->next = *curp;
308 if (*curp) {
309 (*curp)->tous = &(newctx->next);
310 }
311 *curp = newctx;
312 newctx->tous = curp;
313 if (add_app_data) {
314 add_app_data(data, *curp);
315 }
316
317 /* Initialize specified instance tags */
318 if (our_instag) {
319 newctx->our_instance = our_instag->instag;
320 }
321
322 if (their_instance >= OTRL_MIN_VALID_INSTAG ||
323 their_instance == OTRL_INSTAG_MASTER) {
324 newctx->their_instance = their_instance;
325 }
326
327 if (their_instance >= OTRL_MIN_VALID_INSTAG) {
328 newctx->m_context = otrl_context_find(us, user, accountname,
329 protocol, OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data);
330 }
331
332 if (their_instance == OTRL_INSTAG_MASTER) {
333 /* if we're adding a master, there are no children, so the most
334 * recent context is the one we add. */
335 newctx->recent_child = newctx;
336 newctx->recent_rcvd_child = newctx;
337 newctx->recent_sent_child = newctx;
338 }
339
340 return *curp;
341 }
342 return NULL;
343 }
344
345 /* Return true iff the given fingerprint is marked as trusted. */
otrl_context_is_fingerprint_trusted(Fingerprint * fprint)346 int otrl_context_is_fingerprint_trusted(Fingerprint *fprint) {
347 return fprint && fprint->trust && fprint->trust[0] != '\0';
348 }
349
350 /* This method gets called after sending or receiving a message, to
351 * update the master context's "recent context" pointers. */
otrl_context_update_recent_child(ConnContext * context,unsigned int sent_msg)352 void otrl_context_update_recent_child(ConnContext *context,
353 unsigned int sent_msg) {
354 ConnContext *m_context = context->m_context;
355
356 if (sent_msg) {
357 m_context->recent_sent_child = context;
358 } else {
359 m_context->recent_rcvd_child = context;
360 }
361
362 m_context->recent_child = context;
363
364 }
365
366 /* Find a fingerprint in a given context, perhaps adding it if not
367 * present. */
otrl_context_find_fingerprint(ConnContext * context,unsigned char fingerprint[20],int add_if_missing,int * addedp)368 Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
369 unsigned char fingerprint[20], int add_if_missing, int *addedp)
370 {
371 Fingerprint *f;
372 if (addedp) *addedp = 0;
373
374 if (!context || !context->m_context) return NULL;
375
376 context = context->m_context;
377
378 f = context->fingerprint_root.next;
379 while(f) {
380 if (!memcmp(f->fingerprint, fingerprint, 20)) return f;
381 f = f->next;
382 }
383
384 /* Didn't find it. */
385 if (add_if_missing) {
386 if (addedp) *addedp = 1;
387 f = malloc(sizeof(*f));
388 assert(f != NULL);
389 f->fingerprint = malloc(20);
390 assert(f->fingerprint != NULL);
391 memmove(f->fingerprint, fingerprint, 20);
392 f->context = context;
393 f->trust = NULL;
394 f->next = context->fingerprint_root.next;
395 if (f->next) {
396 f->next->tous = &(f->next);
397 }
398 context->fingerprint_root.next = f;
399 f->tous = &(context->fingerprint_root.next);
400 return f;
401 }
402 return NULL;
403 }
404
405 /* Set the trust level for a given fingerprint */
otrl_context_set_trust(Fingerprint * fprint,const char * trust)406 void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
407 {
408 if (fprint == NULL) return;
409
410 free(fprint->trust);
411 fprint->trust = trust ? strdup(trust) : NULL;
412 }
413
414 /* Force a context into the OTRL_MSGSTATE_FINISHED state. */
otrl_context_force_finished(ConnContext * context)415 void otrl_context_force_finished(ConnContext *context)
416 {
417 context->msgstate = OTRL_MSGSTATE_FINISHED;
418 otrl_auth_clear(&(context->auth));
419 context->active_fingerprint = NULL;
420 memset(context->sessionid, 0, 20);
421 context->sessionid_len = 0;
422 context->protocol_version = 0;
423 otrl_sm_state_free(context->smstate);
424 otrl_context_priv_force_finished(context->context_priv);
425 }
426
427 /* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
otrl_context_force_plaintext(ConnContext * context)428 void otrl_context_force_plaintext(ConnContext *context)
429 {
430 /* First clean up everything we'd need to do for the FINISHED state */
431 otrl_context_force_finished(context);
432
433 /* And just set the state properly */
434 context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
435 }
436
437 /* Forget a fingerprint (so long as it's not the active one. If it's a
438 * fingerprint_root, forget the whole context (as long as
439 * and_maybe_context is set, and it's PLAINTEXT). Also, if it's not
440 * the fingerprint_root, but it's the only fingerprint, and we're
441 * PLAINTEXT, forget the whole context if and_maybe_context is set. */
otrl_context_forget_fingerprint(Fingerprint * fprint,int and_maybe_context)442 void otrl_context_forget_fingerprint(Fingerprint *fprint,
443 int and_maybe_context)
444 {
445 ConnContext *context = fprint->context;
446 if (fprint == &(context->fingerprint_root)) {
447 if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
448 and_maybe_context) {
449 otrl_context_forget(context);
450 }
451 } else {
452 if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
453 context->active_fingerprint != fprint) {
454
455 free(fprint->fingerprint);
456 free(fprint->trust);
457 *(fprint->tous) = fprint->next;
458 if (fprint->next) {
459 fprint->next->tous = fprint->tous;
460 }
461 free(fprint);
462 if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
463 context->fingerprint_root.next == NULL &&
464 and_maybe_context) {
465 /* We just deleted the only fingerprint. Forget the
466 * whole thing. */
467 otrl_context_forget(context);
468 }
469 }
470 }
471 }
472
473 /* Forget a whole context, so long as it's PLAINTEXT. If a context has child
474 * instances, don't remove this instance unless children are also all in
475 * PLAINTEXT state. In this case, the children will also be removed.
476 * Returns 0 on success, 1 on failure. */
otrl_context_forget(ConnContext * context)477 int otrl_context_forget(ConnContext *context)
478 {
479 if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
480
481 if (context->their_instance == OTRL_INSTAG_MASTER) {
482 ConnContext *c_iter;
483
484 for (c_iter = context; c_iter &&
485 c_iter->m_context == context->m_context;
486 c_iter = c_iter->next) {
487 if (c_iter->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
488 }
489
490 c_iter = context->next;
491 while (c_iter && c_iter->m_context == context->m_context) {
492 if (!otrl_context_forget(c_iter)) {
493 c_iter = context->next;
494 } else {
495 return 1;
496 }
497 }
498
499 }
500
501 /* Just to be safe, force to plaintext. This also frees any
502 * extraneous data lying around. */
503 otrl_context_force_plaintext(context);
504
505 /* First free all the Fingerprints */
506 while(context->fingerprint_root.next) {
507 otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
508 }
509 /* Now free all the dynamic info here */
510 free(context->username);
511 free(context->accountname);
512 free(context->protocol);
513 free(context->smstate);
514 context->username = NULL;
515 context->accountname = NULL;
516 context->protocol = NULL;
517 context->smstate = NULL;
518
519 /* Free the application data, if it exists */
520 if (context->app_data && context->app_data_free) {
521 (context->app_data_free)(context->app_data);
522 context->app_data = NULL;
523 }
524
525 /* Fix the list linkages */
526 *(context->tous) = context->next;
527 if (context->next) {
528 context->next->tous = context->tous;
529 }
530
531 free(context);
532 return 0;
533 }
534
535 /* Forget all the contexts in a given OtrlUserState. */
otrl_context_forget_all(OtrlUserState us)536 void otrl_context_forget_all(OtrlUserState us)
537 {
538 ConnContext *c_iter;
539
540 for (c_iter = us->context_root; c_iter; c_iter = c_iter->next) {
541 otrl_context_force_plaintext(c_iter);
542 }
543
544 while (us->context_root) {
545 otrl_context_forget(us->context_root);
546 }
547 }
548