Blame samples/login_server.c

Packit 16808d
Packit 16808d
/*
Packit 16808d
  Login-parsing Faux Server
Packit 16808d
  The Meanwhile Project
Packit 16808d
Packit 16808d
  This is a tool to aide in reverse engineering different types of
Packit 16808d
  authentication schemes.
Packit 16808d
Packit 16808d
  Christopher O'Brien <siege@preoccupied.net>
Packit 16808d
*/
Packit 16808d
Packit 16808d
Packit 16808d
#include <stdio.h>
Packit 16808d
#include <stdlib.h>
Packit 16808d
#include <string.h>
Packit 16808d
#include <sys/socket.h>
Packit 16808d
#include <netdb.h>
Packit 16808d
#include <netinet/in.h>
Packit 16808d
#include <unistd.h>
Packit 16808d
Packit 16808d
#include <glib.h>
Packit 16808d
#include <glib/glist.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
/** the server socket or the connected socket */
Packit 16808d
static int sock;
Packit 16808d
Packit 16808d
/** the io channel */
Packit 16808d
static GIOChannel *chan;
Packit 16808d
Packit 16808d
/** the listening event on the io channel */
Packit 16808d
static int chan_io;
Packit 16808d
Packit 16808d
Packit 16808d
static guchar *sbuf;
Packit 16808d
static gsize sbuf_size;
Packit 16808d
static gsize sbuf_recv;
Packit 16808d
Packit 16808d
Packit 16808d
struct mwMpi *private, *public;
Packit 16808d
Packit 16808d
Packit 16808d
static void hexout(const char *txt, const guchar *buf, gsize len) {
Packit 16808d
  FILE *fp;
Packit 16808d
Packit 16808d
  if(txt) fprintf(stdout, "\n%s\n", txt);
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
static void send_msg(struct mwMessage *msg) {
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
  struct mwOpaque o = { 0, 0 };
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
  if(sock) write(sock, o.data, o.len);
Packit 16808d
Packit 16808d
  hexout("sent:", o.data, o.len);
Packit 16808d
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void handshake_ack() {
Packit 16808d
  struct mwMsgHandshakeAck *msg;
Packit 16808d
Packit 16808d
  msg = (struct mwMsgHandshakeAck *)
Packit 16808d
    mwMessage_new(mwMessage_HANDSHAKE_ACK);
Packit 16808d
Packit 16808d
  msg->major = 0x1e;
Packit 16808d
  msg->minor = 0x1d;
Packit 16808d
Packit 16808d
  mwMpi_randDHKeypair(private, public);
Packit 16808d
  mwMpi_export(public, &msg->data);
Packit 16808d
Packit 16808d
  msg->magic = 0x01234567;
Packit 16808d
  hexout("sending pubkey:", msg->data.data, msg->data.len);
Packit 16808d
Packit 16808d
  send_msg(MW_MESSAGE(msg));
Packit 16808d
  mwMessage_free(MW_MESSAGE(msg));
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void handle_login(struct mwMsgLogin *msg) {
Packit 16808d
  struct mwGetBuffer *gb;
Packit 16808d
  struct mwOpaque a, b, c;
Packit 16808d
  guint16 z;
Packit 16808d
  struct mwMpi *remote, *shared;
Packit 16808d
  guchar iv[8];
Packit 16808d
Packit 16808d
  remote = mwMpi_new();
Packit 16808d
  shared = mwMpi_new();
Packit 16808d
Packit 16808d
  mwIV_init(iv);
Packit 16808d
Packit 16808d
  gb = mwGetBuffer_wrap(&msg->auth_data);
Packit 16808d
  guint16_get(gb, &z);
Packit 16808d
  mwOpaque_get(gb, &a);
Packit 16808d
  mwOpaque_get(gb, &b);
Packit 16808d
  mwGetBuffer_free(gb);
Packit 16808d
Packit 16808d
  mwMpi_import(remote, &a);
Packit 16808d
  mwOpaque_clear(&a);
Packit 16808d
Packit 16808d
  mwMpi_calculateDHShared(shared, remote, private);
Packit 16808d
  mwMpi_export(shared, &a);
Packit 16808d
  hexout("shared key:", a.data, a.len);
Packit 16808d
Packit 16808d
  mwDecrypt(a.data+(a.len-16), 16, iv, &b, &c);
Packit 16808d
  hexout("decrypted to:", c.data, c.len);
Packit 16808d
Packit 16808d
  mwOpaque_clear(&a);
Packit 16808d
  mwOpaque_clear(&b);
Packit 16808d
  mwOpaque_clear(&c);
Packit 16808d
Packit 16808d
  mwMpi_free(remote);
Packit 16808d
  mwMpi_free(shared);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void done() {
Packit 16808d
  close(sock);
Packit 16808d
  exit(0);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void side_process(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
  b = mwGetBuffer_wrap(&o);
Packit 16808d
  type = guint16_peek(b);
Packit 16808d
Packit 16808d
  hexout("received:", buf, len);
Packit 16808d
Packit 16808d
  switch(type) {
Packit 16808d
  case mwMessage_HANDSHAKE:
Packit 16808d
    printf("got handshake, sending handshake_ack\n");
Packit 16808d
    handshake_ack();
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case mwMessage_LOGIN:
Packit 16808d
    printf("got login, attempting to decipher\n");
Packit 16808d
    {
Packit 16808d
      struct mwMsgLogin *msg = (struct mwMsgLogin *) mwMessage_get(b);
Packit 16808d
      handle_login(msg);
Packit 16808d
      mwMessage_free(MW_MESSAGE(msg));
Packit 16808d
      done();
Packit 16808d
    }
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case mwMessage_CHANNEL_DESTROY:
Packit 16808d
    printf("channel destroy\n");
Packit 16808d
    done();
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  default:
Packit 16808d
    ;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  mwGetBuffer_free(b);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void sbuf_free() {
Packit 16808d
  g_free(sbuf);
Packit 16808d
  sbuf = NULL;
Packit 16808d
  sbuf_size = 0;
Packit 16808d
  sbuf_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(const guchar *b, gsize n) {
Packit 16808d
Packit 16808d
  gsize x = sbuf_size - sbuf_recv;
Packit 16808d
Packit 16808d
  if(n < x) {
Packit 16808d
    memcpy(sbuf + sbuf_recv, b, n);
Packit 16808d
    sbuf_recv += n;
Packit 16808d
    return 0;
Packit 16808d
    
Packit 16808d
  } else {
Packit 16808d
    memcpy(sbuf + sbuf_recv, b, x);
Packit 16808d
    ADVANCE(b, n, x);
Packit 16808d
    
Packit 16808d
    if(sbuf_size == 4) {
Packit 16808d
      struct mwOpaque o = { .len = 4, .data = sbuf };
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, sbuf, 4);
Packit 16808d
	memcpy(t+4, b, n);
Packit 16808d
	
Packit 16808d
	sbuf_free();
Packit 16808d
	
Packit 16808d
	sbuf = t;
Packit 16808d
	sbuf_size = x;
Packit 16808d
	sbuf_recv = n + 4;
Packit 16808d
	return 0;
Packit 16808d
	
Packit 16808d
      } else {
Packit 16808d
	sbuf_free();
Packit 16808d
	side_process(b, x);
Packit 16808d
	ADVANCE(b, n, x);
Packit 16808d
      }
Packit 16808d
      
Packit 16808d
    } else {
Packit 16808d
      side_process(sbuf+4, sbuf_size-4);
Packit 16808d
      sbuf_free();
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(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
    sbuf = (guchar *) g_malloc0(4);
Packit 16808d
    memcpy(sbuf, b, n);
Packit 16808d
    sbuf_size = 4;
Packit 16808d
    sbuf_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
    sbuf = (guchar *) g_malloc(x);
Packit 16808d
    memcpy(sbuf, b, n);
Packit 16808d
    sbuf_size = x;
Packit 16808d
    sbuf_recv = n;
Packit 16808d
    return 0;
Packit 16808d
    
Packit 16808d
  } else {
Packit 16808d
    ADVANCE(b, n, 4);
Packit 16808d
    side_process(b, x);
Packit 16808d
    ADVANCE(b, n, x);
Packit 16808d
Packit 16808d
    return n;
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static gsize side_recv(const guchar *b, gsize n) {
Packit 16808d
Packit 16808d
  if(n && (sbuf_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(sbuf_size > 0) {
Packit 16808d
    return side_recv_cont(b, n);
Packit 16808d
Packit 16808d
  } else {
Packit 16808d
    return side_recv_empty(b, n);
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void feed_buf(const guchar *buf, gsize n) {
Packit 16808d
  guchar *b = (guchar *) buf;
Packit 16808d
  gsize remain = 0;
Packit 16808d
Packit 16808d
  while(n > 0) {
Packit 16808d
    remain = side_recv(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() {
Packit 16808d
  guchar buf[2048];
Packit 16808d
  int len;
Packit 16808d
Packit 16808d
  len = read(sock, buf, 2048);
Packit 16808d
  if(len > 0) feed_buf(buf, (gsize) len);
Packit 16808d
Packit 16808d
  return len;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static gboolean read_cb(GIOChannel *chan,
Packit 16808d
			GIOCondition cond,
Packit 16808d
			gpointer data) {
Packit 16808d
  int ret = 0;
Packit 16808d
Packit 16808d
  if(cond & G_IO_IN) {
Packit 16808d
    ret = read_recv();
Packit 16808d
    if(ret > 0) return TRUE;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(sock) {
Packit 16808d
    g_source_remove(chan_io);
Packit 16808d
    close(sock);
Packit 16808d
    sock = 0;
Packit 16808d
    chan = NULL;
Packit 16808d
    chan_io = 0;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  done();
Packit 16808d
  
Packit 16808d
  return FALSE;
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
Packit 16808d
  printf("accepting connection\n");
Packit 16808d
  
Packit 16808d
  sock = accept(sock, (struct sockaddr *) &rem, &len;;
Packit 16808d
  g_assert(sock > 0);
Packit 16808d
Packit 16808d
  g_source_remove(chan_io);
Packit 16808d
  chan = g_io_channel_unix_new(sock);
Packit 16808d
  chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit 16808d
			   read_cb, NULL);
Packit 16808d
  
Packit 16808d
  return FALSE;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void init_socket(int port) {
Packit 16808d
  /* start listening on the local port specifier */
Packit 16808d
Packit 16808d
  struct sockaddr_in sin;
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(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
  chan = g_io_channel_unix_new(sock);
Packit 16808d
  chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit 16808d
			   listen_cb, NULL);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int main(int argc, char *argv[]) {
Packit 16808d
  int port = 0;
Packit 16808d
Packit 16808d
  private = mwMpi_new();
Packit 16808d
  public = mwMpi_new();
Packit 16808d
Packit 16808d
  if(argc > 1) {
Packit 16808d
    port = atoi(argv[1]);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(!port) {
Packit 16808d
    fprintf(stderr,
Packit 16808d
	    ( " Usage: %s local_port\n"
Packit 16808d
	      " Creates a locally-running sametime server which prints"
Packit 16808d
	      " login information to stdout\n" ),
Packit 16808d
	    argv[0]);
Packit 16808d
    exit(1);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  /* @todo create signal handlers to cleanup socket */
Packit 16808d
Packit 16808d
  init_socket(port);
Packit 16808d
Packit 16808d
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
Packit 16808d
  return 0;
Packit 16808d
}
Packit 16808d