Blame samples/logging_proxy.c

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