Changeset 27db433


Ignore:
Timestamp:
2008-02-15T17:36:18Z (16 years ago)
Author:
Sven Moritz Hallberg <sm@…>
Branches:
master
Children:
dc9797f
Parents:
522a00f
Message:

implement background keygen via child process

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    r522a00f r27db433  
    136136        irc->otr_us = otrl_userstate_create();
    137137        irc->otr_keygen = 0;
     138        irc->otr_to = NULL;
     139        irc->otr_from = NULL;
    138140        irc->otr_ntodo = 0;
    139141       
  • irc.h

    r522a00f r27db433  
    9999       
    100100        OtrlUserState otr_us;
    101         pid_t otr_keygen;
    102         int otr_ntodo;
     101        pid_t otr_keygen;    /* pid of keygen slave */
     102        FILE *otr_to;        /* pipe to keygen slave */
     103        FILE *otr_from;      /* pipe from keygen slave */
     104        int otr_ntodo;       /* number of keys left to generate */
    103105} irc_t;
    104106
  • otr.c

    r522a00f r27db433  
    4343#include "otr.h"
    4444#include <sys/types.h>
     45#include <sys/wait.h>
    4546#include <unistd.h>
    4647
     
    106107void otr_keygen(irc_t *irc, const char *handle, const char *protocol);
    107108
     109/* main function for the forked keygen slave */
     110void keygen_child_main(OtrlUserState us, int infd, int outfd);
     111
    108112/* mainloop handler for when a keygen finishes */
    109113gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond);
     114
     115/* copy the contents of file a to file b, overwriting it if it exists */
     116void copyfile(const char *a, const char *b);
     117
     118/* read one line of input from a stream, excluding trailing newline */
     119void myfgets(char *s, int size, FILE *stream);
    110120
    111121/* some yes/no handlers */
     
    14171427void otr_keygen(irc_t *irc, const char *handle, const char *protocol)
    14181428{
    1419        
    14201429        irc_usermsg(irc, "generating new private key for %s/%s...", handle, protocol);
    1421         irc_usermsg(irc, "n/a: not implemented");
    1422         return;
    14231430
    14241431        /* 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,
    1437                 kg->protocol);
    1438                
    1439                 when done, send filename, accountname, and protocol to output. */
    1440        
     1432           handler on its output. */
     1433        if(!irc->otr_keygen || waitpid(irc->otr_keygen, NULL, WNOHANG)) {
     1434                pid_t p;
     1435                int to[2], from[2];
     1436                FILE *tof, *fromf;
     1437               
     1438                if(pipe(to) < 0 || pipe(from) < 0) {
     1439                        irc_usermsg(irc, "otr keygen: couldn't create pipe: %s", strerror(errno));
     1440                        return;
     1441                }
     1442               
     1443                tof = fdopen(to[1], "w");
     1444                fromf = fdopen(from[0], "r");
     1445                if(!tof || !fromf) {
     1446                        irc_usermsg(irc, "otr keygen: couldn't streamify pipe: %s", strerror(errno));
     1447                        return;
     1448                }
     1449               
     1450                p = fork();
     1451                if(p<0) {
     1452                        irc_usermsg(irc, "otr keygen: couldn't fork: %s", strerror(errno));
     1453                        return;
     1454                }
     1455               
     1456                if(!p) {
     1457                        /* child process */
     1458                        signal(SIGTERM, exit);
     1459                        keygen_child_main(irc->otr_us, to[0], from[1]);
     1460                        exit(0);
     1461                }
     1462               
     1463                irc->otr_keygen = p;
     1464                irc->otr_to = tof;
     1465                irc->otr_from = fromf;
     1466                irc->otr_ntodo = 0;
     1467                b_input_add(from[0], GAIM_INPUT_READ, keygen_finish_handler, irc);
     1468        }
     1469       
     1470        /* send accountname and protocol for the new key to our keygen slave */
     1471        fprintf(irc->otr_to, "%s\n%s\n", handle, protocol);
     1472        fflush(irc->otr_to);
     1473        irc->otr_ntodo++;
     1474}
     1475
     1476void keygen_child_main(OtrlUserState us, int infd, int outfd)
     1477{
     1478        FILE *input, *output;
     1479        char filename[128], accountname[512], protocol[512];
     1480        gcry_error_t e;
     1481        int tempfd;
     1482       
     1483        input = fdopen(infd, "r");
     1484        output = fdopen(outfd, "w");
     1485       
     1486        while(!feof(input) && !ferror(input) && !feof(output) && !ferror(output)) {
     1487                myfgets(accountname, 512, input);
     1488                myfgets(protocol, 512, input);
     1489               
     1490                strncpy(filename, "/tmp/bitlbee-XXXXXX", 128);
     1491                tempfd = mkstemp(filename);
     1492                close(tempfd);
     1493
     1494                e = otrl_privkey_generate(us, filename, accountname, protocol);
     1495                if(e) {
     1496                        fprintf(output, "\n");  /* this means failure */
     1497                        fprintf(output, "otr keygen: %s\n", gcry_strerror(e));
     1498                        unlink(filename);
     1499                } else {
     1500                        fprintf(output, "%s\n", filename);
     1501                        fprintf(output, "otr keygen for %s/%s complete\n", accountname, protocol);
     1502                }
     1503                fflush(output);
     1504        }
     1505       
     1506        fclose(input);
     1507        fclose(output);
    14411508}
    14421509
    14431510gboolean keygen_finish_handler(gpointer data, gint fd, b_input_condition cond)
    14441511{
    1445         /* in the handler:
    1446            read filename, accountname, and protocol from child output
    1447            print a message to the user
    1448                         irc_usermsg(kg->irc, "otr keygen for %s/%s complete", kg->handle, kg->protocol);
    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 */
     1512        irc_t *irc = (irc_t *)data;
     1513        char filename[512], msg[512];
     1514
     1515        log_message(LOGLVL_DEBUG, "keygen_finish_handler cond=%d", cond);
     1516
     1517        myfgets(filename, 512, irc->otr_from);
     1518        myfgets(msg, 512, irc->otr_from);
     1519       
     1520        log_message(LOGLVL_DEBUG, "filename='%s'", filename);
     1521        log_message(LOGLVL_DEBUG, "msg='%s'", msg);
     1522       
     1523        irc_usermsg(irc, "%s", msg);
     1524        if(filename[0]) {
     1525                char *kf = g_strdup_printf("%s%s.otr_keys", global.conf->configdir, irc->nick);
     1526                char *tmp = g_strdup_printf("%s.new", kf);
     1527                copyfile(filename, tmp);
     1528                unlink(filename);
     1529                rename(tmp,kf);
     1530                otrl_privkey_read(irc->otr_us, kf);
     1531                g_free(kf);
     1532                g_free(tmp);
     1533        }
     1534               
     1535        irc->otr_ntodo--;
     1536        if(irc->otr_ntodo < 1) {
     1537                /* okay, we think the slave is idle now, so kill him */
     1538                log_message(LOGLVL_DEBUG, "all keys done. die, slave!");
     1539                fclose(irc->otr_from);
     1540                fclose(irc->otr_to);
     1541                kill(irc->otr_keygen, SIGTERM);
     1542                waitpid(irc->otr_keygen, NULL, 0);
     1543                irc->otr_keygen = 0;
     1544                return FALSE;  /* unregister ourselves */
     1545        } else {
     1546                return TRUE;   /* slave still working, keep watching */
     1547        }
     1548}
     1549
     1550void copyfile(const char *a, const char *b)
     1551{
     1552        int fda, fdb;
     1553        int n;
     1554        char buf[1024];
     1555       
     1556        log_message(LOGLVL_DEBUG, "copyfile '%s' '%s'", a, b);
     1557       
     1558        fda = open(a, O_RDONLY);
     1559        fdb = open(b, O_WRONLY | O_CREAT | O_TRUNC, 0600);
     1560       
     1561        while((n=read(fda, buf, 1024)) > 0)
     1562                write(fdb, buf, n);
     1563       
     1564        close(fda);
     1565        close(fdb);     
     1566}
     1567
     1568void myfgets(char *s, int size, FILE *stream)
     1569{
     1570        if(!fgets(s, size, stream)) {
     1571                s[0] = '\0';
     1572        } else {
     1573                int n = strlen(s);
     1574                if(n>0 && s[n-1] == '\n')
     1575                        s[n-1] = '\0';
     1576        }
    14561577}
    14571578
Note: See TracChangeset for help on using the changeset viewer.