Blame samples/logging_proxy.c.fix-glib-headers

Packit ee6627
Packit ee6627
/*
Packit ee6627
  Logging Sametime Proxy Utility
Packit ee6627
  The Meanwhile Project
Packit ee6627
Packit ee6627
  This is a tool which can act as a proxy between a client and a
Packit ee6627
  sametime server, which will log all messages to stdout. It will also
Packit ee6627
  munge channel creation messages in order to be able to decrypt any
Packit ee6627
  encrypted data sent over a channel, and will log decrypted chunks to
Packit ee6627
  stdout as well. This makes reverse-engineering of services much,
Packit ee6627
  much easier.
Packit ee6627
Packit ee6627
  The idea is simple, but the implementation made my head hurt.
Packit ee6627
Packit ee6627
  Christopher O'Brien <siege@preoccupied.net>
Packit ee6627
*/
Packit ee6627
Packit ee6627
Packit ee6627
#include <netinet/in.h>
Packit ee6627
#include <netdb.h>
Packit ee6627
#include <stdlib.h>
Packit ee6627
#include <stdio.h>
Packit ee6627
#include <string.h>
Packit ee6627
#include <sys/socket.h>
Packit ee6627
#include <unistd.h>
Packit ee6627
Packit ee6627
#include <glib.h>
Packit ee6627
#include <glib/glist.h>
Packit ee6627
Packit ee6627
#include <mw_cipher.h>
Packit ee6627
#include <mw_common.h>
Packit ee6627
#include <mw_message.h>
Packit ee6627
Packit ee6627
Packit ee6627
/** one side of the proxy (either the client side or the server
Packit ee6627
    side). The forward method for one should push data into the socket
Packit ee6627
    of the other. */
