1 
2 /*
3   Clear Channel Sametime Proxy Utility
4   The Meanwhile Project
5 
6   This is a tool which can act as a proxy between a client and a
7   sametime server, which will force all channels to be created without
8   any encryption method. This makes reverse-engineering much, much
9   easier.
10 
11   It also outputs the messages sent to and from the client to stdout
12   as hex pairs. If compiled with USE_HEXDUMP, output will be printed
13   via `hexdump -C`
14 
15   All it really does is nab all Channel Create messages, strip the
16   offered ciphers portion from the message and replace it with an
17   empty ciphers list.
18 
19   Christopher O'Brien <siege@preoccupied.net>
20 */
21 
22 
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30 
31 #include <glib.h>
32 #include <glib.h>
33 
34 #include <mw_common.h>
35 #include <mw_message.h>
36 
37 
38 struct proxy_side {
39   int sock;
40   GIOChannel *chan;
41   gint chan_io;
42 
43   guchar *buf;
44   gsize buf_size;
45   gsize buf_recv;
46 
47   void (*forward)(const guchar *buf, gsize len);
48 };
49 
50 
51 static struct proxy_side client;
52 static struct proxy_side server;
53 
54 
hexdump(const char * txt,const guchar * buf,gsize len)55 static void hexdump(const char *txt, const guchar *buf, gsize len) {
56   FILE *fp;
57 
58   if(txt) fprintf(stdout, "\n%s\n", txt);
59   fflush(stdout);
60 
61   fp = popen("hexdump -C", "w");
62   fwrite(buf, len, 1, fp);
63   fflush(fp);
64   pclose(fp);
65 }
66 
67 
put_msg(struct mwMessage * msg,struct mwOpaque * o)68 static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
69   struct mwPutBuffer *b;
70 
71   b = mwPutBuffer_new();
72   mwMessage_put(b, msg);
73   mwPutBuffer_finalize(o, b);
74 
75   b = mwPutBuffer_new();
76   mwOpaque_put(b, o);
77   mwOpaque_clear(o);
78   mwPutBuffer_finalize(o, b);
79 }
80 
81 
side_buf_free(struct proxy_side * s)82 static void side_buf_free(struct proxy_side *s) {
83   g_free(s->buf);
84   s->buf = NULL;
85   s->buf_size = 0;
86   s->buf_recv = 0;
87 }
88 
89 
munge_redir()90 static void munge_redir() {
91   struct mwMessage *msg;
92   struct mwOpaque o = { 0, 0 };
93 
94   msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
95   put_msg(msg, &o);
96   mwMessage_free(msg);
97 
98   server.forward(o.data, o.len);
99 
100   mwOpaque_clear(&o);
101 }
102 
103 
munge_create(struct proxy_side * side,struct mwMsgChannelCreate * msg)104 static void munge_create(struct proxy_side *side,
105 			 struct mwMsgChannelCreate *msg) {
106 
107   struct mwOpaque o = { 0, 0 };
108   GList *l;
109 
110   for(l = msg->encrypt.items; l; l = l->next) {
111     mwEncryptItem_clear(l->data);
112     g_free(l->data);
113   }
114   g_list_free(msg->encrypt.items);
115   msg->encrypt.items = NULL;
116 
117   msg->encrypt.mode = 0x00;
118   msg->encrypt.extra = 0x00;
119   msg->encrypt.flag = FALSE;
120 
121   put_msg(MW_MESSAGE(msg), &o);
122   side->forward(o.data, o.len);
123   mwOpaque_clear(&o);
124 }
125 
126 
side_process(struct proxy_side * s,const guchar * buf,gsize len)127 static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
128   struct mwOpaque o = { .len = len, .data = (guchar *) buf };
129   struct mwGetBuffer *b;
130   guint16 type;
131 
132   if(! len) return;
133 
134   b = mwGetBuffer_wrap(&o);
135   type = guint16_peek(b);
136 
137   switch(type) {
138   case mwMessage_LOGIN_REDIRECT:
139     munge_redir();
140     break;
141 
142   case mwMessage_CHANNEL_CREATE:
143     {
144       struct mwMessage *msg = mwMessage_get(b);
145       munge_create(s, (struct mwMsgChannelCreate *) msg);
146       mwMessage_free(msg);
147       break;
148     }
149 
150   default:
151     {
152       struct mwPutBuffer *pb = mwPutBuffer_new();
153       struct mwOpaque po = { 0, 0 };
154       mwOpaque_put(pb, &o);
155       mwPutBuffer_finalize(&po, pb);
156       s->forward(po.data, po.len);
157       mwOpaque_clear(&po);
158     }
159   }
160 
161   mwGetBuffer_free(b);
162 }
163 
164 
165 #define ADVANCE(b, n, count) { b += count; n -= count; }
166 
167 
168 /* handle input to complete an existing buffer */
side_recv_cont(struct proxy_side * s,const guchar * b,gsize n)169 static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
170 
171   gsize x = s->buf_size - s->buf_recv;
172 
173   if(n < x) {
174     memcpy(s->buf+s->buf_recv, b, n);
175     s->buf_recv += n;
176     return 0;
177 
178   } else {
179     memcpy(s->buf+s->buf_recv, b, x);
180     ADVANCE(b, n, x);
181 
182     if(s->buf_size == 4) {
183       struct mwOpaque o = { .len = 4, .data = s->buf };
184       struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
185       x = guint32_peek(gb);
186       mwGetBuffer_free(gb);
187 
188       if(n < x) {
189 	guchar *t;
190 	x += 4;
191 	t = (guchar *) g_malloc(x);
192 	memcpy(t, s->buf, 4);
193 	memcpy(t+4, b, n);
194 
195 	side_buf_free(s);
196 
197 	s->buf = t;
198 	s->buf_size = x;
199 	s->buf_recv = n + 4;
200 	return 0;
201 
202       } else {
203 	side_buf_free(s);
204 	side_process(s, b, x);
205 	ADVANCE(b, n, x);
206       }
207 
208     } else {
209       side_process(s, s->buf+4, s->buf_size-4);
210       side_buf_free(s);
211     }
212   }
213 
214   return n;
215 }
216 
217 
218 /* handle input when there's nothing previously buffered */
side_recv_empty(struct proxy_side * s,const guchar * b,gsize n)219 static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
220   struct mwOpaque o = { .len = n, .data = (guchar *) b };
221   struct mwGetBuffer *gb;
222   gsize x;
223 
224   if(n < 4) {
225     s->buf = (guchar *) g_malloc0(4);
226     memcpy(s->buf, b, n);
227     s->buf_size = 4;
228     s->buf_recv = n;
229     return 0;
230   }
231 
232   gb = mwGetBuffer_wrap(&o);
233   x = guint32_peek(gb);
234   mwGetBuffer_free(gb);
235   if(! x) return n - 4;
236 
237   if(n < (x + 4)) {
238 
239     x += 4;
240     s->buf = (guchar *) g_malloc(x);
241     memcpy(s->buf, b, n);
242     s->buf_size = x;
243     s->buf_recv = n;
244     return 0;
245 
246   } else {
247     ADVANCE(b, n, 4);
248     side_process(s, b, x);
249     ADVANCE(b, n, x);
250 
251     return n;
252   }
253 }
254 
255 
side_recv(struct proxy_side * s,const guchar * b,gsize n)256 static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
257 
258   if(n && (s->buf_size == 0) && (*b & 0x80)) {
259     ADVANCE(b, n, 1);
260   }
261 
262   if(n == 0) {
263     return 0;
264 
265   } else if(s->buf_size > 0) {
266     return side_recv_cont(s, b, n);
267 
268   } else {
269     return side_recv_empty(s, b, n);
270   }
271 }
272 
273 
feed_buf(struct proxy_side * side,const guchar * buf,gsize n)274 static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
275   guchar *b = (guchar *) buf;
276   gsize remain = 0;
277 
278   g_return_if_fail(side != NULL);
279 
280   while(n > 0) {
281     remain = side_recv(side, b, n);
282     b += (n - remain);
283     n = remain;
284   }
285 }
286 
287 
read_recv(struct proxy_side * side)288 static int read_recv(struct proxy_side *side) {
289   guchar buf[2048];
290   int len;
291 
292   len = read(side->sock, buf, 2048);
293   if(len > 0) feed_buf(side, buf, (gsize) len);
294 
295   return len;
296 }
297 
298 
done()299 static void done() {
300   close(client.sock);
301   close(server.sock);
302   exit(0);
303 }
304 
305 
read_cb(GIOChannel * chan,GIOCondition cond,gpointer data)306 static gboolean read_cb(GIOChannel *chan,
307 			GIOCondition cond,
308 			gpointer data) {
309 
310   struct proxy_side *side = data;
311   int ret = 0;
312 
313   if(cond & G_IO_IN) {
314     ret = read_recv(side);
315     if(ret > 0) return TRUE;
316   }
317 
318   if(side->sock) {
319     g_source_remove(side->chan_io);
320     close(side->sock);
321     side->sock = 0;
322     side->chan = NULL;
323     side->chan_io = 0;
324   }
325 
326   done();
327 
328   return FALSE;
329 }
330 
331 
client_cb(const guchar * buf,gsize len)332 static void client_cb(const guchar *buf, gsize len) {
333   if(server.sock) {
334     hexdump("client -> server", buf, len);
335     write(server.sock, buf, len);
336   }
337 }
338 
339 
listen_cb(GIOChannel * chan,GIOCondition cond,gpointer data)340 static gboolean listen_cb(GIOChannel *chan,
341 			  GIOCondition cond,
342 			  gpointer data) {
343 
344   struct sockaddr_in rem;
345   guint len = sizeof(rem);
346   struct proxy_side *side = data;
347   int sock;
348 
349   sock = accept(side->sock, (struct sockaddr *) &rem, &len);
350   g_assert(sock > 0);
351 
352   g_source_remove(side->chan_io);
353   side->sock = sock;
354   side->chan = g_io_channel_unix_new(sock);
355   side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
356 				 read_cb, side);
357 
358   return FALSE;
359 }
360 
361 
init_client(int port)362 static void init_client(int port) {
363   /* start listening on the local port specifier */
364 
365   struct sockaddr_in sin;
366   int sock;
367 
368   sock = socket(PF_INET, SOCK_STREAM, 0);
369   g_assert(sock >= 0);
370 
371   memset(&sin, 0, sizeof(struct sockaddr_in));
372   sin.sin_family = PF_INET;
373   sin.sin_port = htons(port);
374   sin.sin_addr.s_addr = htonl(INADDR_ANY);
375 
376   if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
377     g_assert_not_reached();
378 
379   if(listen(sock, 1) < 0)
380     g_assert_not_reached();
381 
382   client.forward = client_cb;
383   client.sock = sock;
384   client.chan = g_io_channel_unix_new(sock);
385   client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
386 				  listen_cb, &client);
387 }
388 
389 
server_cb(const guchar * buf,gsize len)390 static void server_cb(const guchar *buf, gsize len) {
391   if(client.sock) {
392     hexdump("server -> client", buf, len);
393     write(client.sock, buf, len);
394   }
395 }
396 
397 
398 /* address lookup used by init_sock */
init_sockaddr(struct sockaddr_in * addr,const char * host,int port)399 static void init_sockaddr(struct sockaddr_in *addr,
400 			  const char *host, int port) {
401 
402   struct hostent *hostinfo;
403 
404   addr->sin_family = AF_INET;
405   addr->sin_port = htons (port);
406   hostinfo = gethostbyname(host);
407   if(hostinfo == NULL) {
408     fprintf(stderr, "Unknown host %s.\n", host);
409     exit(1);
410   }
411   addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
412 }
413 
414 
init_server(const char * host,int port)415 static void init_server(const char *host, int port) {
416   /* connect to server on host/port */
417   struct sockaddr_in srvrname;
418   int sock;
419 
420   sock = socket(PF_INET, SOCK_STREAM, 0);
421   if(sock < 0) {
422     fprintf(stderr, "socket failure");
423     exit(1);
424   }
425 
426   init_sockaddr(&srvrname, host, port);
427   connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
428 
429   server.forward = server_cb;
430   server.sock = sock;
431   server.chan = g_io_channel_unix_new(sock);
432   server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
433 				  read_cb, &server);
434 }
435 
436 
main(int argc,char * argv[])437 int main(int argc, char *argv[]) {
438   char *host = NULL;
439   int client_port = 0, server_port = 0;
440 
441   memset(&client, 0, sizeof(struct proxy_side));
442   memset(&server, 0, sizeof(struct proxy_side));
443 
444   if(argc > 1) {
445     char *z;
446 
447     host = argv[1];
448     z = host;
449 
450     host = strchr(z, ':');
451     if(host) *host++ = '\0';
452     client_port = atoi(z);
453 
454     z = strchr(host, ':');
455     if(z) *z++ = '\0';
456     server_port = atoi(z);
457   }
458 
459   if(!host || !*host || !client_port || !server_port) {
460     fprintf(stderr,
461 	    ( " Usage: %s local_port:remote_host:remote_port\n"
462 	      " Creates a locally-running sametime proxy which enforces"
463 	      " unencrypted channels\n" ),
464 	    argv[0]);
465     exit(1);
466   }
467 
468   /* @todo create signal handlers to cleanup sockets */
469 
470   init_client(client_port);
471   init_server(host, server_port);
472 
473   g_main_loop_run(g_main_loop_new(NULL, FALSE));
474   return 0;
475 }
476 
477