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

Packit ee6627
Packit ee6627
/*
Packit ee6627
  Clear Channel 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 force all channels to be created without
Packit ee6627
  any encryption method. This makes reverse-engineering much, much
Packit ee6627
  easier.
Packit ee6627
Packit ee6627
  It also outputs the messages sent to and from the client to stdout
Packit ee6627
  as hex pairs. If compiled with USE_HEXDUMP, output will be printed
Packit ee6627
  via `hexdump -C`
Packit ee6627
  
Packit ee6627
  All it really does is nab all Channel Create messages, strip the
Packit ee6627
  offered ciphers portion from the message and replace it with an
Packit ee6627
  empty ciphers list.
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_common.h>
Packit ee6627
#include <mw_message.h>
Packit ee6627
Packit ee6627
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;
Packit ee6627
static struct proxy_side server;
Packit ee6627
Packit ee6627
Packit ee6627
static void hexdump(const char *txt, const guchar *buf, gsize len) {
Packit ee6627
  FILE *fp;
Packit ee6627
Packit ee6627
  if(txt) fprintf(stdout, "\n%s\n", txt);
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
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 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
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
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
Packit ee6627
  for(l = msg->encrypt.items; l; l = l->next) {
Packit ee6627
    mwEncryptItem_clear(l->data);
Packit ee6627
    g_free(l->data);
Packit ee6627
  }
Packit ee6627
  g_list_free(msg->encrypt.items);
Packit ee6627
  msg->encrypt.items = NULL;
Packit ee6627
Packit ee6627
  msg->encrypt.mode = 0x00;
Packit ee6627
  msg->encrypt.extra = 0x00;
Packit ee6627
  msg->encrypt.flag = FALSE;
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 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
  b = mwGetBuffer_wrap(&o);
Packit ee6627
  type = guint16_peek(b);
Packit ee6627
Packit ee6627
  switch(type) {
Packit ee6627
  case mwMessage_LOGIN_REDIRECT:
Packit ee6627
    munge_redir();
Packit ee6627
    break;
Packit ee6627
Packit ee6627
  case mwMessage_CHANNEL_CREATE:
Packit ee6627
    {
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
  default:
Packit ee6627
    {
Packit ee6627
      struct mwPutBuffer *pb = mwPutBuffer_new();
Packit ee6627
      struct mwOpaque po = { 0, 0 };
Packit ee6627
      mwOpaque_put(pb, &o);
Packit ee6627
      mwPutBuffer_finalize(&po, pb);
Packit ee6627
      s->forward(po.data, po.len);
Packit ee6627
      mwOpaque_clear(&po);
Packit ee6627
    }
Packit ee6627
  }
Packit ee6627
Packit ee6627
  mwGetBuffer_free(b);
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
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
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 done() {
Packit ee6627
  close(client.sock);
Packit ee6627
  close(server.sock);
Packit ee6627
  exit(0);
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
  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
  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) {
Packit ee6627
    hexdump("client -> server", buf, len);
Packit ee6627
    write(server.sock, buf, len);
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
  struct proxy_side *side = data;
Packit ee6627
  int sock;
Packit ee6627
  
Packit ee6627
  sock = accept(side->sock, (struct sockaddr *) &rem, &len;;
Packit ee6627
  g_assert(sock > 0);
Packit ee6627
Packit ee6627
  g_source_remove(side->chan_io);
Packit ee6627
  side->sock = sock;
Packit ee6627
  side->chan = g_io_channel_unix_new(sock);
Packit ee6627
  side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit ee6627
				 read_cb, side);
Packit ee6627
Packit ee6627
  return FALSE;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void init_client(int port) {
Packit ee6627
  /* start listening on the local port specifier */
Packit ee6627
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(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
  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
				  listen_cb, &client);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void server_cb(const guchar *buf, gsize len) {
Packit ee6627
  if(client.sock) {
Packit ee6627
    hexdump("server -> client", buf, len);
Packit ee6627
    write(client.sock, buf, len);
Packit ee6627
  }
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
static void init_server(const char *host, int port) {
Packit ee6627
  /* connect to server on host/port */
Packit ee6627
  struct sockaddr_in srvrname;
Packit ee6627
  int sock;
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, 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
Packit ee6627
Packit ee6627
int main(int argc, char *argv[]) {
Packit ee6627
  char *host = NULL;
Packit ee6627
  int client_port = 0, server_port = 0;
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(!host || !*host || !client_port || !server_port) {
Packit ee6627
    fprintf(stderr,
Packit ee6627
	    ( " Usage: %s local_port:remote_host:remote_port\n"
Packit ee6627
	      " Creates a locally-running sametime proxy which enforces"
Packit ee6627
	      " unencrypted channels\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
  init_client(client_port);
Packit ee6627
  init_server(host, server_port);
Packit ee6627
Packit ee6627
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
Packit ee6627
  return 0;
Packit ee6627
}
Packit ee6627