Packit ee6627
struct proxy_side {
Packit ee6627
  int sock;
Packit ee6627
  GIOChannel *chan;
Packit ee6627
  gint chan_io;
Packit ee6627
Packit ee6627
  guchar *buf;
Packit ee6627
  gsize buf_size;
Packit ee6627
  gsize buf_recv;
Packit ee6627
Packit ee6627
  void (*forward)(const guchar *buf, gsize len);
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
static struct proxy_side client;  /**< side facing the client */
Packit ee6627
static struct proxy_side server;  /**< side facing the server */
Packit ee6627
Packit ee6627
Packit ee6627
static char *host = NULL;
Packit ee6627
static int client_port = 0;
Packit ee6627
static int server_port = 0;
Packit ee6627
Packit ee6627
Packit ee6627
static int counter = 0;
Packit ee6627
static int listen_sock = 0;
Packit ee6627
static GIOChannel *listen_chan = NULL;
Packit ee6627
static gint listen_io = 0;
Packit ee6627
Packit ee6627
Packit ee6627
Packit ee6627
Packit ee6627
Packit ee6627
/** given one side, get the other */
Packit ee6627
#define OTHER_SIDE(side) \
Packit ee6627
  ((side == &client)? &server: &client)
Packit ee6627
Packit ee6627
Packit ee6627
/** encryption state information used in the RC2/40 cipher */
Packit ee6627
struct rc2_40enc {
Packit ee6627
  guchar outgoing_iv[8];
Packit ee6627
  int outgoing_key[64];
Packit ee6627
  guchar incoming_iv[8];
Packit ee6627
  int incoming_key[64];
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
/* re-usable rc2 40 stuff */
Packit ee6627
static int session_key[64] = {
Packit ee6627
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit ee6627
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit ee6627
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit ee6627
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
/** encryption state information used in the RC2/128 cipher */
Packit ee6627
struct rc2_128enc {
Packit ee6627
  guchar outgoing_iv[8];
Packit ee6627
  guchar incoming_iv[8];
Packit ee6627
  int shared_key[64];
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
/* re-usable rc2 128 stuff */
Packit ee6627
static struct mwMpi *private_key;
Packit ee6627
static struct mwOpaque public_key;
Packit ee6627
Packit ee6627
Packit ee6627
/** represents a channel. The channel has a left side and a right
Packit ee6627
    side. The left side is the creator of the channel. The right side
Packit ee6627
    is the target of the channel. Each side has its own encryption
Packit ee6627
    state information, so an incoming message from either side can
Packit ee6627
    be decrypted, then re-encrypted for the other side. */
Packit ee6627
struct channel {
Packit ee6627
  guint32 id;
Packit ee6627
Packit ee6627
  /* login id of creator or NULL if created by client side */
Packit ee6627
  char *creator;
Packit ee6627
Packit ee6627
  /* the offer from the left side */
Packit ee6627
  struct mwEncryptOffer offer;
Packit ee6627
Packit ee6627
  /** the mode of encryption */
Packit ee6627
  enum {
Packit ee6627
    enc_none = 0,  /**< nothing encrypted */
Packit ee6627
    enc_easy,      /**< easy (rc2/40) encryption */
Packit ee6627
    enc_hard,      /**< hard (rc2/128) encryption */
Packit ee6627
  } enc_mode;
Packit ee6627
Packit ee6627
  /** encryption data for the left side */
Packit ee6627
  union {
Packit ee6627
    struct rc2_40enc easy;
Packit ee6627
    struct rc2_128enc hard;
Packit ee6627
  } left_enc;
Packit ee6627
Packit ee6627
  /** encryption data for the right side */
Packit ee6627
  union {
Packit ee6627
    struct rc2_40enc easy;
Packit ee6627
    struct rc2_128enc hard;
Packit ee6627
  } right_enc;
Packit ee6627
Packit ee6627
  struct proxy_side *left;   /**< proxy side acting as the left side */
Packit ee6627
  struct proxy_side *right;  /**< proxy side acting as the right side */
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
/* collection of channels */
Packit ee6627
static GHashTable *channels;
Packit ee6627
Packit ee6627
Packit ee6627
#define PUT_CHANNEL(chan) \
Packit ee6627
  g_hash_table_insert(channels, GUINT_TO_POINTER((chan)->id), (chan))
Packit ee6627
Packit ee6627
#define GET_CHANNEL(id) \
Packit ee6627
  g_hash_table_lookup(channels, GUINT_TO_POINTER(id))
Packit ee6627
Packit ee6627
#define REMOVE_CHANNEL(id) \
Packit ee6627
  g_hash_table_remove(channels, GUINT_TO_POINTER(id))
Packit ee6627
Packit ee6627
Packit ee6627
/** print a message to stdout and use hexdump to print a data chunk */
Packit ee6627
static void hexdump_vprintf(const guchar *buf, gsize len,
Packit ee6627
			    const char *txt, va_list args) {
Packit ee6627
  FILE *fp;
Packit ee6627
Packit ee6627
  if(txt) {
Packit ee6627
    fputc('\n', stdout);
Packit ee6627
    vfprintf(stdout, txt, args);
Packit ee6627
    fputc('\n', stdout);
Packit ee6627
  }
Packit ee6627
  fflush(stdout);
Packit ee6627
Packit ee6627
  fp = popen("hexdump -C", "w");
Packit ee6627
  fwrite(buf, len, 1, fp);
Packit ee6627
  fflush(fp);
Packit ee6627
  pclose(fp);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** print a message to stdout and use hexdump to print a data chunk */
Packit ee6627
static void hexdump_printf(const guchar *buf, gsize len,
Packit ee6627
			   const char *txt, ...) {
Packit ee6627
  va_list args;
Packit ee6627
  va_start(args, txt);
Packit ee6627
  hexdump_vprintf(buf, len, txt, args);
Packit ee6627
  va_end(args);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** serialize a message for sending */
Packit ee6627
static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
Packit ee6627
  struct mwPutBuffer *b;
Packit ee6627
Packit ee6627
  b = mwPutBuffer_new();
Packit ee6627
  mwMessage_put(b, msg);
Packit ee6627
  mwPutBuffer_finalize(o, b);
Packit ee6627
  
Packit ee6627
  b = mwPutBuffer_new();
Packit ee6627
  mwOpaque_put(b, o);
Packit ee6627
  mwOpaque_clear(o);
Packit ee6627
  mwPutBuffer_finalize(o, b);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void key_copy(int to[64], int from[64]) {
Packit ee6627
  int i = 64;
Packit ee6627
  while(i--) to[i] = from[i];
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* we don't want to be redirected away from the proxy, so eat any
Packit ee6627
   redirect messages from the server and respond with a login cont */
Packit ee6627
static void munge_redir() {
Packit ee6627
  struct mwMessage *msg;
Packit ee6627
  struct mwOpaque o = { 0, 0 };
Packit ee6627
Packit ee6627
  msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
Packit ee6627
  put_msg(msg, &o);
Packit ee6627
  mwMessage_free(msg);
Packit ee6627
Packit ee6627
  server.forward(o.data, o.len);
Packit ee6627
Packit ee6627
  mwOpaque_clear(&o);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* handle receipt of channel create messages from either side,
Packit ee6627
   recording the offered ciphers, and munging it to instead include
Packit ee6627
   our own key as applicable, then sending it on */
Packit ee6627
static void munge_create(struct proxy_side *side,
Packit ee6627
			 struct mwMsgChannelCreate *msg) {
Packit ee6627
Packit ee6627
  struct mwOpaque o = { 0, 0 };
Packit ee6627
  GList *l;
Packit ee6627
  struct channel *c;
Packit ee6627
Packit ee6627
  /* create a new channel on the side */
Packit ee6627
  c = g_new0(struct channel, 1);
Packit ee6627
  c->id = msg->channel;
Packit ee6627
  c->left = side;
Packit ee6627
  c->right = OTHER_SIDE(side);
Packit ee6627
Packit ee6627
  if(msg->creator_flag) {
Packit ee6627
    c->creator = g_strdup(msg->creator.login_id);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* record the mode and encryption items */
Packit ee6627
  c->offer.mode = msg->encrypt.mode;
Packit ee6627
  c->offer.items = msg->encrypt.items;
Packit ee6627
  c->offer.extra = msg->encrypt.extra;
Packit ee6627
  c->offer.flag = msg->encrypt.flag;
Packit ee6627
Packit ee6627
  PUT_CHANNEL(c);
Packit ee6627
Packit ee6627
  /* replace the encryption items with our own as applicable */
Packit ee6627
  if(msg->encrypt.items) {
Packit ee6627
    l = msg->encrypt.items;
Packit ee6627
    msg->encrypt.items = NULL; /* steal them */
Packit ee6627
Packit ee6627
    for(; l; l = l->next) {
Packit ee6627
      struct mwEncryptItem *i1, *i2;
Packit ee6627
Packit ee6627
      /* the original we've stolen */
Packit ee6627
      i1 = l->data;
Packit ee6627
Packit ee6627
      /* the munged replacement */
Packit ee6627
      i2 = g_new0(struct mwEncryptItem, 1);
Packit ee6627
      i2->id = i1->id;
Packit ee6627
Packit ee6627
      switch(i1->id) {
Packit ee6627
      case mwCipher_RC2_128:
Packit ee6627
	printf("munging an offered RC2/128\n");
Packit ee6627
	mwOpaque_clone(&i2->info, &public_key);
Packit ee6627
	break;
Packit ee6627
      case mwCipher_RC2_40:
Packit ee6627
	printf("munging an offered RC2/40\n");
Packit ee6627
      default:
Packit ee6627
	;
Packit ee6627
      }
Packit ee6627
Packit ee6627
      msg->encrypt.items = g_list_append(msg->encrypt.items, i2);
Packit ee6627
    }
Packit ee6627
  }
Packit ee6627
Packit ee6627
  put_msg(MW_MESSAGE(msg), &o);
Packit ee6627
  side->forward(o.data, o.len);
Packit ee6627
  mwOpaque_clear(&o);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* find an enc item by id in a list of items */
Packit ee6627
struct mwEncryptItem *find_item(GList *items, guint16 id) {
Packit ee6627
  GList *ltmp;
Packit ee6627
  for(ltmp = items; ltmp; ltmp = ltmp->next) {
Packit ee6627
    struct mwEncryptItem *i = ltmp->data;
Packit ee6627
    if(i->id == id) return i;
Packit ee6627
  }
Packit ee6627
  return NULL;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* handle acceptance of a channel */
Packit ee6627
static void munge_accept(struct proxy_side *side,
Packit ee6627
			 struct mwMsgChannelAccept *msg) {
Packit ee6627
Packit ee6627
  struct mwOpaque o = {0,0};
Packit ee6627
  struct channel *chan;
Packit ee6627
  struct mwEncryptItem *item;
Packit ee6627
Packit ee6627
  chan = GET_CHANNEL(msg->head.channel);
Packit ee6627
  item = msg->encrypt.item;
Packit ee6627
Packit ee6627
  if(! item) {
Packit ee6627
    /* cut to the chase */
Packit ee6627
    put_msg(MW_MESSAGE(msg), &o);
Packit ee6627
    side->forward(o.data, o.len);
Packit ee6627
    mwOpaque_clear(&o);
Packit ee6627
    return;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* init right-side encryption with our enc and accepted enc */
Packit ee6627
  switch(item->id) {
Packit ee6627
  case mwCipher_RC2_128: {
Packit ee6627
    struct mwMpi *remote, *shared;
Packit ee6627
    struct mwOpaque k;
Packit ee6627
Packit ee6627
    remote = mwMpi_new();
Packit ee6627
    shared = mwMpi_new();
Packit ee6627
Packit ee6627
    printf("right side accepted RC2/128\n");
Packit ee6627
Packit ee6627
    mwMpi_import(remote, &item->info);
Packit ee6627
    mwMpi_calculateDHShared(shared, remote, private_key);
Packit ee6627
    mwMpi_export(shared, &k);
Packit ee6627
Packit ee6627
    chan->enc_mode = enc_hard;
Packit ee6627
Packit ee6627
    mwIV_init(chan->right_enc.hard.outgoing_iv);
Packit ee6627
    mwIV_init(chan->right_enc.hard.incoming_iv);
Packit ee6627
    mwKeyExpand(chan->right_enc.hard.shared_key, k.data+(k.len-16), 16);
Packit ee6627
Packit ee6627
    mwMpi_free(remote);
Packit ee6627
    mwMpi_free(shared);
Packit ee6627
    mwOpaque_clear(&k);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  case mwCipher_RC2_40: {
Packit ee6627
    char *who;
Packit ee6627
    
Packit ee6627
    printf("right side accepted RC2/40\n");
Packit ee6627
Packit ee6627
    chan->enc_mode = enc_easy;
Packit ee6627
Packit ee6627
    mwIV_init(chan->right_enc.easy.outgoing_iv);
Packit ee6627
    mwIV_init(chan->right_enc.easy.incoming_iv);
Packit ee6627
Packit ee6627
    if(msg->acceptor_flag) {
Packit ee6627
      who = msg->acceptor.login_id;
Packit ee6627
      printf("right side is the server\n");
Packit ee6627
      printf("server is %s\n", who);
Packit ee6627
      mwKeyExpand(chan->right_enc.easy.incoming_key, (guchar *) who, 5);
Packit ee6627
      key_copy(chan->right_enc.easy.outgoing_key, session_key);
Packit ee6627
Packit ee6627
    } else {
Packit ee6627
      who = chan->creator;
Packit ee6627
      printf("right side is the client\n");
Packit ee6627
      printf("server is %s\n", who);
Packit ee6627
      key_copy(chan->right_enc.easy.incoming_key, session_key);
Packit ee6627
      mwKeyExpand(chan->right_enc.easy.outgoing_key, (guchar *) who, 5);
Packit ee6627
    }
Packit ee6627
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  default:
Packit ee6627
    chan->enc_mode = enc_none;
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* init left-side encryption with offered enc and our enc, munge accept */
Packit ee6627
  switch(item->id) {
Packit ee6627
  case mwCipher_RC2_128: {
Packit ee6627
    struct mwMpi *remote, *shared;
Packit ee6627
    struct mwOpaque k;
Packit ee6627
    struct mwEncryptItem *offered;
Packit ee6627
    
Packit ee6627
    remote = mwMpi_new();
Packit ee6627
    shared = mwMpi_new();
Packit ee6627
Packit ee6627
    printf("accepting left side with RC2/128\n");
Packit ee6627
    
Packit ee6627
    offered = find_item(chan->offer.items, mwCipher_RC2_128);
Packit ee6627
    mwMpi_import(remote, &offered->info);
Packit ee6627
    mwMpi_calculateDHShared(shared, remote, private_key);
Packit ee6627
    mwMpi_export(shared, &k);
Packit ee6627
    
Packit ee6627
    mwIV_init(chan->left_enc.hard.outgoing_iv);
Packit ee6627
    mwIV_init(chan->left_enc.hard.incoming_iv);
Packit ee6627
    mwKeyExpand(chan->left_enc.hard.shared_key, k.data+(k.len-16), 16);
Packit ee6627
Packit ee6627
    mwMpi_free(remote);
Packit ee6627
    mwMpi_free(shared);
Packit ee6627
    mwOpaque_clear(&k);
Packit ee6627
    
Packit ee6627
    /* munge accept with out public key */
Packit ee6627
    mwOpaque_clear(&item->info);
Packit ee6627
    mwOpaque_clone(&item->info, &public_key);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  case mwCipher_RC2_40:
Packit ee6627
    printf("accepting left side with RC2/40\n");
Packit ee6627
Packit ee6627
    mwIV_init(chan->left_enc.easy.outgoing_iv);
Packit ee6627
    mwIV_init(chan->left_enc.easy.incoming_iv);
Packit ee6627
Packit ee6627
    key_copy(chan->left_enc.easy.outgoing_key,
Packit ee6627
	     chan->right_enc.easy.incoming_key);
Packit ee6627
Packit ee6627
    key_copy(chan->left_enc.easy.incoming_key,
Packit ee6627
	     chan->right_enc.easy.outgoing_key);
Packit ee6627
    break;
Packit ee6627
    
Packit ee6627
  default:
Packit ee6627
    ;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  put_msg(MW_MESSAGE(msg), &o);
Packit ee6627
  side->forward(o.data, o.len);
Packit ee6627
  mwOpaque_clear(&o);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void dec(struct channel *chan, struct proxy_side *side,
Packit ee6627
		struct mwOpaque *to, struct mwOpaque *from) {
Packit ee6627
  
Packit ee6627
  switch(chan->enc_mode) {
Packit ee6627
  case enc_easy: {
Packit ee6627
    if(chan->left == side) {
Packit ee6627
      /* left side decrypt */
Packit ee6627
      mwDecryptExpanded(chan->left_enc.easy.incoming_key,
Packit ee6627
			chan->left_enc.easy.incoming_iv,
Packit ee6627
			from, to);
Packit ee6627
    } else {
Packit ee6627
      /* right side decrypt */
Packit ee6627
      mwDecryptExpanded(chan->right_enc.easy.incoming_key,
Packit ee6627
			chan->right_enc.easy.incoming_iv,
Packit ee6627
			from, to);
Packit ee6627
    }
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  case enc_hard: {
Packit ee6627
    if(chan->left == side) {
Packit ee6627
      /* left side decrypt */
Packit ee6627
      mwDecryptExpanded(chan->left_enc.hard.shared_key,
Packit ee6627
			chan->left_enc.hard.incoming_iv,
Packit ee6627
			from, to);
Packit ee6627
    } else {
Packit ee6627
      /* right side decrypt */
Packit ee6627
      mwDecryptExpanded(chan->right_enc.hard.shared_key,
Packit ee6627
			chan->right_enc.hard.incoming_iv,
Packit ee6627
			from, to);
Packit ee6627
    }
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void enc(struct channel *chan, struct proxy_side *side,
Packit ee6627
		struct mwOpaque *to, struct mwOpaque *from) {
Packit ee6627
Packit ee6627
  switch(chan->enc_mode) {
Packit ee6627
  case enc_easy: {
Packit ee6627
    if(chan->left == side) {
Packit ee6627
      /* left side encrypt */
Packit ee6627
      mwEncryptExpanded(chan->left_enc.easy.outgoing_key,
Packit ee6627
			chan->left_enc.easy.outgoing_iv,
Packit ee6627
			from, to);
Packit ee6627
    } else {
Packit ee6627
      /* right side encrypt */
Packit ee6627
      mwEncryptExpanded(chan->right_enc.easy.outgoing_key,
Packit ee6627
			chan->right_enc.easy.outgoing_iv,
Packit ee6627
			from, to);
Packit ee6627
    }
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  case enc_hard: {
Packit ee6627
    if(chan->left == side) {
Packit ee6627
      /* left side encrypt */
Packit ee6627
      mwEncryptExpanded(chan->left_enc.hard.shared_key,
Packit ee6627
			chan->left_enc.hard.outgoing_iv,
Packit ee6627
			from, to);
Packit ee6627
    } else {
Packit ee6627
      /* right side encrypt */
Packit ee6627
      mwEncryptExpanded(chan->right_enc.hard.shared_key,
Packit ee6627
			chan->right_enc.hard.outgoing_iv,
Packit ee6627
			from, to);
Packit ee6627
    }
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void munge_channel(struct proxy_side *side,
Packit ee6627
			  struct mwMsgChannelSend *msg) {
Packit ee6627
Packit ee6627
  struct mwOpaque o = {0,0};
Packit ee6627
Packit ee6627
  if(msg->head.options & mwMessageOption_ENCRYPT) {
Packit ee6627
    struct mwOpaque d = {0,0};
Packit ee6627
    struct channel *chan;
Packit ee6627
Packit ee6627
    chan = GET_CHANNEL(msg->head.channel);
Packit ee6627
Packit ee6627
    /* decrypt from side */
Packit ee6627
    dec(chan, side, &d, &msg->data);
Packit ee6627
Packit ee6627
    /* display */
Packit ee6627
    hexdump_printf(d.data, d.len, "decrypted channel message data:",
Packit ee6627
		   msg->type);
Packit ee6627
Packit ee6627
    /* encrypt to other side */
Packit ee6627
    mwOpaque_clear(&msg->data);
Packit ee6627
    enc(chan, OTHER_SIDE(side), &msg->data, &d);
Packit ee6627
    mwOpaque_clear(&d);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* send to other side */
Packit ee6627
  put_msg(MW_MESSAGE(msg), &o);
Packit ee6627
  side->forward(o.data, o.len);
Packit ee6627
  mwOpaque_clear(&o);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* handle destruction of a channel */
Packit ee6627
static void handle_destroy(struct proxy_side *side,
Packit ee6627
			   struct mwMsgChannelDestroy *msg) {
Packit ee6627
Packit ee6627
  struct channel *chan;
Packit ee6627
  GList *l;
Packit ee6627
Packit ee6627
  chan = GET_CHANNEL(msg->head.channel);
Packit ee6627
  REMOVE_CHANNEL(msg->head.channel);
Packit ee6627
Packit ee6627
  if(! chan) return;
Packit ee6627
Packit ee6627
  for(l = chan->offer.items; l; l = l->next) {
Packit ee6627
    mwEncryptItem_free(l->data);
Packit ee6627
  }
Packit ee6627
  g_list_free(chan->offer.items);
Packit ee6627
  chan->offer.items = NULL;
Packit ee6627
Packit ee6627
  g_free(chan->creator);
Packit ee6627
  chan->creator = NULL;
Packit ee6627
Packit ee6627
  g_free(chan);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void forward(struct proxy_side *to,
Packit ee6627
		    struct mwOpaque *data) {
Packit ee6627
Packit ee6627
  struct mwPutBuffer *pb = mwPutBuffer_new();
Packit ee6627
  struct mwOpaque po = { 0, 0 };
Packit ee6627
Packit ee6627
  mwOpaque_put(pb, data);
Packit ee6627
  mwPutBuffer_finalize(&po, pb);
Packit ee6627
  to->forward(po.data, po.len);
Packit ee6627
  mwOpaque_clear(&po);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/* handle messages from either side */
Packit ee6627
static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
Packit ee6627
  struct mwOpaque o = { .len = len, .data = (guchar *) buf };
Packit ee6627
  struct mwGetBuffer *b;
Packit ee6627
  guint16 type;
Packit ee6627
Packit ee6627
  if(! len) return;
Packit ee6627
Packit ee6627
  if(s == &server) {
Packit ee6627
    hexdump_printf(buf, len, "server -> client");
Packit ee6627
  } else {
Packit ee6627
    hexdump_printf(buf, len, "client -> server");
Packit ee6627
  }
Packit ee6627
Packit ee6627
  b = mwGetBuffer_wrap(&o);
Packit ee6627
  type = guint16_peek(b);
Packit ee6627
Packit ee6627
  switch(type) {
Packit ee6627
  case mwMessage_LOGIN_ACK: {
Packit ee6627
    struct mwMsgLoginAck *msg = (struct mwMsgLoginAck *) mwMessage_get(b);
Packit ee6627
    printf("client is %s\n", msg->login.login_id);
Packit ee6627
    mwKeyExpand(session_key, (guchar *) msg->login.login_id, 5);
Packit ee6627
    mwMessage_free(MW_MESSAGE(msg));
Packit ee6627
    forward(s, &o);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  case mwMessage_LOGIN_REDIRECT: {
Packit ee6627
    munge_redir();
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  case mwMessage_CHANNEL_CREATE: {
Packit ee6627
    struct mwMessage *msg = mwMessage_get(b);
Packit ee6627
    munge_create(s, (struct mwMsgChannelCreate *) msg);
Packit ee6627
    mwMessage_free(msg);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  case mwMessage_CHANNEL_ACCEPT: {
Packit ee6627
    struct mwMessage *msg = mwMessage_get(b);
Packit ee6627
    munge_accept(s, (struct mwMsgChannelAccept *) msg);
Packit ee6627
    mwMessage_free(msg);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  case mwMessage_CHANNEL_DESTROY: {
Packit ee6627
    struct mwMessage *msg = mwMessage_get(b);
Packit ee6627
    handle_destroy(s, (struct mwMsgChannelDestroy *) msg);
Packit ee6627
    mwMessage_free(msg);
Packit ee6627
    forward(s, &o);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  case mwMessage_CHANNEL_SEND: {
Packit ee6627
    struct mwMessage *msg = mwMessage_get(b);
Packit ee6627
    munge_channel(s, (struct mwMsgChannelSend *) msg);
Packit ee6627
    mwMessage_free(msg);
Packit ee6627
    break;
Packit ee6627
  }
Packit ee6627
    
Packit ee6627
  default:
Packit ee6627
    forward(s, &o);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  mwGetBuffer_free(b);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** clean up a proxy side's inner buffer */
Packit ee6627
static void side_buf_free(struct proxy_side *s) {
Packit ee6627
  g_free(s->buf);
Packit ee6627
  s->buf = NULL;
Packit ee6627
  s->buf_size = 0;
Packit ee6627
  s->buf_recv = 0;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
#define ADVANCE(b, n, count) { b += count; n -= count; }
Packit ee6627
Packit ee6627
Packit ee6627
/** handle input to complete an existing buffer */
Packit ee6627
static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
Packit ee6627
Packit ee6627
  gsize x = s->buf_size - s->buf_recv;
Packit ee6627
Packit ee6627
  if(n < x) {
Packit ee6627
    memcpy(s->buf+s->buf_recv, b, n);
Packit ee6627
    s->buf_recv += n;
Packit ee6627
    return 0;
Packit ee6627
    
Packit ee6627
  } else {
Packit ee6627
    memcpy(s->buf+s->buf_recv, b, x);
Packit ee6627
    ADVANCE(b, n, x);
Packit ee6627
    
Packit ee6627
    if(s->buf_size == 4) {
Packit ee6627
      struct mwOpaque o = { .len = 4, .data = s->buf };
Packit ee6627
      struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
Packit ee6627
      x = guint32_peek(gb);
Packit ee6627
      mwGetBuffer_free(gb);
Packit ee6627
Packit ee6627
      if(n < x) {
Packit ee6627
	guchar *t;
Packit ee6627
	x += 4;
Packit ee6627
	t = (guchar *) g_malloc(x);
Packit ee6627
	memcpy(t, s->buf, 4);
Packit ee6627
	memcpy(t+4, b, n);
Packit ee6627
	
Packit ee6627
	side_buf_free(s);
Packit ee6627
	
Packit ee6627
	s->buf = t;
Packit ee6627
	s->buf_size = x;
Packit ee6627
	s->buf_recv = n + 4;
Packit ee6627
	return 0;
Packit ee6627
	
Packit ee6627
      } else {
Packit ee6627
	side_buf_free(s);
Packit ee6627
	side_process(s, b, x);
Packit ee6627
	ADVANCE(b, n, x);
Packit ee6627
      }
Packit ee6627
      
Packit ee6627
    } else {
Packit ee6627
      side_process(s, s->buf+4, s->buf_size-4);
Packit ee6627
      side_buf_free(s);
Packit ee6627
    }
Packit ee6627
  }
Packit ee6627
Packit ee6627
  return n;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** handle input when there's nothing previously buffered */
Packit ee6627
static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
Packit ee6627
  struct mwOpaque o = { .len = n, .data = (guchar *) b };
Packit ee6627
  struct mwGetBuffer *gb;
Packit ee6627
  gsize x;
Packit ee6627
Packit ee6627
  if(n < 4) {
Packit ee6627
    s->buf = (guchar *) g_malloc0(4);
Packit ee6627
    memcpy(s->buf, b, n);
Packit ee6627
    s->buf_size = 4;
Packit ee6627
    s->buf_recv = n;
Packit ee6627
    return 0;
Packit ee6627
  }
Packit ee6627
  
Packit ee6627
  gb = mwGetBuffer_wrap(&o);
Packit ee6627
  x = guint32_peek(gb);
Packit ee6627
  mwGetBuffer_free(gb);
Packit ee6627
  if(! x) return n - 4;
Packit ee6627
Packit ee6627
  if(n < (x + 4)) {
Packit ee6627
Packit ee6627
    x += 4;
Packit ee6627
    s->buf = (guchar *) g_malloc(x);
Packit ee6627
    memcpy(s->buf, b, n);
Packit ee6627
    s->buf_size = x;
Packit ee6627
    s->buf_recv = n;
Packit ee6627
    return 0;
Packit ee6627
    
Packit ee6627
  } else {
Packit ee6627
    ADVANCE(b, n, 4);
Packit ee6627
    side_process(s, b, x);
Packit ee6627
    ADVANCE(b, n, x);
Packit ee6627
Packit ee6627
    return n;
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** handle input in chunks */
Packit ee6627
static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
Packit ee6627
Packit ee6627
  if(n && (s->buf_size == 0) && (*b & 0x80)) {
Packit ee6627
    ADVANCE(b, n, 1);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  if(n == 0) {
Packit ee6627
    return 0;
Packit ee6627
Packit ee6627
  } else if(s->buf_size > 0) {
Packit ee6627
    return side_recv_cont(s, b, n);
Packit ee6627
Packit ee6627
  } else {
Packit ee6627
    return side_recv_empty(s, b, n);
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** handle input */
Packit ee6627
static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
Packit ee6627
  guchar *b = (guchar *) buf;
Packit ee6627
  gsize remain = 0;
Packit ee6627
  
Packit ee6627
  g_return_if_fail(side != NULL);
Packit ee6627
Packit ee6627
  while(n > 0) {
Packit ee6627
    remain = side_recv(side, b, n);
Packit ee6627
    b += (n - remain);
Packit ee6627
    n = remain;
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static int read_recv(struct proxy_side *side) {
Packit ee6627
  guchar buf[2048];
Packit ee6627
  int len;
Packit ee6627
Packit ee6627
  len = read(side->sock, buf, 2048);
Packit ee6627
  if(len > 0) feed_buf(side, buf, (gsize) len);
Packit ee6627
Packit ee6627
  return len;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void init_listen();
Packit ee6627
Packit ee6627
Packit ee6627
static void side_done(struct proxy_side *side) {
Packit ee6627
  if(side->sock) {
Packit ee6627
    g_source_remove(side->chan_io);
Packit ee6627
    close(side->sock);
Packit ee6627
    side->sock = 0;
Packit ee6627
    side->chan = NULL;
Packit ee6627
    side->chan_io = 0;
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void done() {
Packit ee6627
  printf("closing connection\n");
Packit ee6627
Packit ee6627
  side_done(&client);
Packit ee6627
  side_done(&server);
Packit ee6627
Packit ee6627
  if(counter--) {
Packit ee6627
    init_listen();
Packit ee6627
  } else {
Packit ee6627
    exit(0);
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static gboolean read_cb(GIOChannel *chan,
Packit ee6627
			GIOCondition cond,
Packit ee6627
			gpointer data) {
Packit ee6627
Packit ee6627
  struct proxy_side *side = data;
Packit ee6627
  int ret = 0;
Packit ee6627
Packit ee6627
  if(cond & G_IO_IN) {
Packit ee6627
    ret = read_recv(side);
Packit ee6627
    if(ret > 0) return TRUE;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  done();
Packit ee6627
  
Packit ee6627
  return FALSE;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void client_cb(const guchar *buf, gsize len) {
Packit ee6627
  if(server.sock) write(server.sock, buf, len);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** setup the client */
Packit ee6627
static void init_client(int sock) {
Packit ee6627
Packit ee6627
  client.forward = client_cb;
Packit ee6627
  client.sock = sock;
Packit ee6627
  client.chan = g_io_channel_unix_new(sock);
Packit ee6627
  client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit ee6627
				  read_cb, &client);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void server_cb(const guchar *buf, gsize len) {
Packit ee6627
  if(client.sock) write(client.sock, buf, len);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** generate a private/public DH keypair for internal (re)use */
Packit ee6627
static void init_rc2_128() {
Packit ee6627
  struct mwMpi *public;
Packit ee6627
Packit ee6627
  private_key = mwMpi_new();
Packit ee6627
  public = mwMpi_new();
Packit ee6627
Packit ee6627
  mwMpi_randDHKeypair(private_key, public);
Packit ee6627
  mwMpi_export(public, &public_key);
Packit ee6627
Packit ee6627
  mwMpi_free(public);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** address lookup used by init_sock */
Packit ee6627
static void init_sockaddr(struct sockaddr_in *addr,
Packit ee6627
			  const char *host, int port) {
Packit ee6627
Packit ee6627
  struct hostent *hostinfo;
Packit ee6627
Packit ee6627
  addr->sin_family = AF_INET;
Packit ee6627
  addr->sin_port = htons (port);
Packit ee6627
  hostinfo = gethostbyname(host);
Packit ee6627
  if(hostinfo == NULL) {
Packit ee6627
    fprintf(stderr, "Unknown host %s.\n", host);
Packit ee6627
    exit(1);
Packit ee6627
  }
Packit ee6627
  addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** connect to server on host:port */
Packit ee6627
static void init_server() {
Packit ee6627
  struct sockaddr_in srvrname;
Packit ee6627
  int sock;
Packit ee6627
Packit ee6627
  printf("connecting to %s:%i\n", host, server_port);
Packit ee6627
Packit ee6627
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit ee6627
  if(sock < 0) {
Packit ee6627
    fprintf(stderr, "socket failure");
Packit ee6627
    exit(1);
Packit ee6627
  }
Packit ee6627
  
Packit ee6627
  init_sockaddr(&srvrname, host, server_port);
Packit ee6627
  connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
Packit ee6627
Packit ee6627
  server.forward = server_cb;
Packit ee6627
  server.sock = sock;
Packit ee6627
  server.chan = g_io_channel_unix_new(sock);
Packit ee6627
  server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit ee6627
				  read_cb, &server);
Packit ee6627
Packit ee6627
  printf("connected to %s:%i\n", host, server_port);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
Packit ee6627
static gboolean listen_cb(GIOChannel *chan,
Packit ee6627
			  GIOCondition cond,
Packit ee6627
			  gpointer data) {
Packit ee6627
Packit ee6627
  struct sockaddr_in rem;
Packit ee6627
  guint len = sizeof(rem);
Packit ee6627
  int sock;
Packit ee6627
  
Packit ee6627
  printf("got connection\n");
Packit ee6627
Packit ee6627
  sock = accept(listen_sock, (struct sockaddr *) &rem, &len;;
Packit ee6627
  /* g_assert(sock > 0); */
Packit ee6627
Packit ee6627
  init_server();
Packit ee6627
  init_client(sock);
Packit ee6627
Packit ee6627
  listen_io = 0;
Packit ee6627
Packit ee6627
  return FALSE;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void init_listen() {
Packit ee6627
  if(! listen_sock) {
Packit ee6627
    struct sockaddr_in sin;
Packit ee6627
    int sock;
Packit ee6627
Packit ee6627
    sock = socket(PF_INET, SOCK_STREAM, 0);
Packit ee6627
    g_assert(sock >= 0);
Packit ee6627
Packit ee6627
    memset(&sin, 0, sizeof(struct sockaddr_in));
Packit ee6627
    sin.sin_family = PF_INET;
Packit ee6627
    sin.sin_port = htons(client_port);
Packit ee6627
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
Packit ee6627
Packit ee6627
    if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
Packit ee6627
      g_assert_not_reached();
Packit ee6627
Packit ee6627
    if(listen(sock, 1) < 0)
Packit ee6627
      g_assert_not_reached();
Packit ee6627
Packit ee6627
    listen_sock = sock;
Packit ee6627
    listen_chan = g_io_channel_unix_new(sock);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  if(! listen_io) {
Packit ee6627
    listen_io = g_io_add_watch(listen_chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit ee6627
			       listen_cb, NULL);
Packit ee6627
    printf("listening on port %i\n", client_port);
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
int main(int argc, char *argv[]) {
Packit ee6627
Packit ee6627
  memset(&client, 0, sizeof(struct proxy_side));
Packit ee6627
  memset(&server, 0, sizeof(struct proxy_side));
Packit ee6627
Packit ee6627
  if(argc > 1) {
Packit ee6627
    char *z;
Packit ee6627
Packit ee6627
    host = argv[1];
Packit ee6627
    z = host;
Packit ee6627
Packit ee6627
    host = strchr(z, ':');
Packit ee6627
    if(host) *host++ = '\0';
Packit ee6627
    client_port = atoi(z);
Packit ee6627
Packit ee6627
    z = strchr(host, ':');
Packit ee6627
    if(z) *z++ = '\0';
Packit ee6627
    server_port = atoi(z);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  if(argc > 2) {
Packit ee6627
    counter = atoi(argv[2]);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  if(!host || !*host || !client_port || !server_port) {
Packit ee6627
    fprintf(stderr,
Packit ee6627
	    ( " Usage: %s local_port:remote_host:remote_port [n]\n"
Packit ee6627
	      " Creates a locally-running sametime proxy which enforces"
Packit ee6627
	      " unencrypted channels. Will drop the first n connections\n" ),
Packit ee6627
	    argv[0]);
Packit ee6627
    exit(1);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* @todo create signal handlers to cleanup sockets */
Packit ee6627
Packit ee6627
  channels = g_hash_table_new(g_direct_hash, g_direct_equal);
Packit ee6627
Packit ee6627
  init_rc2_128();
Packit ee6627
  init_listen();
Packit ee6627
Packit ee6627
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
Packit ee6627
  return 0;
Packit ee6627
}
Packit ee6627