Blame samples/nocipher_proxy.c

Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Clear Channel Sametime Proxy Utility
Packit Service 37472d
  The Meanwhile Project
Packit Service 37472d
Packit Service 37472d
  This is a tool which can act as a proxy between a client and a
Packit Service 37472d
  sametime server, which will force all channels to be created without
Packit Service 37472d
  any encryption method. This makes reverse-engineering much, much
Packit Service 37472d
  easier.
Packit Service 37472d
Packit Service 37472d
  It also outputs the messages sent to and from the client to stdout
Packit Service 37472d
  as hex pairs. If compiled with USE_HEXDUMP, output will be printed
Packit Service 37472d
  via `hexdump -C`
Packit Service 37472d
  
Packit Service 37472d
  All it really does is nab all Channel Create messages, strip the
Packit Service 37472d
  offered ciphers portion from the message and replace it with an
Packit Service 37472d
  empty ciphers list.
Packit Service 37472d
Packit Service 37472d
  Christopher O'Brien <siege@preoccupied.net>
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#include <netinet/in.h>
Packit Service 37472d
#include <netdb.h>
Packit Service 37472d
#include <stdlib.h>
Packit Service 37472d
#include <stdio.h>
Packit Service 37472d
#include <string.h>
Packit Service 37472d
#include <sys/socket.h>
Packit Service 37472d
#include <unistd.h>
Packit Service 37472d
Packit Service 37472d
#include <glib.h>
Packit Service 37472d
Packit Service 37472d
#include <mw_common.h>
Packit Service 37472d
#include <mw_message.h>
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct proxy_side {
Packit Service 37472d
  int sock;
Packit Service 37472d
  GIOChannel *chan;
Packit Service 37472d
  gint chan_io;
Packit Service 37472d
Packit Service 37472d
  guchar *buf;
Packit Service 37472d
  gsize buf_size;
Packit Service 37472d
  gsize buf_recv;
Packit Service 37472d
Packit Service 37472d
  void (*forward)(const guchar *buf, gsize len);
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct proxy_side client;
Packit Service 37472d
static struct proxy_side server;
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void hexdump(const char *txt, const guchar *buf, gsize len) {
Packit Service 37472d
  FILE *fp;
Packit Service 37472d
Packit Service 37472d
  if(txt) fprintf(stdout, "\n%s\n", txt);
Packit Service 37472d
  fflush(stdout);
Packit Service 37472d
Packit Service 37472d
  fp = popen("hexdump -C", "w");
Packit Service 37472d
  fwrite(buf, len, 1, fp);
Packit Service 37472d
  fflush(fp);
Packit Service 37472d
  pclose(fp);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  mwMessage_put(b, msg);
Packit Service 37472d
  mwPutBuffer_finalize(o, b);
Packit Service 37472d
  
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  mwOpaque_put(b, o);
Packit Service 37472d
  mwOpaque_clear(o);
Packit Service 37472d
  mwPutBuffer_finalize(o, b);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void side_buf_free(struct proxy_side *s) {
Packit Service 37472d
  g_free(s->buf);
Packit Service 37472d
  s->buf = NULL;
Packit Service 37472d
  s->buf_size = 0;
Packit Service 37472d
  s->buf_recv = 0;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void munge_redir() {
Packit Service 37472d
  struct mwMessage *msg;
Packit Service 37472d
  struct mwOpaque o = { 0, 0 };
Packit Service 37472d
Packit Service 37472d
  msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
Packit Service 37472d
  put_msg(msg, &o);
Packit Service 37472d
  mwMessage_free(msg);
Packit Service 37472d
Packit Service 37472d
  server.forward(o.data, o.len);
Packit Service 37472d
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void munge_create(struct proxy_side *side,
Packit Service 37472d
			 struct mwMsgChannelCreate *msg) {
Packit Service 37472d
Packit Service 37472d
  struct mwOpaque o = { 0, 0 };
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  for(l = msg->encrypt.items; l; l = l->next) {
Packit Service 37472d
    mwEncryptItem_clear(l->data);
Packit Service 37472d
    g_free(l->data);
Packit Service 37472d
  }
Packit Service 37472d
  g_list_free(msg->encrypt.items);
Packit Service 37472d
  msg->encrypt.items = NULL;
Packit Service 37472d
Packit Service 37472d
  msg->encrypt.mode = 0x00;
Packit Service 37472d
  msg->encrypt.extra = 0x00;
Packit Service 37472d
  msg->encrypt.flag = FALSE;
Packit Service 37472d
Packit Service 37472d
  put_msg(MW_MESSAGE(msg), &o);
Packit Service 37472d
  side->forward(o.data, o.len);
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
Packit Service 37472d
  struct mwOpaque o = { .len = len, .data = (guchar *) buf };
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
  guint16 type;
Packit Service 37472d
Packit Service 37472d
  if(! len) return;
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(&o);
Packit Service 37472d
  type = guint16_peek(b);
Packit Service 37472d
Packit Service 37472d
  switch(type) {
Packit Service 37472d
  case mwMessage_LOGIN_REDIRECT:
Packit Service 37472d
    munge_redir();
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case mwMessage_CHANNEL_CREATE:
Packit Service 37472d
    {
Packit Service 37472d
      struct mwMessage *msg = mwMessage_get(b);
Packit Service 37472d
      munge_create(s, (struct mwMsgChannelCreate *) msg);
Packit Service 37472d
      mwMessage_free(msg);
Packit Service 37472d
      break;
Packit Service 37472d
    }
Packit Service 37472d
    
Packit Service 37472d
  default:
Packit Service 37472d
    {
Packit Service 37472d
      struct mwPutBuffer *pb = mwPutBuffer_new();
Packit Service 37472d
      struct mwOpaque po = { 0, 0 };
Packit Service 37472d
      mwOpaque_put(pb, &o);
Packit Service 37472d
      mwPutBuffer_finalize(&po, pb);
Packit Service 37472d
      s->forward(po.data, po.len);
Packit Service 37472d
      mwOpaque_clear(&po);
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define ADVANCE(b, n, count) { b += count; n -= count; }
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* handle input to complete an existing buffer */
Packit Service 37472d
static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
Packit Service 37472d
Packit Service 37472d
  gsize x = s->buf_size - s->buf_recv;
Packit Service 37472d
Packit Service 37472d
  if(n < x) {
Packit Service 37472d
    memcpy(s->buf+s->buf_recv, b, n);
Packit Service 37472d
    s->buf_recv += n;
Packit Service 37472d
    return 0;
Packit Service 37472d
    
Packit Service 37472d
  } else {
Packit Service 37472d
    memcpy(s->buf+s->buf_recv, b, x);
Packit Service 37472d
    ADVANCE(b, n, x);
Packit Service 37472d
    
Packit Service 37472d
    if(s->buf_size == 4) {
Packit Service 37472d
      struct mwOpaque o = { .len = 4, .data = s->buf };
Packit Service 37472d
      struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
Packit Service 37472d
      x = guint32_peek(gb);
Packit Service 37472d
      mwGetBuffer_free(gb);
Packit Service 37472d
Packit Service 37472d
      if(n < x) {
Packit Service 37472d
	guchar *t;
Packit Service 37472d
	x += 4;
Packit Service 37472d
	t = (guchar *) g_malloc(x);
Packit Service 37472d
	memcpy(t, s->buf, 4);
Packit Service 37472d
	memcpy(t+4, b, n);
Packit Service 37472d
	
Packit Service 37472d
	side_buf_free(s);
Packit Service 37472d
	
Packit Service 37472d
	s->buf = t;
Packit Service 37472d
	s->buf_size = x;
Packit Service 37472d
	s->buf_recv = n + 4;
Packit Service 37472d
	return 0;
Packit Service 37472d
	
Packit Service 37472d
      } else {
Packit Service 37472d
	side_buf_free(s);
Packit Service 37472d
	side_process(s, b, x);
Packit Service 37472d
	ADVANCE(b, n, x);
Packit Service 37472d
      }
Packit Service 37472d
      
Packit Service 37472d
    } else {
Packit Service 37472d
      side_process(s, s->buf+4, s->buf_size-4);
Packit Service 37472d
      side_buf_free(s);
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return n;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* handle input when there's nothing previously buffered */
Packit Service 37472d
static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
Packit Service 37472d
  struct mwOpaque o = { .len = n, .data = (guchar *) b };
Packit Service 37472d
  struct mwGetBuffer *gb;
Packit Service 37472d
  gsize x;
Packit Service 37472d
Packit Service 37472d
  if(n < 4) {
Packit Service 37472d
    s->buf = (guchar *) g_malloc0(4);
Packit Service 37472d
    memcpy(s->buf, b, n);
Packit Service 37472d
    s->buf_size = 4;
Packit Service 37472d
    s->buf_recv = n;
Packit Service 37472d
    return 0;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  gb = mwGetBuffer_wrap(&o);
Packit Service 37472d
  x = guint32_peek(gb);
Packit Service 37472d
  mwGetBuffer_free(gb);
Packit Service 37472d
  if(! x) return n - 4;
Packit Service 37472d
Packit Service 37472d
  if(n < (x + 4)) {
Packit Service 37472d
Packit Service 37472d
    x += 4;
Packit Service 37472d
    s->buf = (guchar *) g_malloc(x);
Packit Service 37472d
    memcpy(s->buf, b, n);
Packit Service 37472d
    s->buf_size = x;
Packit Service 37472d
    s->buf_recv = n;
Packit Service 37472d
    return 0;
Packit Service 37472d
    
Packit Service 37472d
  } else {
Packit Service 37472d
    ADVANCE(b, n, 4);
Packit Service 37472d
    side_process(s, b, x);
Packit Service 37472d
    ADVANCE(b, n, x);
Packit Service 37472d
Packit Service 37472d
    return n;
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
Packit Service 37472d
Packit Service 37472d
  if(n && (s->buf_size == 0) && (*b & 0x80)) {
Packit Service 37472d
    ADVANCE(b, n, 1);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(n == 0) {
Packit Service 37472d
    return 0;
Packit Service 37472d
Packit Service 37472d
  } else if(s->buf_size > 0) {
Packit Service 37472d
    return side_recv_cont(s, b, n);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    return side_recv_empty(s, b, n);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
Packit Service 37472d
  guchar *b = (guchar *) buf;
Packit Service 37472d
  gsize remain = 0;
Packit Service 37472d
  
Packit Service 37472d
  g_return_if_fail(side != NULL);
Packit Service 37472d
Packit Service 37472d
  while(n > 0) {
Packit Service 37472d
    remain = side_recv(side, b, n);
Packit Service 37472d
    b += (n - remain);
Packit Service 37472d
    n = remain;
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static int read_recv(struct proxy_side *side) {
Packit Service 37472d
  guchar buf[2048];
Packit Service 37472d
  int len;
Packit Service 37472d
Packit Service 37472d
  len = read(side->sock, buf, 2048);
Packit Service 37472d
  if(len > 0) feed_buf(side, buf, (gsize) len);
Packit Service 37472d
Packit Service 37472d
  return len;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void done() {
Packit Service 37472d
  close(client.sock);
Packit Service 37472d
  close(server.sock);
Packit Service 37472d
  exit(0);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static gboolean read_cb(GIOChannel *chan,
Packit Service 37472d
			GIOCondition cond,
Packit Service 37472d
			gpointer data) {
Packit Service 37472d
Packit Service 37472d
  struct proxy_side *side = data;
Packit Service 37472d
  int ret = 0;
Packit Service 37472d
Packit Service 37472d
  if(cond & G_IO_IN) {
Packit Service 37472d
    ret = read_recv(side);
Packit Service 37472d
    if(ret > 0) return TRUE;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(side->sock) {
Packit Service 37472d
    g_source_remove(side->chan_io);
Packit Service 37472d
    close(side->sock);
Packit Service 37472d
    side->sock = 0;
Packit Service 37472d
    side->chan = NULL;
Packit Service 37472d
    side->chan_io = 0;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  done();
Packit Service 37472d
  
Packit Service 37472d
  return FALSE;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void client_cb(const guchar *buf, gsize len) {
Packit Service 37472d
  if(server.sock) {
Packit Service 37472d
    hexdump("client -> server", buf, len);
Packit Service 37472d
    write(server.sock, buf, len);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static gboolean listen_cb(GIOChannel *chan,
Packit Service 37472d
			  GIOCondition cond,
Packit Service 37472d
			  gpointer data) {
Packit Service 37472d
Packit Service 37472d
  struct sockaddr_in rem;
Packit Service 37472d
  guint len = sizeof(rem);
Packit Service 37472d
  struct proxy_side *side = data;
Packit Service 37472d
  int sock;
Packit Service 37472d
  
Packit Service 37472d
  sock = accept(side->sock, (struct sockaddr *) &rem, &len;;
Packit Service 37472d
  g_assert(sock > 0);
Packit Service 37472d
Packit Service 37472d
  g_source_remove(side->chan_io);
Packit Service 37472d
  side->sock = sock;
Packit Service 37472d
  side->chan = g_io_channel_unix_new(sock);
Packit Service 37472d
  side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit Service 37472d
				 read_cb, side);
Packit Service 37472d
Packit Service 37472d
  return FALSE;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void init_client(int port) {
Packit Service 37472d
  /* start listening on the local port specifier */
Packit Service 37472d
Packit Service 37472d
  struct sockaddr_in sin;
Packit Service 37472d
  int sock;
Packit Service 37472d
Packit Service 37472d
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit Service 37472d
  g_assert(sock >= 0);
Packit Service 37472d
Packit Service 37472d
  memset(&sin, 0, sizeof(struct sockaddr_in));
Packit Service 37472d
  sin.sin_family = PF_INET;
Packit Service 37472d
  sin.sin_port = htons(port);
Packit Service 37472d
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
Packit Service 37472d
Packit Service 37472d
  if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
Packit Service 37472d
    g_assert_not_reached();
Packit Service 37472d
Packit Service 37472d
  if(listen(sock, 1) < 0)
Packit Service 37472d
    g_assert_not_reached();
Packit Service 37472d
Packit Service 37472d
  client.forward = client_cb;
Packit Service 37472d
  client.sock = sock;
Packit Service 37472d
  client.chan = g_io_channel_unix_new(sock);
Packit Service 37472d
  client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit Service 37472d
				  listen_cb, &client);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void server_cb(const guchar *buf, gsize len) {
Packit Service 37472d
  if(client.sock) {
Packit Service 37472d
    hexdump("server -> client", buf, len);
Packit Service 37472d
    write(client.sock, buf, len);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/* address lookup used by init_sock */
Packit Service 37472d
static void init_sockaddr(struct sockaddr_in *addr,
Packit Service 37472d
			  const char *host, int port) {
Packit Service 37472d
Packit Service 37472d
  struct hostent *hostinfo;
Packit Service 37472d
Packit Service 37472d
  addr->sin_family = AF_INET;
Packit Service 37472d
  addr->sin_port = htons (port);
Packit Service 37472d
  hostinfo = gethostbyname(host);
Packit Service 37472d
  if(hostinfo == NULL) {
Packit Service 37472d
    fprintf(stderr, "Unknown host %s.\n", host);
Packit Service 37472d
    exit(1);
Packit Service 37472d
  }
Packit Service 37472d
  addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void init_server(const char *host, int port) {
Packit Service 37472d
  /* connect to server on host/port */
Packit Service 37472d
  struct sockaddr_in srvrname;
Packit Service 37472d
  int sock;
Packit Service 37472d
Packit Service 37472d
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit Service 37472d
  if(sock < 0) {
Packit Service 37472d
    fprintf(stderr, "socket failure");
Packit Service 37472d
    exit(1);
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  init_sockaddr(&srvrname, host, port);
Packit Service 37472d
  connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
Packit Service 37472d
Packit Service 37472d
  server.forward = server_cb;
Packit Service 37472d
  server.sock = sock;
Packit Service 37472d
  server.chan = g_io_channel_unix_new(sock);
Packit Service 37472d
  server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit Service 37472d
				  read_cb, &server);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int main(int argc, char *argv[]) {
Packit Service 37472d
  char *host = NULL;
Packit Service 37472d
  int client_port = 0, server_port = 0;
Packit Service 37472d
Packit Service 37472d
  memset(&client, 0, sizeof(struct proxy_side));
Packit Service 37472d
  memset(&server, 0, sizeof(struct proxy_side));
Packit Service 37472d
Packit Service 37472d
  if(argc > 1) {
Packit Service 37472d
    char *z;
Packit Service 37472d
Packit Service 37472d
    host = argv[1];
Packit Service 37472d
    z = host;
Packit Service 37472d
Packit Service 37472d
    host = strchr(z, ':');
Packit Service 37472d
    if(host) *host++ = '\0';
Packit Service 37472d
    client_port = atoi(z);
Packit Service 37472d
Packit Service 37472d
    z = strchr(host, ':');
Packit Service 37472d
    if(z) *z++ = '\0';
Packit Service 37472d
    server_port = atoi(z);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  if(!host || !*host || !client_port || !server_port) {
Packit Service 37472d
    fprintf(stderr,
Packit Service 37472d
	    ( " Usage: %s local_port:remote_host:remote_port\n"
Packit Service 37472d
	      " Creates a locally-running sametime proxy which enforces"
Packit Service 37472d
	      " unencrypted channels\n" ),
Packit Service 37472d
	    argv[0]);
Packit Service 37472d
    exit(1);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* @todo create signal handlers to cleanup sockets */
Packit Service 37472d
Packit Service 37472d
  init_client(client_port);
Packit Service 37472d
  init_server(host, server_port);
Packit Service 37472d
Packit Service 37472d
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
Packit Service 37472d
  return 0;
Packit Service 37472d
}
Packit Service 37472d