- Timestamp:
- 2008-02-15T09:27:26Z (17 years ago)
- Branches:
- master
- Children:
- 27db433
- Parents:
- 6c91e6e
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
otr.c
r6c91e6e r522a00f 103 103 /** misc. helpers/subroutines: **/ 104 104 105 /* start background threadto generate a (new) key for a given account */105 /* start background process to generate a (new) key for a given account */ 106 106 void otr_keygen(irc_t *irc, const char *handle, const char *protocol); 107 107 108 /* keygen thread main func */ 109 gpointer otr_keygen_thread_func(gpointer data); 110 111 /* mainloop handler for when keygen thread finishes */ 108 /* mainloop handler for when a keygen finishes */ 112 109 gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond); 113 114 /* data to be passed to otr_keygen_thread_func */115 struct kgdata {116 irc_t *irc; /* access to OTR userstate */117 char *keyfile; /* free me! */118 const char *handle; /* don't free! */119 const char *protocol; /* don't free! */120 GMutex *mutex; /* lock for the 'done' flag, free me! */121 int done; /* is the thread done? */122 gcry_error_t result; /* return value of otrl_privkey_generate */123 };124 110 125 111 /* some yes/no handlers */ … … 172 158 void otr_init(void) 173 159 { 174 if(!g_thread_supported()) g_thread_init(NULL);175 160 OTRL_INIT; 176 161 … … 196 181 } 197 182 198 /* Notice on the otr_mutex:199 200 The incoming/outgoing message handlers try to lock the otr_mutex. If they succeed,201 this will prevent a concurrent keygen (possibly spawned by that very command)202 from messing up the userstate. If the lock fails, that means there already is203 a keygen in progress. Instead of blocking for an unknown time, they204 will bail out gracefully, informing the user of this temporary "coma".205 TODO: Hold back incoming/outgoing messages and process them when keygen completes?206 207 The other routines do not lock the otr_mutex themselves, it is done as a208 catch-all in the root command handler. Rationale:209 a) it's easy to code210 b) it makes it obvious that no command can get its userstate corrupted211 c) the "irc" struct is readily available there for feedback to the user212 */213 214 183 void otr_load(irc_t *irc) 215 184 { … … 217 186 account_t *a; 218 187 gcry_error_t e; 219 int eno;188 gcry_error_t enoent = gcry_error_from_errno(ENOENT); 220 189 221 190 log_message(LOGLVL_DEBUG, "otr_load '%s'", irc->nick); … … 223 192 g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, irc->nick); 224 193 e = otrl_privkey_read(irc->otr_us, s); 225 eno = gcry_error_code_to_errno(e); 226 if(e && eno!=ENOENT) { 227 log_message(LOGLVL_ERROR, "otr load: %s: %s", s, strerror(e)); 194 if(e && e!=enoent) { 195 irc_usermsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); 228 196 } 229 197 g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->nick); 230 198 e = otrl_privkey_read_fingerprints(irc->otr_us, s, NULL, NULL); 231 eno = gcry_error_code_to_errno(e); 232 if(e && eno!=ENOENT) { 233 log_message(LOGLVL_ERROR, "otr load: %s: %s", s, strerror(e)); 199 if(e && e!=enoent) { 200 irc_usermsg(irc, "otr load: %s: %s", s, gcry_strerror(e)); 234 201 } 235 202 … … 250 217 e = otrl_privkey_write_fingerprints(irc->otr_us, s); 251 218 if(e) { 252 log_message(LOGLVL_ERROR, "otr save: %s: %s", s,strerror(e));219 irc_usermsg(irc, "otr save: %s: %s", s, gcry_strerror(e)); 253 220 } 254 221 chmod(s, 0600); … … 302 269 char *colormsg; 303 270 304 if(!g_static_rec_mutex_trylock(&ic->irc->otr_mutex)) {305 user_t *u = user_findhandle(ic, handle);306 307 /* fallback for non-otr clients */308 if(u && !u->encrypted) {309 return g_strdup(msg);310 }311 312 irc_usermsg(ic->irc, "encrypted msg from %s during keygen - dropped",313 peernick(ic->irc, handle, ic->acc->prpl->name));314 return NULL;315 }316 317 271 ignore_msg = otrl_message_receiving(ic->irc->otr_us, &global.otr_ops, ic, 318 272 ic->acc->user, ic->acc->prpl->name, handle, msg, &newmsg, … … 323 277 if(ignore_msg) { 324 278 /* this was an internal OTR protocol message */ 325 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);326 279 return NULL; 327 280 } else if(!newmsg) { 328 281 /* this was a non-OTR message */ 329 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);330 282 return g_strdup(msg); 331 283 } else { … … 347 299 } 348 300 otrl_message_free(newmsg); 349 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);350 301 return colormsg; 351 302 } … … 358 309 ConnContext *ctx = NULL; 359 310 360 if(!g_static_rec_mutex_trylock(&ic->irc->otr_mutex)) {361 user_t *u = user_findhandle(ic, handle);362 363 /* Fallback for non-otr clients.364 Yes, this better shouldn't send private stuff in the clear... */365 if(u && !u->encrypted) {366 return ic->acc->prpl->buddy_msg(ic, (char *)handle, (char *)msg, flags);367 }368 369 irc_usermsg(ic->irc, "encrypted message to %s during keygen - not sent",370 peernick(ic->irc, handle, ic->acc->prpl->name));371 return 1;372 }373 374 311 st = otrl_message_sending(ic->irc->otr_us, &global.otr_ops, ic, 375 312 ic->acc->user, ic->acc->prpl->name, handle, 376 313 msg, NULL, &otrmsg, NULL, NULL); 377 314 if(st) { 378 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);379 315 return st; 380 316 } … … 387 323 if(!ctx) { 388 324 otrl_message_free(otrmsg); 389 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);390 325 return 1; 391 326 } … … 399 334 } 400 335 401 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);402 336 return st; 403 337 } … … 1483 1417 void otr_keygen(irc_t *irc, const char *handle, const char *protocol) 1484 1418 { 1485 GError *err;1486 GThread *thr;1487 struct kgdata *kg;1488 gint ev;1489 1419 1490 1420 irc_usermsg(irc, "generating new private key for %s/%s...", handle, protocol); 1491 1492 kg = g_new0(struct kgdata, 1); 1493 if(!kg) { 1494 irc_usermsg(irc, "otr keygen failed: out of memory"); 1495 return; 1496 } 1497 1498 /* Assemble the job description to be passed to thread and handler */ 1499 kg->irc = irc; 1500 kg->keyfile = g_strdup_printf("%s%s.otr_keys", global.conf->configdir, kg->irc->nick); 1501 if(!kg->keyfile) { 1502 irc_usermsg(irc, "otr keygen failed: out of memory"); 1503 g_free(kg); 1504 return; 1505 } 1506 kg->handle = handle; 1507 kg->protocol = protocol; 1508 kg->mutex = g_mutex_new(); 1509 if(!kg->mutex) { 1510 irc_usermsg(irc, "otr keygen failed: couldn't create mutex"); 1511 g_free(kg->keyfile); 1512 g_free(kg); 1513 return; 1514 } 1515 kg->done = 0; 1516 1517 /* Poll for completion of the thread periodically. I would have preferred 1518 to just wait on a pipe but this way it's portable to Windows. *sigh* 1519 */ 1520 ev = b_timeout_add(1000, &keygen_finish_handler, kg); 1521 if(!ev) { 1522 irc_usermsg(irc, "otr keygen failed: couldn't register timeout"); 1523 g_free(kg->keyfile); 1524 g_mutex_free(kg->mutex); 1525 g_free(kg); 1526 return; 1527 } 1528 1529 thr = g_thread_create(&otr_keygen_thread_func, kg, FALSE, &err); 1530 if(!thr) { 1531 irc_usermsg(irc, "otr keygen failed: %s", err->message); 1532 g_free(kg->keyfile); 1533 g_mutex_free(kg->mutex); 1534 g_free(kg); 1535 b_event_remove(ev); 1536 } 1537 } 1538 1539 gpointer otr_keygen_thread_func(gpointer data) 1540 { 1541 struct kgdata *kg = (struct kgdata *)data; 1542 1543 /* lock OTR subsystem and do the work */ 1544 g_static_rec_mutex_lock(&kg->irc->otr_mutex); 1545 kg->result = otrl_privkey_generate(kg->irc->otr_us, kg->keyfile, kg->handle, 1421 irc_usermsg(irc, "n/a: not implemented"); 1422 return; 1423 1424 /* see if we already have a keygen child running. if not, start one and put a 1425 handler on its output. 1426 1427 b_input_add(fd, GAIM_INPUT_READ, keygen_finish_handler, NULL); 1428 1429 generate a fresh temp file name for our new key and save our current keys to it. 1430 send the child filename and accountname/protocol for the new key 1431 increment 'ntodo' */ 1432 1433 /* in the child: 1434 read filename, accountname, protocol from input, and start work: 1435 1436 result = otrl_privkey_generate(kg->irc->otr_us, kg->keyfile, kg->handle, 1546 1437 kg->protocol); 1547 chmod(kg->keyfile, 0600); 1548 g_static_rec_mutex_unlock(&kg->irc->otr_mutex); 1549 /* OTR enabled again */ 1550 1551 /* notify mainloop */ 1552 g_mutex_lock(kg->mutex); 1553 kg->done = 1; 1554 g_mutex_unlock(kg->mutex); 1555 1556 return NULL; 1438 1439 when done, send filename, accountname, and protocol to output. */ 1440 1557 1441 } 1558 1442 1559 1443 gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond) 1560 1444 { 1561 struct kgdata *kg = (struct kgdata *)data; 1562 int done; 1563 1564 g_mutex_lock(kg->mutex); 1565 done = kg->done; 1566 g_mutex_unlock(kg->mutex); 1567 if(kg->done) { 1568 if(kg->result) { 1569 irc_usermsg(kg->irc, "otr keygen: %s", strerror(kg->result)); 1570 } else { 1445 /* in the handler: 1446 read filename, accountname, and protocol from child output 1447 print a message to the user 1571 1448 irc_usermsg(kg->irc, "otr keygen for %s/%s complete", kg->handle, kg->protocol); 1572 } 1573 g_free(kg->keyfile); 1574 g_mutex_free(kg->mutex); 1575 g_free(kg); 1576 return FALSE; /* unregister timeout */ 1577 } 1578 1579 return TRUE; /* still working, continue checking */ 1449 load the file into userstate 1450 call otr_save. 1451 remove the tempfile. 1452 decrement 'ntodo' 1453 if 'ntodo' reaches zero, send SIGTERM to the child, waitpid for it, return FALSE */ 1454 1455 return TRUE; /* still working, keep watching */ 1580 1456 } 1581 1457
Note: See TracChangeset
for help on using the changeset viewer.