Changeset 522a00f


Ignore:
Timestamp:
2008-02-15T09:27:26Z (16 years ago)
Author:
Sven Moritz Hallberg <sm@…>
Branches:
master
Children:
27db433
Parents:
6c91e6e
Message:

remove thread-based keygen
replace it with a process-based stub

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    r6c91e6e r522a00f  
    2828#include "crypting.h"
    2929#include "ipc.h"
     30#include <sys/types.h>
     31#include <sys/wait.h>
    3032
    3133static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     
    133135
    134136        irc->otr_us = otrl_userstate_create();
    135         g_static_rec_mutex_init(&irc->otr_mutex);
     137        irc->otr_keygen = 0;
     138        irc->otr_ntodo = 0;
    136139       
    137140        return( irc );
     
    286289       
    287290        otrl_userstate_free(irc->otr_us);
    288         g_static_rec_mutex_free(&irc->otr_mutex);
     291        if(irc->otr_keygen) {
     292                kill(irc->otr_keygen, SIGTERM);
     293                waitpid(irc->otr_keygen, NULL, 0);
     294                /* TODO: remove stale keygen tempfiles */
     295        }
    289296       
    290297        g_free(irc);
  • irc.h

    r6c91e6e r522a00f  
    9999       
    100100        OtrlUserState otr_us;
    101         GStaticRecMutex otr_mutex;      /* for locking otr during keygen */
     101        pid_t otr_keygen;
     102        int otr_ntodo;
    102103} irc_t;
    103104
  • otr.c

    r6c91e6e r522a00f  
    103103/** misc. helpers/subroutines: **/
    104104
    105 /* start background thread to generate a (new) key for a given account */
     105/* start background process to generate a (new) key for a given account */
    106106void otr_keygen(irc_t *irc, const char *handle, const char *protocol);
    107107
    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 */
    112109gboolean 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 };
    124110
    125111/* some yes/no handlers */
     
    172158void otr_init(void)
    173159{
    174         if(!g_thread_supported()) g_thread_init(NULL);
    175160        OTRL_INIT;
    176161       
     
    196181}
    197182
    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 is
    203    a keygen in progress. Instead of blocking for an unknown time, they
    204    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 a
    208    catch-all in the root command handler. Rationale:
    209      a) it's easy to code
    210      b) it makes it obvious that no command can get its userstate corrupted
    211      c) the "irc" struct is readily available there for feedback to the user
    212  */
    213 
    214183void otr_load(irc_t *irc)
    215184{
     
    217186        account_t *a;
    218187        gcry_error_t e;
    219         int eno;
     188        gcry_error_t enoent = gcry_error_from_errno(ENOENT);
    220189
    221190        log_message(LOGLVL_DEBUG, "otr_load '%s'", irc->nick);
     
    223192        g_snprintf(s, 511, "%s%s.otr_keys", global.conf->configdir, irc->nick);
    224193        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));
    228196        }
    229197        g_snprintf(s, 511, "%s%s.otr_fprints", global.conf->configdir, irc->nick);
    230198        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));
    234201        }
    235202       
     
    250217        e = otrl_privkey_write_fingerprints(irc->otr_us, s);
    251218        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));
    253220        }
    254221        chmod(s, 0600);
     
    302269        char *colormsg;
    303270       
    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 
    317271        ignore_msg = otrl_message_receiving(ic->irc->otr_us, &global.otr_ops, ic,
    318272                ic->acc->user, ic->acc->prpl->name, handle, msg, &newmsg,
     
    323277        if(ignore_msg) {
    324278                /* this was an internal OTR protocol message */
    325                 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    326279                return NULL;
    327280        } else if(!newmsg) {
    328281                /* this was a non-OTR message */
    329                 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    330282                return g_strdup(msg);
    331283        } else {
     
    347299                }
    348300                otrl_message_free(newmsg);
    349                 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    350301                return colormsg;
    351302        }
     
    358309        ConnContext *ctx = NULL;
    359310       
    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    
    374311        st = otrl_message_sending(ic->irc->otr_us, &global.otr_ops, ic,
    375312                ic->acc->user, ic->acc->prpl->name, handle,
    376313                msg, NULL, &otrmsg, NULL, NULL);
    377314        if(st) {
    378                 g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    379315                return st;
    380316        }
     
    387323                if(!ctx) {
    388324                        otrl_message_free(otrmsg);
    389                         g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    390325                        return 1;
    391326                }
     
    399334        }
    400335       
    401         g_static_rec_mutex_unlock(&ic->irc->otr_mutex);
    402336        return st;
    403337}
     
    14831417void otr_keygen(irc_t *irc, const char *handle, const char *protocol)
    14841418{
    1485         GError *err;
    1486         GThread *thr;
    1487         struct kgdata *kg;
    1488         gint ev;
    14891419       
    14901420        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,
    15461437                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       
    15571441}
    15581442
    15591443gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond)
    15601444{
    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
    15711448                        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 */
    15801456}
    15811457
  • root_commands.c

    r6c91e6e r522a00f  
    8686                return;
    8787       
    88         if(!g_static_rec_mutex_trylock(&irc->otr_mutex)) {
    89                 irc_usermsg(irc, "keygen in progress, bitlbee comatose - please wait");
    90                 return;
    91         }
    92        
    9388        for( i = 0; commands[i].command; i++ )
    9489                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
     
    9792                        {
    9893                                irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
    99                                 g_static_rec_mutex_unlock(&irc->otr_mutex);
    10094                                return;
    10195                        }
    10296                        commands[i].execute( irc, cmd );
    103                         g_static_rec_mutex_unlock(&irc->otr_mutex);
    10497                        return;
    10598                }
    10699       
    107100        irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] );
    108         g_static_rec_mutex_unlock(&irc->otr_mutex);
    109101}
    110102
Note: See TracChangeset for help on using the changeset viewer.