1 /*
2 * This file handles TCP client-to-client communications.
3 *
4 * Author/Copyright: James Schofield (jschofield@ottawa.com) 22 Feb 2001
5 * Lots of changes from Rüdiger Kuhlmann. File transfer by Rüdiger Kuhlmann.
6 * This file may be distributed under version 2 of the GPL licence.
7 *
8 * $Id: oscar_dc.c 2851 2010-03-06 18:16:56Z kuhlmann $
9 */
10
11 #include "climm.h"
12 #include "util_ui.h"
13 #include "util_io.h"
14 #include "file_util.h"
15 #include "util.h"
16 #include "buildmark.h"
17 #include "conv.h"
18 #include "cmd_user.h"
19 #include "im_response.h"
20 #include "preferences.h"
21 #include "im_request.h"
22 #include "contact.h"
23 #include "connection.h"
24 #include "packet.h"
25 #include "oscar_dc.h"
26 #include "util_syntax.h"
27 #include "oscar_snac.h"
28 #include "oscar_service.h"
29 #include "oscar_icbm.h"
30 #include "oscar_base.h"
31
32 #include <unistd.h>
33 #include <assert.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #if HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
38 #endif
39 #if HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45 #if HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 #if HAVE_WINSOCK2_H
49 #include <winsock2.h>
50 #endif
51
52 #ifdef ENABLE_SSL
53 #define CV_ORIGIN_dcssl (peer->ssl_status == SSL_STATUS_OK ? CV_ORIGIN_ssl : CV_ORIGIN_dc)
54 #else
55 #define CV_ORIGIN_dcssl CV_ORIGIN_dc
56 #endif
57
58 #define ASSERT_ANY_DIRECT(s) (assert (s), assert ((s)->type & TYPEF_ANY_DIRECT), assert ((s)->serv), ASSERT_ANY_LISTEN ((s)->serv->oscar_dc))
59 #define ASSERT_ANY_LISTEN(s) (assert (s), assert ((s)->type & TYPEF_ANY_LISTEN), assert ((s)->serv))
60
61 #define LICQ_WITHSSL 0x7D800000 /* taken from licq 1.2.7 */
62
63 #ifdef ENABLE_PEER2PEER
64
65 static void TCPDispatchPeer (Connection *peer);
66
67 static Packet *TCPReceivePacket (Connection *peer);
68
69 static void TCPSendInit (Connection *peer);
70 static void TCPSendInitAck (Connection *peer);
71 static void TCPSendInit2 (Connection *peer);
72 static Connection *TCPReceiveInit (Connection *peer, Packet *pak);
73 static void TCPReceiveInitAck (Connection *peer, Packet *pak);
74 static Connection *TCPReceiveInit2 (Connection *peer, Packet *pak);
75
76
77 static Packet *PacketTCPC (Connection *peer, UDWORD cmd);
78
79 static void TCPCallBackTimeout (Event *event);
80 static void TCPCallBackResend (Event *event);
81 static void TCPCallBackReceive (Event *event);
82
83 static void Encrypt_Pak (Connection *peer, Packet *pak);
84 static BOOL Decrypt_Pak (Connection *peer, Packet *pak);
85
86 static void TCPSendInitv6 (Connection *peer);
87
88 int PeerSSLSupported (Connection *conn DEBUGPARAM);
89 #define PeerSSLSupported(c) PeerSSLSupported(c DEBUGARGS)
90
91 /*********************************************/
92
93 /*
94 * "Logs in" peer2peer connection by opening listening socket.
95 */
ConnectionInitPeer(Connection * list)96 Event *ConnectionInitPeer (Connection *list)
97 {
98 ASSERT_MSGLISTEN (list);
99
100 if (list->version < 6 || list->version > 8)
101 {
102 rl_printf (i18n (2024, "Unknown protocol version %d for ICQ peer-to-peer protocol.\n"), list->version);
103 return NULL;
104 }
105
106 if (list->version == 6)
107 rl_print (i18n (2046, "You may want to use protocol version 8 for the ICQ peer-to-peer protocol instead.\n"));
108
109 rl_printf (i18n (2521, "Opening peer-to-peer connection at %slocalhost%s:%s%ld%s... "),
110 COLQUOTE, COLNONE, COLQUOTE, UD2UL (list->port), COLNONE);
111
112 list->connect = 0;
113 list->oscar_dc_seq = -1;
114 list->dispatch = &TCPDispatchMain;
115 list->oscar_our_session = 0;
116 list->ip = 0;
117 s_repl (&list->server, NULL);
118 list->port = ServerPrefVal (list->serv, CO_OSCAR_DC_PORT);
119 list->cont = list->serv->conn->cont;
120
121 UtilIOListenTCP (list);
122 return NULL;
123 }
124
125 /*
126 * Starts establishing a TCP connection to given contact.
127 */
TCPDirectOpen(Connection * list,Contact * cont)128 BOOL TCPDirectOpen (Connection *list, Contact *cont)
129 {
130 Connection *peer;
131
132 ASSERT_MSGLISTEN (list);
133 assert (cont);
134
135 if (!cont || !cont->dc || cont->dc->version < 6)
136 return FALSE;
137 if (cont == list->cont)
138 return FALSE;
139
140 if (!(peer = ServerFindChild (list->serv, cont, TYPE_MSGDIRECT)))
141 if (!(peer = ServerChild (list->serv, cont, TYPE_MSGDIRECT)))
142 return FALSE;
143
144 ASSERT_MSGDIRECT (peer);
145
146 if (peer->connect & CONNECT_MASK)
147 return TRUE;
148
149 peer->version = list->version <= cont->dc->version ? list->version : cont->dc->version;
150 peer->port = 0;
151 peer->cont = cont;
152 peer->oscar_file= NULL;
153 peer->dispatch = &TCPDispatchConn;
154 s_repl (&peer->server, NULL);
155
156 if (peer->type == TYPE_MSGDIRECT)
157 peer->port = cont->dc->port;
158
159 if (cont->dc->ip_rem && cont->dc->port && ~cont->dc->ip_rem)
160 {
161 peer->connect = 0;
162 peer->ip = cont->dc->ip_rem;
163 }
164 else if (cont->dc->ip_loc && cont->dc->port && ~cont->dc->ip_loc)
165 {
166 peer->connect = 2;
167 peer->ip = cont->dc->ip_loc;
168 }
169 else
170 {
171 peer->connect = CONNECT_FAIL;
172 return FALSE;
173 }
174
175 if (prG->verbose)
176 {
177 rl_log_for (cont->nick, COLCONTACT);
178 rl_printf (i18n (2522, "Opening TCP connection at %s:%s%ld%s... "),
179 s_wordquote (s_ip (peer->ip)), COLQUOTE, UD2UL (peer->port), COLNONE);
180 rl_printf ("\n");
181 }
182 UtilIOConnectTCP (peer);
183 return TRUE;
184 }
185
186 /*
187 * Closes TCP message/file connection(s) to given contact.
188 */
TCPDirectClose(Connection * list,Contact * cont)189 void TCPDirectClose (Connection *list, Contact *cont)
190 {
191 Connection *peer;
192
193 ASSERT_MSGLISTEN (list);
194 assert (cont);
195
196 while ((peer = ServerFindChild (list->serv, cont, TYPEF_ANY_DIRECT)))
197 TCPClose (peer);
198 }
199
200 /*
201 * Switchs off TCP for a given uin.
202 */
TCPDirectOff(Connection * list,Contact * cont)203 void TCPDirectOff (Connection *list, Contact *cont)
204 {
205 Connection *peer;
206
207 ASSERT_MSGLISTEN (list);
208 assert (cont);
209
210 if (!(peer = ServerFindChild (list->serv, cont, TYPE_MSGDIRECT)))
211 if (!(peer = ServerChild (list->serv, cont, TYPE_MSGDIRECT)))
212 return;
213
214 peer->cont = cont;
215 peer->connect = CONNECT_FAIL;
216
217 ASSERT_MSGDIRECT(peer);
218
219 if (peer->incoming)
220 {
221 PacketD (peer->incoming);
222 peer->incoming = NULL;
223 }
224 }
225
226 /**************************************************/
227
228 /*
229 * Reconnect hook. Actually, just inform the user.
230 */
TCPDispatchReconn(Connection * peer)231 void TCPDispatchReconn (Connection *peer)
232 {
233 ASSERT_ANY_DIRECT(peer);
234
235 if (prG->verbose)
236 {
237 Contact *cont = peer->cont;
238
239 rl_log_for (cont->nick, COLCONTACT);
240 rl_print (i18n (2023, "Direct connection closed by peer.\n"));
241 }
242 TCPClose (peer);
243 }
244
245 /*
246 * Accepts a new direct connection.
247 */
TCPDispatchMain(Connection * list)248 void TCPDispatchMain (Connection *list)
249 {
250 Connection *peer;
251 int rc;
252 io_err_t rce;
253
254 ASSERT_ANY_LISTEN(list);
255
256 if (~list->connect & CONNECT_OK)
257 {
258 rc = UtilIOAccept (list, NULL);
259 assert (rc <= 0);
260 rce = UtilIOShowError (list, rc);
261 if (rce == IO_CONNECTED)
262 {
263 list->connect |= CONNECT_OK;
264 if (list->type == TYPE_MSGLISTEN && list->serv && list->serv->type == TYPE_SERVER
265 && (list->serv->conn->connect & CONNECT_OK))
266 SnacCliSetstatus (list->serv, ims_online, 2);
267 }
268 else if (rce != IO_OK)
269 list->connect = CONNECT_FAIL;
270 return;
271 }
272
273 if (list->version == 6)
274 rl_print (i18n (2046, "You may want to use protocol version 8 for the ICQ peer-to-peer protocol instead.\n"));
275
276 peer = ServerChild (list->serv, list->cont, list->type == TYPE_MSGLISTEN ? TYPE_MSGDIRECT : TYPE_FILEDIRECT);
277 if (!peer)
278 {
279 rl_print (i18n (1914, "Can't allocate connection structure.\n"));
280 UtilIOClose (list);
281 return;
282 }
283
284 rc = UtilIOAccept (list, peer);
285 if (rc <= 0)
286 {
287 rce = UtilIOShowError (list, rc);
288 switch (rce)
289 {
290 case IO_OK:
291 case IO_RW:
292 ConnectionD (peer);
293 return;
294 case IO_CONNECTED:
295 default:
296 assert (0);
297 }
298 }
299 else
300 {
301 peer->oscar_our_session = 0;
302 peer->dispatch = &TCPDispatchShake;
303 peer->sok = rc;
304 peer->connect = 16 | CONNECT_SELECT_R;
305 peer->cont = NULL;
306 }
307 }
308
309 /*
310 * Continues connecting.
311 */
TCPDispatchConn(Connection * peer)312 void TCPDispatchConn (Connection *peer)
313 {
314 Contact *cont;
315 int rc;
316 io_err_t rce;
317
318 ASSERT_ANY_DIRECT (peer);
319
320 if (!(cont = peer->cont) || !cont->dc)
321 {
322 TCPClose (peer);
323 return;
324 }
325
326 rc = UtilIORead (peer, NULL, 0);
327 assert (rc <= 0);
328 rce = UtilIOShowError (peer, rc);
329 if (rce == IO_CONNECTED)
330 {
331 if (prG->verbose)
332 {
333 rl_log_for (cont->nick, COLCONTACT);
334 rl_printf (i18n (2522, "Opening TCP connection at %s:%s%ld%s... "),
335 s_wordquote (s_ip (peer->ip)), COLQUOTE, UD2UL (peer->port), COLNONE);
336 rl_print (i18n (1785, "success.\n"));
337 }
338 QueueEnqueueData (peer, QUEUE_TCP_TIMEOUT, peer->ip, time (NULL) + 10,
339 NULL, cont, NULL, &TCPCallBackTimeout);
340 peer->connect = 1 | CONNECT_SELECT_R;
341 peer->dispatch = &TCPDispatchShake;
342 #ifdef ENABLE_SSL
343 /* We only set that status from here since we don't initialize
344 * SSL for incoming connections.
345 */
346 peer->ssl_status = SSL_STATUS_REQUEST;
347 #endif
348 TCPDispatchShake (peer);
349 return;
350
351 }
352 else if (rce == IO_OK)
353 return;
354 else if (rce == IO_RW && (peer->connect & 7) == 0 && cont->dc->ip_loc && ~cont->dc->ip_loc)
355 {
356 peer->connect = 2;
357 peer->ip = cont->dc->ip_loc;
358 if (prG->verbose)
359 {
360 rl_log_for (cont->nick, COLCONTACT);
361 rl_printf (i18n (2522, "Opening TCP connection at %s:%s%ld%s... "),
362 s_wordquote (s_ip (peer->ip)), COLQUOTE, UD2UL (peer->port), COLNONE);
363 }
364 rl_printf ("\n");
365 UtilIOConnectTCP (peer);
366 }
367 else
368 {
369 if (prG->verbose)
370 rl_printf (i18n (1855, "TCP connection to %s at %s:%ld failed.\n"),
371 cont->nick, s_ip (peer->ip), UD2UL (peer->port));
372 peer->connect = CONNECT_FAIL;
373 return;
374 }
375 }
376
377 /*
378 * Shake hands with peer.
379 */
TCPDispatchShake(Connection * peer)380 void TCPDispatchShake (Connection *peer)
381 {
382 Contact *cont;
383 Packet *pak = NULL;
384
385 ASSERT_ANY_DIRECT (peer);
386
387 if ((peer->connect & CONNECT_MASK) != 1)
388 if (!(pak = TCPReceivePacket (peer)))
389 return;
390
391 while (1)
392 {
393 if (!peer)
394 return;
395
396 if (!(cont = peer->cont) && (peer->connect & CONNECT_MASK) != 16)
397 {
398 TCPClose (peer);
399 peer->connect = CONNECT_FAIL;
400 if (pak)
401 PacketD (pak);
402 return;
403 }
404
405 DebugH (DEB_TCP, "HS %d uin %s nick %s state %d pak %p peer %p",
406 peer->sok, cont ? cont->screen : 0, cont ? cont->nick : "<>", peer->connect, pak, peer);
407
408 switch (peer->connect & CONNECT_MASK)
409 {
410 case 1:
411 peer->connect++;
412 TCPSendInit (peer);
413 return;
414 case 2:
415 peer->connect++;
416 TCPReceiveInitAck (peer, pak);
417 PacketD (pak);
418 return;
419 case 3:
420 peer->connect++;
421 peer = TCPReceiveInit (peer, pak);
422 PacketD (pak);
423 pak = NULL;
424 continue;
425 case 4:
426 peer->connect++;
427 TCPSendInitAck (peer);
428 continue;
429 case 5:
430 peer->connect++;
431 if (peer->version > 6 && peer->type == TYPE_MSGDIRECT)
432 {
433 TCPSendInit2 (peer);
434 return;
435 }
436 continue;
437 case 6:
438 peer->connect = 7 | CONNECT_SELECT_R;
439 if (peer->version > 6 && peer->type == TYPE_MSGDIRECT)
440 {
441 peer = TCPReceiveInit2 (peer, pak);
442 PacketD (pak);
443 pak = NULL;
444 }
445 continue;
446 case 7:
447 peer->connect = 48 | CONNECT_SELECT_R;
448 continue;
449 case 16:
450 peer->connect++;
451 peer = TCPReceiveInit (peer, pak);
452 PacketD (pak);
453 pak = NULL;
454 continue;
455 case 17:
456 peer->connect++;
457 TCPSendInitAck (peer);
458 continue;
459 case 18:
460 peer->connect++;
461 TCPSendInit (peer);
462 return;
463 case 19:
464 peer->connect++;
465 TCPReceiveInitAck (peer, pak);
466 PacketD (pak);
467 if (peer->version > 6 && peer->type == TYPE_MSGDIRECT)
468 return;
469 pak = NULL;
470 continue;
471 case 20:
472 peer->connect++;
473 if (peer->version > 6 && peer->type == TYPE_MSGDIRECT)
474 {
475 peer = TCPReceiveInit2 (peer, pak);
476 PacketD (pak);
477 pak = NULL;
478 }
479 continue;
480 case 21:
481 peer->connect = 48 | CONNECT_SELECT_R;
482 if (peer->version > 6 && peer->type == TYPE_MSGDIRECT)
483 TCPSendInit2 (peer);
484 continue;
485 case 48:
486 EventD (QueueDequeue (peer, QUEUE_TCP_TIMEOUT, peer->ip));
487 if (prG->verbose)
488 {
489 rl_log_for (cont->nick, COLCONTACT);
490 rl_print (i18n (1833, "Peer to peer TCP connection established.\n"));
491 }
492 peer->connect = CONNECT_OK | CONNECT_SELECT_R;
493 if (peer->type == TYPE_FILEDIRECT)
494 {
495 peer->dispatch = &PeerFileDispatch;
496 QueueRetry (peer, QUEUE_PEER_FILE, cont);
497 }
498 else if (peer->type == TYPE_MSGDIRECT)
499 {
500 peer->dispatch = &TCPDispatchPeer;
501 QueueRetry (peer, QUEUE_TCP_RESEND, cont);
502 }
503 #ifdef ENABLE_SSL
504 /* outgoing peer connection established */
505 if (peer->type == TYPE_MSGDIRECT && peer->ssl_status == SSL_STATUS_REQUEST && PeerSSLSupported (peer))
506 if (!TCPSendSSLReq (peer->serv->oscar_dc, cont))
507 rl_printf (i18n (2372, "Could not send SSL request to %s\n"), cont->nick);
508 #endif
509 return;
510 case 0:
511 return;
512 default:
513 assert (0);
514 }
515 }
516 }
517
518 /*
519 * Handles all incoming TCP traffic.
520 * Queues incoming packets, ignoring resends
521 * and deleting CANCEL requests from the queue.
522 */
TCPDispatchPeer(Connection * peer)523 static void TCPDispatchPeer (Connection *peer)
524 {
525 Contact *cont;
526 Packet *pak;
527 UWORD seq_in = 0, seq, cmd;
528
529 ASSERT_MSGDIRECT (peer);
530
531 if (!(cont = peer->cont))
532 {
533 TCPClose (peer);
534 return;
535 }
536
537 peer->connect &= ~CONNECT_SELECT_W;
538
539 if (!(pak = TCPReceivePacket (peer)))
540 return;
541
542 if (peer->version > 6)
543 PacketRead1 (pak);
544 PacketRead4 (pak);
545 cmd = PacketReadAt2 (pak, PacketReadPos (pak));
546 seq = PacketReadAt2 (pak, PacketReadPos (pak) + 4);
547
548 /* Make sure this isn't a resend */
549 if ((seq_in == 0) || (seq < seq_in))
550 {
551 seq_in = seq;
552 /* Store the event in the recv queue for handling later */
553 QueueEnqueueData (peer, QUEUE_TCP_RECEIVE, seq_in, 0, pak, cont,
554 OptSetVals (NULL, CO_ORIGIN, CV_ORIGIN_dcssl, 0),
555 &TCPCallBackReceive);
556 peer->oscar_dc_seq--;
557 }
558 }
559
560 /*********************************************/
561
562 /*
563 * Handles timeout on TCP send/read/whatever
564 */
TCPCallBackTimeout(Event * event)565 static void TCPCallBackTimeout (Event *event)
566 {
567 Connection *peer = event->conn;
568
569 if (!peer)
570 {
571 EventD (event);
572 return;
573 }
574 ASSERT_ANY_DIRECT (peer);
575 assert (event->type == QUEUE_TCP_TIMEOUT);
576
577 if ((peer->connect & CONNECT_MASK) && prG->verbose)
578 {
579 Contact *cont;
580
581 if ((cont = peer->cont))
582 rl_printf (i18n (1850, "Timeout on connection with %s at %s:%ld\n"),
583 cont->nick, s_ip (peer->ip), UD2UL (peer->port));
584 TCPClose (peer);
585 }
586 EventD (event);
587 }
588
589 /*
590 * Receives an incoming TCP packet.
591 * Resets socket on error. Paket must be freed.
592 */
TCPReceivePacket(Connection * peer)593 static Packet *TCPReceivePacket (Connection *peer)
594 {
595 Packet *pak;
596
597 ASSERT_ANY_DIRECT (peer);
598
599 if (!(peer->connect & CONNECT_MASK))
600 return NULL;
601
602 pak = UtilIOReceiveTCP2 (peer);
603
604 if (!peer->connect)
605 {
606 TCPClose (peer);
607 if (pak)
608 PacketD (pak);
609 return NULL;
610 }
611
612 if (!pak)
613 return NULL;
614
615 peer->stat_pak_rcvd++;
616
617 if (peer->connect & CONNECT_OK && peer->type == TYPE_MSGDIRECT)
618 {
619 if (!Decrypt_Pak (peer, pak))
620 {
621 if (prG->verbose & DEB_TCP)
622 {
623 rl_printf ("%s " COLINDENT "%s", s_now, COLSERVER);
624 rl_printf (i18n (1789, "Received malformed packet: (%d)"), peer->sok);
625 rl_printf ("%s\n", COLNONE);
626 rl_print (s_dump (pak->data, pak->len));
627 rl_print (COLEXDENT "\r");
628
629 }
630 TCPClose (peer);
631 PacketD (pak);
632 return NULL;
633 }
634 }
635
636 if (prG->verbose & DEB_PACKTCP)
637 TCPPrint (pak, peer, FALSE);
638
639 pak->rpos = 0;
640 pak->wpos = 0;
641
642 return pak;
643 }
644
645 /*
646 * Creates a peer-to-peer packet.
647 */
PeerPacketC(Connection * peer,UBYTE cmd)648 Packet *PeerPacketC (Connection *peer, UBYTE cmd)
649 {
650 Packet *pak;
651
652 ASSERT_ANY_DIRECT (peer);
653
654 pak = PacketC ();
655 if (peer->type != TYPE_MSGDIRECT || peer->version > 6 || cmd != PEER_MSG)
656 PacketWrite1 (pak, cmd);
657 return pak;
658 }
659
660 /*
661 * Encrypts and sends a TCP packet.
662 * Resets socket on error.
663 */
PeerPacketSend(Connection * peer,Packet * pak)664 void PeerPacketSend (Connection *peer, Packet *pak)
665 {
666 Packet *tpak;
667
668 ASSERT_ANY_DIRECT (peer);
669 assert (pak);
670
671 if (!(peer->connect & CONNECT_MASK))
672 return;
673
674 if (prG->verbose & DEB_PACKTCP)
675 TCPPrint (pak, peer, TRUE);
676
677 tpak = PacketC ();
678 assert (tpak);
679
680 PacketWriteAt2 (tpak, 0, pak->len);
681 memcpy (tpak->data + 2, pak->data, pak->len);
682 tpak->len = pak->len + 2;
683
684 if (peer->type == TYPE_MSGDIRECT)
685 if (PacketReadAt1 (pak, 0) == PEER_MSG || (!PacketReadAt1 (pak, 0) && peer->type == TYPE_MSGDIRECT && peer->version == 6))
686 Encrypt_Pak (peer, tpak);
687
688 UtilIOSendTCP2 (peer, tpak);
689 }
690
691
692 /*
693 * Sends a TCP initialization packet.
694 */
TCPSendInitv6(Connection * peer)695 static void TCPSendInitv6 (Connection *peer)
696 {
697 Packet *pak;
698
699 ASSERT_ANY_DIRECT (peer);
700 assert (peer->cont);
701
702 if (!(peer->connect & CONNECT_MASK))
703 return;
704
705 if (!(peer->oscar_our_session))
706 peer->oscar_our_session = rand ();
707
708 pak = PeerPacketC (peer, PEER_INIT);
709 PacketWrite2 (pak, 6); /* TCP version */
710 PacketWrite2 (pak, 0); /* TCP revision */
711 PacketWrite4 (pak, peer->cont->uin); /* destination UIN */
712 PacketWrite2 (pak, 0); /* unknown - zero */
713 PacketWrite4 (pak, peer->serv->oscar_dc->port); /* our port */
714 PacketWrite4 (pak, peer->serv->oscar_uin); /* our UIN */
715 PacketWriteB4 (pak, peer->serv->conn->our_outside_ip); /* our (remote) IP */
716 PacketWriteB4 (pak, peer->serv->conn->our_local_ip); /* our (local) IP */
717 PacketWrite1 (pak, ServerPrefVal (peer->serv, CO_OSCAR_DC_MODE) & 15); /* connection type */
718 PacketWrite4 (pak, peer->serv->oscar_dc->port); /* our (other) port */
719 PacketWrite4 (pak, peer->oscar_our_session); /* session id */
720
721 DebugH (DEB_TCP, "HS %d uin %s CONNECT pak %p peer %p",
722 peer->sok, peer->cont->screen, pak, peer);
723
724 PeerPacketSend (peer, pak);
725 PacketD (pak);
726 }
727
728 /*
729 * Sends a v7/v8 TCP initialization packet.
730 */
TCPSendInit(Connection * peer)731 static void TCPSendInit (Connection *peer)
732 {
733 Packet *pak;
734
735 ASSERT_ANY_DIRECT (peer);
736
737 if (peer->version == 6)
738 {
739 TCPSendInitv6 (peer);
740 return;
741 }
742
743 if (!(peer->connect & CONNECT_MASK))
744 return;
745
746 if (!peer->oscar_our_session)
747 {
748 Contact *cont;
749
750 if (!(cont = peer->cont) || !cont->dc)
751 {
752 TCPClose (peer);
753 return;
754 }
755 peer->oscar_our_session = cont->dc->cookie;
756 }
757
758 pak = PeerPacketC (peer, PEER_INIT);
759 PacketWrite2 (pak, peer->version); /* TCP version */
760 PacketWrite2 (pak, 43); /* length */
761 PacketWrite4 (pak, peer->cont->uin); /* destination UIN */
762 PacketWrite2 (pak, 0); /* unknown - zero */
763 PacketWrite4 (pak, peer->serv->oscar_dc->port); /* our port */
764 PacketWrite4 (pak, peer->serv->oscar_uin); /* our UIN */
765 PacketWriteB4 (pak, peer->serv->conn->our_outside_ip); /* our (remote) IP */
766 PacketWriteB4 (pak, peer->serv->conn->our_local_ip); /* our (local) IP */
767 PacketWrite1 (pak, ServerPrefVal (peer->serv, CO_OSCAR_DC_MODE) & 15); /* connection type */
768 PacketWrite4 (pak, peer->serv->oscar_dc->port); /* our (other) port */
769 PacketWrite4 (pak, peer->oscar_our_session); /* session id */
770 PacketWrite4 (pak, 0x00000050);
771 PacketWrite4 (pak, 0x00000003);
772 PacketWrite4 (pak, 0);
773
774 DebugH (DEB_TCP, "HS %d uin %s CONNECTv8 pak %p peer %p",
775 peer->sok, peer->cont->screen, pak, peer);
776
777 PeerPacketSend (peer, pak);
778 PacketD (pak);
779 }
780
781 /*
782 * Sends the initialization acknowledge packet
783 */
TCPSendInitAck(Connection * peer)784 static void TCPSendInitAck (Connection *peer)
785 {
786 Packet *pak;
787
788 ASSERT_ANY_DIRECT (peer);
789 assert (peer->cont);
790
791 if (!(peer->connect & CONNECT_MASK))
792 return;
793
794 pak = PeerPacketC (peer, PEER_INITACK);
795 PacketWrite1 (pak, 0);
796 PacketWrite2 (pak, 0);
797
798 DebugH (DEB_TCP, "HS %d uin %s INITACK pak %p peer %p",
799 peer->sok, peer->cont->screen, pak, peer);
800
801 PeerPacketSend (peer, pak);
802 PacketD (pak);
803 }
804
TCPSendInit2(Connection * peer)805 static void TCPSendInit2 (Connection *peer)
806 {
807 Packet *pak;
808
809 ASSERT_ANY_DIRECT (peer);
810 assert (peer->cont);
811 assert (peer->version > 6);
812
813 if (!(peer->connect & CONNECT_MASK))
814 return;
815
816 pak = PeerPacketC (peer, PEER_INIT2);
817 PacketWrite4 (pak, 10);
818 PacketWrite4 (pak, 1);
819 PacketWrite4 (pak, (peer->connect & 16) ? 1 : 0);
820 PacketWrite4 (pak, 0);
821 PacketWrite4 (pak, 0);
822 PacketWrite4 (pak, (peer->connect & 16) ? 0x40001 : 0);
823 PacketWrite4 (pak, 0);
824 PacketWrite4 (pak, (peer->connect & 16) ? 0 : 0x40001);
825
826 DebugH (DEB_TCP, "HS %d uin %s INITMSG pak %p peer %p",
827 peer->sok, peer->cont->screen, pak, peer);
828
829 PeerPacketSend (peer, pak);
830 PacketD (pak);
831 }
832
833 #define FAIL(x) { err = x; break; }
834
TCPReceiveInit(Connection * peer,Packet * pak)835 static Connection *TCPReceiveInit (Connection *peer, Packet *pak)
836 {
837 Contact *cont;
838 UDWORD muin, uin, sid, port, port2, oip, iip;
839 UWORD cmd, len, len2, tcpflag, err, nver, i;
840 Connection *peer2;
841
842 ASSERT_ANY_DIRECT (peer);
843 assert (pak);
844
845 err = 0;
846 while (1)
847 {
848 cmd = PacketRead1 (pak);
849 nver = PacketRead2 (pak);
850 len = PacketRead2 (pak);
851 len2 = PacketReadLeft (pak);
852 muin = PacketRead4 (pak);
853 PacketRead2 (pak);
854 port = PacketRead4 (pak);
855 uin = PacketRead4 (pak);
856 oip = PacketReadB4 (pak);
857 iip = PacketReadB4 (pak);
858 tcpflag = PacketRead1 (pak);
859 port2 = PacketRead4 (pak);
860 sid = PacketRead4 (pak);
861
862 /* check validity of this connection; fail silently */
863
864 if (cmd != PEER_INIT)
865 FAIL (1);
866
867 if (nver < 6)
868 FAIL (2);
869
870 if (nver > 6 && len != len2)
871 FAIL (3);
872
873 if (nver == 6 && 23 > len2)
874 FAIL (4);
875
876 if (muin != peer->serv->oscar_uin)
877 FAIL (5);
878
879 if (uin == peer->serv->oscar_uin)
880 FAIL (6);
881
882 if (!(cont = ContactUIN (peer->serv, uin)))
883 FAIL (7);
884
885 if (!CONTACT_DC (cont))
886 FAIL (10);
887
888 if (port && port2 && port != port2)
889 FAIL (11);
890
891 peer->version = (peer->serv->pref_version > nver ? nver : peer->serv->pref_version);
892
893 if (!peer->oscar_our_session)
894 peer->oscar_our_session = peer->version > 6 ? cont->dc->cookie : sid;
895 if (sid != peer->oscar_our_session)
896 FAIL (8);
897
898 if (ContactPrefVal (cont, CO_IGNORE))
899 FAIL (9);
900
901 /* okay, the connection seems not to be faked, so update using the following information. */
902
903 peer->cont = cont;
904 if (port) cont->dc->port = port;
905 if (oip) cont->dc->ip_rem = oip;
906 if (iip) cont->dc->ip_loc = iip;
907 if (tcpflag) cont->dc->type = tcpflag;
908
909 DebugH (DEB_TCP, "HS %d uin %s nick %s init pak %p peer %p: ver %04x:%04x port %ld uin %ld SID %08lx type %x",
910 peer->sok, cont->screen, cont->nick, pak, peer, peer->version, len, UD2UL (port), UD2UL (uin), UD2UL (sid), peer->type);
911
912 for (i = 0; (peer2 = ConnectionNr (i)); i++)
913 if ( peer2->type == peer->type && peer2->serv == peer->serv
914 && peer2->cont == peer->cont && !peer->oscar_file && peer2 != peer)
915 break;
916
917 if (peer2)
918 {
919 if (peer2->connect & CONNECT_OK)
920 {
921 TCPClose (peer);
922 ConnectionD (peer);
923 return NULL;
924 }
925 /* if ((peer2->connect & CONNECT_MASK) == (UDWORD)TCP_STATE_WAITING)
926 EventD (QueueDequeue (peer2, QUEUE_TCP_TIMEOUT, peer2->ip)); */
927 if (peer2->sok == -1 && peer2->type == TYPE_FILEDIRECT)
928 {
929 peer2->sok = peer->sok;
930 peer2->oscar_our_session = peer->oscar_our_session;
931 peer2->version = peer->version;
932 peer2->connect = peer->connect | CONNECT_SELECT_R;
933 peer2->dispatch = peer->dispatch;
934 peer->sok = -1;
935 ConnectionD (peer);
936 return peer2;
937 }
938 if (peer2->sok != -1)
939 TCPClose (peer2);
940 peer->oscar_file_len = peer2->oscar_file_len;
941 ConnectionD (peer2);
942 }
943 return peer;
944 }
945 if ((prG->verbose & DEB_TCP) && err)
946 rl_printf ("%s %s: %d\n", s_now, i18n (2029, "Protocol error on peer-to-peer connection"), err);
947
948 TCPClose (peer);
949 return NULL;
950 }
951
952 /*
953 * Receives the acknowledge packet for the initialization packet.
954 */
TCPReceiveInitAck(Connection * peer,Packet * pak)955 static void TCPReceiveInitAck (Connection *peer, Packet *pak)
956 {
957 ASSERT_ANY_DIRECT (peer);
958 assert (pak);
959
960 if (pak->len != 4 || PacketReadAt4 (pak, 0) != PEER_INITACK)
961 {
962 DebugH (DEB_TCP, "Received malformed initialization acknowledgement packet.\n");
963 TCPClose (peer);
964 }
965 }
966
TCPReceiveInit2(Connection * peer,Packet * pak)967 static Connection *TCPReceiveInit2 (Connection *peer, Packet *pak)
968 {
969 UWORD cmd, err;
970 UDWORD ten, one;
971
972 ASSERT_MSGDIRECT (peer);
973 assert (pak);
974
975 if (!pak)
976 return peer;
977
978 err = 0;
979 while (1)
980 {
981 cmd = PacketRead1 (pak);
982 ten = PacketRead4 (pak);
983 one = PacketRead4 (pak);
984
985 if (cmd != PEER_INIT2)
986 FAIL (201);
987
988 if (ten != 10)
989 FAIL (202);
990
991 if (one != 1)
992 FAIL (0);
993
994 return peer;
995 }
996
997 if (err && (prG->verbose & (DEB_TCP | DEB_PROTOCOL)))
998 rl_printf ("%s %s: %d\n", s_now, i18n (2029, "Protocol error on peer-to-peer connection"), err);
999 else
1000 peer->connect = 0;
1001 TCPClose (peer);
1002 return NULL;
1003 }
1004
1005 /*
1006 * Check whether peer supports SSL
1007 *
1008 * Returns 0 if SSL/TLS not supported by peer.
1009 */
1010 #undef PeerSSLSupported
PeerSSLSupported(Connection * conn DEBUGPARAM)1011 int PeerSSLSupported (Connection *conn DEBUGPARAM)
1012 {
1013 Contact *cont;
1014 UBYTE status_save = conn->ssl_status;
1015
1016 if (UtilIOSSLSupported() != IO_SSL_OK)
1017 return 0;
1018
1019 if (conn->ssl_status == SSL_STATUS_OK)
1020 return 1; /* SSL session already established */
1021
1022 if (conn->ssl_status == SSL_STATUS_FAILED)
1023 return 0; /* ssl handshake with peer already failed. So don't try again */
1024
1025 conn->ssl_status = SSL_STATUS_FAILED;
1026
1027 if (!(conn->type & TYPEF_ANY_PEER))
1028 return 0;
1029
1030 cont = conn->cont;
1031
1032 /* check for peer capabilities
1033 * Note: we never initialize SSL for incoming direct connections yet
1034 * in order to avoid mutual SSL init trials among climm peers.
1035 */
1036 if (!cont)
1037 return 0;
1038
1039 if (!(HAS_CAP (cont->caps, CAP_SIMNEW) || HAS_CAP (cont->caps, CAP_MICQ)
1040 || HAS_CAP (cont->caps, CAP_CLIMM) || HAS_CAP (cont->caps, CAP_LICQNEW)
1041 || (cont->dc && (cont->dc->id1 & 0xFFFF0000) == LICQ_WITHSSL)))
1042 {
1043 Debug (DEB_SSL, "%s (%s) is no SSL candidate", cont->nick, cont->screen);
1044 TCLEvent (cont, "ssl", "no_candidate");
1045 return 0;
1046 }
1047
1048 conn->ssl_status = status_save;
1049 Debug (DEB_SSL, "%s (%s) is an SSL candidate", cont->nick, cont->screen);
1050 TCLEvent (cont, "ssl", "candidate");
1051 return 1;
1052 }
1053
1054 /*
1055 * Request secure channel in licq's way.
1056 */
TCPSendSSLReq(Connection * list,Contact * cont)1057 BOOL TCPSendSSLReq (Connection *list, Contact *cont)
1058 {
1059 Connection *peer;
1060 UBYTE ret;
1061
1062 ret = PeerSendMsg (list, cont, MSG_SSL_OPEN, "");
1063 if ((peer = ServerFindChild (list->serv, cont, TYPE_MSGDIRECT)))
1064 peer->ssl_status = SSL_STATUS_REQUEST;
1065 return ret;
1066 }
1067
1068
1069 /*
1070 * Close socket and mark as inactive. If verbose, complain.
1071 */
TCPClose(Connection * peer)1072 void TCPClose (Connection *peer)
1073 {
1074 UWORD connect;
1075 assert (peer);
1076
1077 connect = (peer->connect & CONNECT_MASK && !(peer->connect & CONNECT_OK)) ? CONNECT_FAIL : 0;
1078
1079 if (peer->oscar_file)
1080 {
1081 assert (peer->oscar_file->type == TYPE_FILE);
1082 ConnectionD (peer->oscar_file);
1083 }
1084 if (peer->sok != -1)
1085 {
1086 if (peer->connect & CONNECT_MASK && prG->verbose)
1087 {
1088 Contact *cont = peer->cont;
1089 rl_printf ("%s ", s_now);
1090 if (cont)
1091 rl_printf (i18n (1842, "Closing socket %d to %s.\n"), peer->sok, cont->nick);
1092 else
1093 rl_printf (i18n (1843, "Closing socket %d.\n"), peer->sok);
1094 }
1095 }
1096 UtilIOClose (peer);
1097 peer->connect = connect;
1098 peer->oscar_our_session = 0;
1099 if (peer->incoming)
1100 {
1101 PacketD (peer->incoming);
1102 peer->incoming = NULL;
1103 }
1104 if (peer->type == TYPE_FILEDIRECT || !peer->cont)
1105 ConnectionD (peer);
1106 }
1107
TCPCmdName(UWORD cmd)1108 static const char *TCPCmdName (UWORD cmd)
1109 {
1110 static char buf[8];
1111
1112 switch (cmd)
1113 {
1114 case PEER_INIT: return "PEER_INIT";
1115 case PEER_INITACK: return "PEER_INITACK";
1116 case PEER_MSG: return "PEER_MSG";
1117 case PEER_INIT2: return "PEER_INIT2";
1118
1119 case TCP_CMD_CANCEL: return "CANCEL";
1120 case TCP_CMD_ACK: return "ACK";
1121 case TCP_CMD_MESSAGE: return "MSG";
1122
1123 case 0x0029: return "FILEREQ";
1124 case 0x002d: return "CHATREQ";
1125 case 0x0032: return "FILEACK";
1126 }
1127 snprintf (buf, sizeof (buf), "%04x", cmd);
1128 buf[7] = '\0';
1129 return buf;
1130 }
1131
1132 /*
1133 * Output a TCP packet for debugging.
1134 */
TCPPrint(Packet * pak,Connection * peer,BOOL out)1135 void TCPPrint (Packet *pak, Connection *peer, BOOL out)
1136 {
1137 UWORD cmd;
1138 Contact *cont;
1139 char *f;
1140
1141 ASSERT_ANY_DIRECT(peer);
1142
1143 pak->rpos = 0;
1144 cmd = *pak->data;
1145 cont = peer->cont;
1146
1147 rl_printf ("%s " COLINDENT "%s", s_now, out ? COLCLIENT : COLSERVER);
1148 rl_printf (out ? i18n (2078, "Outgoing TCP packet (%d - %s): %s")
1149 : i18n (2079, "Incoming TCP packet (%d - %s): %s"),
1150 peer->sok, cont ? cont->nick : "", TCPCmdName (cmd));
1151 rl_printf ("%s\n", COLNONE);
1152
1153 if (peer->connect & CONNECT_OK && peer->type == TYPE_MSGDIRECT && peer->version == 6)
1154 {
1155 cmd = 2;
1156 pak->rpos --;
1157 }
1158
1159 if (prG->verbose & DEB_PACKTCPDATA)
1160 if (cmd != 6)
1161 {
1162 rl_print (f = PacketDump (pak, peer->type == TYPE_MSGDIRECT ? "gpeer" : "gfile", COLDEBUG, COLNONE));
1163 free (f);
1164 }
1165
1166 rl_print (COLEXDENT "\r");
1167 }
1168
1169 /*
1170 * Create and setup a TCP communication packet.
1171 */
PacketTCPC(Connection * peer,UDWORD cmd)1172 static Packet *PacketTCPC (Connection *peer, UDWORD cmd)
1173 {
1174 Packet *pak;
1175
1176 ASSERT_ANY_DIRECT(peer);
1177
1178 pak = PeerPacketC (peer, PEER_MSG);
1179 PacketWrite4 (pak, 0); /* checksum - filled in later */
1180 PacketWrite2 (pak, cmd); /* command */
1181 return pak;
1182 }
1183
PeerSendMsg(Connection * list,Contact * cont,UDWORD type,const char * text)1184 UBYTE PeerSendMsg (Connection *list, Contact *cont, UDWORD type, const char *text)
1185 {
1186 UBYTE ret;
1187 Message *msg = MsgC ();
1188
1189 msg->send_message = strdup (text);
1190 msg->cont = cont;
1191 msg->type = type;
1192 ret = PeerSendMsgFat (list, cont, msg);
1193 if (!RET_IS_OK (ret))
1194 MsgD (msg);
1195 return ret;
1196 }
1197
1198 /*
1199 * Sends a message via TCP.
1200 * Adds it to the resend queue until acked.
1201 */
PeerSendMsgFat(Connection * list,Contact * cont,Message * msg)1202 UBYTE PeerSendMsgFat (Connection *list, Contact *cont, Message *msg)
1203 {
1204 Packet *pak;
1205 Connection *peer;
1206 Event *event;
1207
1208 ASSERT_MSGLISTEN(list);
1209 assert (cont);
1210 assert (msg);
1211 assert (msg->cont == cont);
1212 assert (msg->send_message);
1213
1214 if (!cont->uin)
1215 return RET_DEFER;
1216 if (cont->uin == list->serv->oscar_uin || !(list->connect & CONNECT_MASK))
1217 return RET_DEFER;
1218
1219 if (!cont->dc || !cont->dc->port || (!cont->dc->ip_loc && !cont->dc->ip_rem))
1220 {
1221 if (HAS_CAP (cont->caps, CAP_REVCONNREQ))
1222 SnacCliSendIP (list->serv, cont);
1223 return RET_DEFER;
1224 }
1225
1226 switch (msg->type & 0xff)
1227 {
1228 case MSG_NORM:
1229 case MSG_URL:
1230 case MSG_GET_AWAY:
1231 case MSG_GET_OCC:
1232 case MSG_GET_NA:
1233 case MSG_GET_DND:
1234 case MSG_GET_FFC:
1235 case MSG_SSL_OPEN:
1236 case MSG_SSL_CLOSE:
1237 case MSG_GET_VER:
1238 break;
1239 default:
1240 return RET_DEFER;
1241 }
1242
1243 if ((peer = ServerFindChild (list->serv, cont, TYPE_MSGDIRECT)))
1244 if (peer->connect & CONNECT_FAIL)
1245 {
1246 if (HAS_CAP (cont->caps, CAP_REVCONNREQ) && ~peer->connect & 1)
1247 {
1248 SnacCliSendIP (list->serv, cont);
1249 peer->connect |= 1;
1250 }
1251 return RET_DEFER;
1252 }
1253
1254 if (!peer || ~peer->connect & CONNECT_OK)
1255 {
1256 TCPDirectOpen (list, cont);
1257 return RET_DEFER;
1258 }
1259
1260 ASSERT_MSGDIRECT(peer);
1261
1262 pak = PacketTCPC (peer, TCP_CMD_MESSAGE);
1263 SrvMsgAdvanced (pak, peer->oscar_dc_seq, msg->type, list->serv->status,
1264 cont->status, -1, c_out_for (msg->send_message, cont, msg->type));
1265 PacketWrite4 (pak, TCP_COL_FG); /* foreground color */
1266 PacketWrite4 (pak, TCP_COL_BG); /* background color */
1267 if (CONT_UTF8 (cont, msg->type))
1268 PacketWriteDLStr (pak, CAP_GID_UTF8);
1269
1270 event = QueueEnqueueData2 (peer, QUEUE_TCP_RESEND, peer->oscar_dc_seq--, 0, msg, &TCPCallBackResend, NULL);
1271 event->cont = cont;
1272 event->pak = pak;
1273 return RET_INPR;
1274 }
1275
1276 /*
1277 * Sends a message via TCP.
1278 * Adds it to the resend queue until acked.
1279 */
TCPSendFiles(Connection * list,Contact * cont,const char * description,const char ** files,const char ** as,int count)1280 BOOL TCPSendFiles (Connection *list, Contact *cont, const char *description, const char **files, const char **as, int count)
1281 {
1282 Packet *pak;
1283 Event *event;
1284 Connection *peer, *flist, *fpeer;
1285 int i, rc, sumlen, sum;
1286 time_t now = time (NULL);
1287 str_s filenames = { NULL, 0, 0};
1288 Message *msg;
1289
1290 ASSERT_MSGLISTEN(list);
1291 assert (cont);
1292
1293 if (!count)
1294 return TRUE;
1295 if (count < 0)
1296 return FALSE;
1297 if (!cont->uin)
1298 return FALSE;
1299 if (!cont->dc || !cont->dc->port)
1300 return FALSE;
1301
1302 if (cont->uin == list->serv->oscar_uin)
1303 return FALSE;
1304 if (!(list->connect & CONNECT_MASK))
1305 return FALSE;
1306 if (!cont->dc->ip_loc && !cont->dc->ip_rem)
1307 return FALSE;
1308
1309 if (!TCPDirectOpen (list, cont))
1310 return FALSE;
1311 if (!(peer = ServerFindChild (list->serv, cont, TYPE_MSGDIRECT)))
1312 return FALSE;
1313 if (peer->connect & CONNECT_FAIL)
1314 return FALSE;
1315
1316 ASSERT_MSGDIRECT(peer);
1317
1318 if (!(flist = PeerFileCreate (peer->serv)))
1319
1320 ASSERT_FILELISTEN(flist);
1321
1322 if (ServerFindChild (flist->serv, cont, TYPE_FILEDIRECT))
1323 return FALSE;
1324
1325 fpeer = ServerChild (flist->serv, cont, TYPE_FILEDIRECT);
1326
1327 ASSERT_FILEDIRECT(fpeer);
1328
1329 fpeer->connect = 77;
1330 fpeer->version = flist->version;
1331
1332 s_init (&filenames, "", 0);
1333 for (sumlen = sum = i = 0; i < count; i++)
1334 {
1335 struct stat fstat;
1336
1337 if (stat (files[i], &fstat))
1338 {
1339 rc = errno;
1340 rl_printf (i18n (2071, "Couldn't stat file %s: %s (%d)\n"),
1341 files[i], strerror (rc), rc);
1342 }
1343 else
1344 {
1345 rl_log_for (cont->nick, COLCONTACT);
1346 rl_printf (i18n (2091, "Queueing %s as %s for transfer.\n"), files[i], as[i]);
1347 if (sum)
1348 s_catn (&filenames, ", ", 2);
1349 s_cat (&filenames, as[i]);
1350 sum++;
1351 sumlen += fstat.st_size;
1352 pak = PeerPacketC (fpeer, 2);
1353 PacketWrite1 (pak, 0);
1354 PacketWriteLNTS (pak, c_out_to (as[i], cont));
1355 PacketWriteLNTS (pak, "");
1356 PacketWrite4 (pak, fstat.st_size);
1357 PacketWrite4 (pak, 0);
1358 PacketWrite4 (pak, 64);
1359 QueueEnqueueData (fpeer, QUEUE_PEER_FILE, sum, now, pak, cont,
1360 OptSetVals (NULL, CO_FILENAME, files[i], 0), &PeerFileResend);
1361 }
1362 }
1363
1364 if (!sum)
1365 {
1366 ConnectionD (fpeer);
1367 s_done (&filenames);
1368 return FALSE;
1369 }
1370
1371 pak = PeerPacketC (fpeer, 0);
1372 PacketWrite4 (pak, 0);
1373 PacketWrite4 (pak, sum);
1374 PacketWrite4 (pak, sumlen);
1375 PacketWrite4 (pak, 64);
1376 PacketWriteLNTS (pak, cont->nick);
1377 QueueEnqueueData (fpeer, QUEUE_PEER_FILE, 0, now, pak, cont,
1378 OptSetVals (NULL, CO_MSGTYPE, MSG_FILE, CO_MSGTEXT, description, 0),
1379 &PeerFileResend);
1380
1381 if (peer->version < 8)
1382 {
1383 pak = PacketTCPC (peer, TCP_CMD_MESSAGE);
1384 SrvMsgAdvanced (pak, peer->oscar_dc_seq, MSG_FILE, list->serv->status,
1385 cont->status, -1, c_out_to_split (description, cont));
1386 PacketWrite2 (pak, 0);
1387 PacketWrite2 (pak, 0);
1388 PacketWriteLNTS (pak, filenames.txt);
1389 PacketWrite4 (pak, sumlen);
1390 PacketWrite4 (pak, 0);
1391 }
1392 else
1393 {
1394 pak = PacketTCPC (peer, TCP_CMD_MESSAGE);
1395 SrvMsgAdvanced (pak, peer->oscar_dc_seq, MSG_EXTENDED, list->serv->status,
1396 cont->status, -1, "");
1397 SrvMsgGreet (pak, 0x29, description, 0, sumlen, filenames.txt);
1398 }
1399
1400 msg = MsgC ();
1401 msg->type = MSG_FILE;
1402 msg->send_message = strdup (description);
1403 msg->cont = cont;
1404 event = QueueEnqueueData2 (peer, QUEUE_TCP_RESEND, peer->oscar_dc_seq--, 0, msg, &TCPCallBackResend, NULL);
1405 event->cont = cont;
1406 event->pak = pak;
1407
1408 s_done (&filenames);
1409 return TRUE;
1410 }
1411
1412 /*
1413 * Resends TCP packets if necessary
1414 */
TCPCallBackResend(Event * event)1415 static void TCPCallBackResend (Event *event)
1416 {
1417 Contact *cont = event->cont;
1418 UWORD delta;
1419 char isfile;
1420 Connection *peer = event->conn;
1421 Packet *pak = event->pak;
1422 Message *msg = event->data;
1423
1424 assert (msg);
1425 assert (cont);
1426 assert (pak);
1427 assert (msg->cont == cont);
1428 assert (msg->send_message);
1429
1430 if (!peer)
1431 {
1432 rl_printf (i18n (2092, "TCP message %s discarded - lost session.\n"), msg->send_message);
1433 MsgD (msg);
1434 event->data = NULL;
1435 EventD (event);
1436 return;
1437 }
1438 isfile = msg->type == MSG_FILE || msg->type == MSG_SSL_OPEN;
1439
1440 ASSERT_MSGDIRECT (peer);
1441
1442 if (peer->connect & CONNECT_MASK && event->attempts < (isfile ? MAX_RETRY_P2PFILE_ATTEMPTS : MAX_RETRY_P2P_ATTEMPTS))
1443 {
1444 if (peer->connect & CONNECT_OK)
1445 {
1446 if (event->attempts > 1)
1447 IMIntMsg (cont, NOW, ims_offline, INT_MSGTRY_DC, msg->send_message);
1448
1449 if (event->attempts < 2)
1450 PeerPacketSend (peer, pak);
1451 event->attempts++;
1452 event->due = time (NULL) + QUEUE_P2P_RESEND_ACK;
1453 }
1454 else
1455 event->due = time (NULL) + 1;
1456 QueueEnqueue (event);
1457 return;
1458 }
1459
1460 if (!isfile)
1461 {
1462 TCPClose (peer);
1463 peer->connect = CONNECT_FAIL;
1464 msg->trans &= ~CV_MSGTRANS_DC;
1465 delta = (peer->version > 6 ? 1 : 0);
1466 if (PacketReadAt2 (pak, 4 + delta) == TCP_CMD_MESSAGE)
1467 {
1468 IMCliReMsg (cont, msg);
1469 event->data = NULL;
1470 msg = NULL;
1471 }
1472 else
1473 rl_printf (i18n (1844, "TCP message %04x discarded after timeout.\n"), PacketReadAt2 (pak, 4 + delta));
1474 }
1475 MsgD (msg);
1476 event->data = NULL;
1477 EventD (event);
1478 }
1479
PeerCallbackReceiveAdvanced(Event * event)1480 static void PeerCallbackReceiveAdvanced (Event *event)
1481 {
1482 DebugH (DEB_TCP, "%p %p %p\n", event, event ? event->conn : NULL, event ? event->pak : NULL);
1483 if (event && event->conn && event->pak && event->conn->type & TYPEF_ANY_DIRECT)
1484 PeerPacketSend (event->conn, event->pak);
1485 #if ENABLE_SSL
1486 switch (event->conn->ssl_status)
1487 {
1488 case SSL_STATUS_INIT:
1489 UtilIOSSLOpen (event->conn, 0);
1490 break;
1491 case SSL_STATUS_CLOSE:
1492 /* Could not figure out how to say good bye to licq correctly.
1493 * That's why we do a simple close.
1494 */
1495 UtilIOClose (event->conn);
1496 break;
1497 default:
1498 DebugH (DEB_SSL, "SSL state on receive %d\n", event->conn->ssl_status);
1499 }
1500 #endif /* ENABLE_SSL */
1501 EventD (event);
1502 }
1503
1504 /*
1505 * Handles a just received packet.
1506 */
TCPCallBackReceive(Event * event)1507 static void TCPCallBackReceive (Event *event)
1508 {
1509 Server *serv;
1510 Connection *peer;
1511 Event *oldevent;
1512 Contact *cont;
1513 Packet *pak, *ack_pak = NULL;
1514 strc_t ctmp, ctext, cname, creason;
1515 char *tmp, *text, *name;
1516 UWORD cmd, type, seq, port /*, unk*/;
1517 /* UDWORD len, flags, xtmp1, xtmp2, xtmp3; */
1518 status_t status;
1519 UDWORD ostat;
1520 UDWORD opt_origin;
1521
1522 if (!OptGetVal (event->opt, CO_ORIGIN, &opt_origin))
1523 opt_origin = 0;
1524
1525 if (!(peer = event->conn) || !(cont = event->cont))
1526 {
1527 EventD (event);
1528 return;
1529 }
1530
1531 ASSERT_MSGDIRECT (peer);
1532 assert (event->pak);
1533
1534 pak = event->pak;
1535 serv = peer->serv;
1536 pak->tpos = pak->rpos;
1537
1538 cmd = PacketRead2 (pak);
1539
1540 switch (cmd)
1541 {
1542 Message *msg;
1543 case TCP_CMD_ACK:
1544 /*unk=*/ PacketRead2 (pak);
1545 seq = PacketRead2 (pak);
1546 /*xtmp1*/PacketRead4 (pak);
1547 /*xtmp2*/PacketRead4 (pak);
1548 /*xtmp3*/PacketRead4 (pak);
1549 type = PacketRead2 (pak);
1550 ostat = PacketRead2 (pak);
1551 status = IcqToStatus (ostat);
1552 /*flags*/PacketRead2 (pak);
1553 ctmp = PacketReadL2Str (pak, NULL);
1554
1555 if (!(oldevent = QueueDequeue (peer, QUEUE_TCP_RESEND, seq)))
1556 break;
1557
1558 msg = oldevent->data;
1559 oldevent->data = NULL;
1560 assert (msg);
1561 assert (oldevent->conn);
1562 assert (oldevent->cont);
1563 assert (oldevent->cont == cont);
1564
1565 if (msg->type != type && type != MSG_EXTENDED)
1566 {
1567 /* D'oh! */
1568 rl_printf ("FIXME: message type mismatch: %d vs %ld\n", type, UD2UL (msg->type)); /* FIXME */
1569 MsgD (msg);
1570 EventD (oldevent);
1571 break;
1572 }
1573
1574 tmp = strdup (ConvFromCont (ctmp, cont));
1575
1576 switch (type)
1577 {
1578 case MSG_NORM:
1579 case MSG_URL:
1580 if (!msg->otrinjected)
1581 {
1582 msg->type = opt_origin == CV_ORIGIN_dc ? INT_MSGACK_DC : INT_MSGACK_SSL;
1583 IMIntMsgMsg (msg, NOW, ims_offline);
1584 if (~cont->oldflags & CONT_SEENAUTO && strlen (tmp) && strcmp (tmp, msg->send_message))
1585 {
1586 IMSrvMsg (cont, NOW, opt_origin, MSG_AUTO, tmp);
1587 cont->oldflags |= CONT_SEENAUTO;
1588 }
1589 }
1590 break;
1591
1592 case MSGF_GETAUTO | MSG_GET_AWAY:
1593 case MSGF_GETAUTO | MSG_GET_OCC:
1594 case MSGF_GETAUTO | MSG_GET_NA:
1595 case MSGF_GETAUTO | MSG_GET_DND:
1596 case MSGF_GETAUTO | MSG_GET_FFC:
1597 case MSGF_GETAUTO | MSG_GET_VER:
1598 IMSrvMsgFat (cont, NOW, OptSetVals (NULL, CO_ORIGIN, opt_origin, CO_MSGTYPE, msg->type,
1599 CO_MSGTEXT, tmp, CO_STATUS, IcqToStatus (ostat & ~MSGF_GETAUTO), 0));
1600 break;
1601
1602 case MSG_FILE:
1603 port = PacketReadB2 (pak);
1604 if (PeerFileAccept (peer, ostat, port))
1605 IMIntMsgFat (cont, NOW, status, INT_FILE_ACKED, tmp, msg->plain_message ? msg->plain_message : msg->send_message, port, 0);
1606 else
1607 IMIntMsgFat (cont, NOW, status, INT_FILE_REJED, tmp, msg->plain_message ? msg->plain_message : msg->send_message, 0, 0);
1608 break;
1609 #ifdef ENABLE_SSL
1610 /* We never stop SSL connections on our own. That's why
1611 * MSG_SSL_CLOSE is not handled here.
1612 */
1613 case MSG_SSL_OPEN:
1614 if (!ostat && !strcmp (tmp, "1"))
1615 UtilIOSSLOpen (event->conn, 1);
1616 else
1617 {
1618 DebugH (DEB_SSL, "%s (%s) is not SSL capable", cont->nick, cont->screen);
1619 #ifdef ENABLE_TCL
1620 TCLEvent (cont, "ssl", "incapable");
1621 #endif
1622 }
1623 break;
1624 #endif
1625 case MSG_EXTENDED:
1626 cmd = PacketRead2 (pak);
1627 PacketReadB4 (pak); /* ID */
1628 PacketReadB4 (pak);
1629 PacketReadB4 (pak);
1630 PacketReadB4 (pak);
1631 PacketRead2 (pak); /* EMPTY */
1632 ctext = PacketReadL4Str (pak, NULL);
1633 PacketReadB4 (pak); /* UNKNOWN */
1634 PacketReadB4 (pak);
1635 PacketReadB4 (pak);
1636 PacketReadB2 (pak);
1637 PacketRead1 (pak);
1638 PacketRead4 (pak); /* LEN */
1639 creason= PacketReadL4Str (pak, NULL);
1640 port = PacketReadB2 (pak);
1641 PacketRead2 (pak); /* PAD */
1642 cname = PacketReadL2Str (pak, NULL);
1643 /*len=*/ PacketRead4 (pak);
1644 /* PORT2 ignored */
1645
1646 text = strdup (ConvFromCont (ctext, cont));
1647 name = strdup (ConvFromCont (cname, cont));
1648
1649 switch (cmd)
1650 {
1651 case 0x0029:
1652 if (PeerFileAccept (peer, ostat, port))
1653 IMIntMsgFat (cont, NOW, status, INT_FILE_ACKED, tmp, msg->plain_message ? msg->plain_message : msg->send_message, port, 0);
1654 else
1655 IMIntMsgFat (cont, NOW, status, INT_FILE_REJED, tmp, msg->plain_message ? msg->plain_message : msg->send_message, 0, 0);
1656 break;
1657
1658 default:
1659 cmd = 0;
1660 }
1661 free (name);
1662 free (text);
1663 if (cmd)
1664 break;
1665
1666 /* fall through */
1667 default:
1668 DebugH (DEB_TCP, "ACK %d uin %s nick %s pak %p peer %p seq %04x",
1669 peer->sok, cont->screen, cont->nick, oldevent->pak, peer, seq);
1670 }
1671 free (tmp);
1672 MsgD (msg);
1673 EventD (oldevent);
1674 break;
1675
1676 case TCP_CMD_MESSAGE:
1677 ack_pak = PacketTCPC (peer, TCP_CMD_ACK);
1678 event->opt = OptSetVals (event->opt, CO_ORIGIN, opt_origin, 0);
1679 oldevent = QueueEnqueueData (event->conn, QUEUE_ACKNOWLEDGE, rand () % 0xff,
1680 (time_t)-1, ack_pak, cont, NULL, &PeerCallbackReceiveAdvanced);
1681 SrvReceiveAdvanced (serv, event, event->pak, oldevent);
1682 break;
1683 }
1684 EventD (event);
1685 }
1686
1687 /*
1688 *
1689 * Encryption/Decryption
1690 *
1691 */
1692
1693 const UBYTE client_check_data[] = {
1694 "As part of this software beta version Mirabilis is "
1695 "granting a limited access to the ICQ network, "
1696 "servers, directories, listings, information and databases (\""
1697 "ICQ Services and Information\"). The "
1698 "ICQ Service and Information may databases (\""
1699 "ICQ Services and Information\"). The "
1700 "ICQ Service and Information may\0"
1701 };
1702
1703 /*
1704 * Encrypts/Decrypts TCP packets
1705 * (leeched from licq)
1706 */
Encrypt_Pak(Connection * peer,Packet * pak)1707 static void Encrypt_Pak (Connection *peer, Packet *pak)
1708 {
1709 UDWORD B1, M1, check, size, i;
1710 UBYTE X1, X2, X3, *p;
1711 UDWORD hex, key;
1712
1713 p = pak->data + 2;
1714 size = pak->len - 2;
1715
1716 if (peer->version > 6)
1717 {
1718 p++;
1719 size--;
1720 }
1721
1722 /* calculate verification data */
1723 M1 = (rand() % ((size < 255 ? size : 255) - 10)) + 10;
1724 X1 = p[M1] ^ 0xff;
1725 X2 = rand() % 220;
1726 X3 = client_check_data[X2] ^ 0xff;
1727 B1 = (p[4] << 24) | (p[6] << 16) | (p[4] << 8) | p[6];
1728
1729 /* calculate checkcode */
1730 check = (M1 << 24) | (X1 << 16) | (X2 << 8) | X3;
1731 check ^= B1;
1732
1733 /* main XOR key */
1734 key = 0x67657268 * size + check;
1735
1736 /* XORing the actual data */
1737 for (i = 0; i < (size + 3) / 4; )
1738 {
1739 hex = key + client_check_data[i & 0xff];
1740 p[i++] ^= hex & 0xff;
1741 p[i++] ^= (hex >> 8) & 0xff;
1742 p[i++] ^= (hex >> 16) & 0xff;
1743 p[i++] ^= (hex >> 24) & 0xff;
1744 }
1745
1746 /* storing the checkcode */
1747 PacketWriteAt4 (pak, peer->version > 6 ? 3 : 2, check);
1748 }
1749
Decrypt_Pak(Connection * peer,Packet * pak)1750 static BOOL Decrypt_Pak (Connection *peer, Packet *pak)
1751 {
1752 UDWORD hex, key, B1, M1, check, i, size;
1753 UBYTE X1, X2, X3, *p;
1754
1755 p = pak->data;
1756 size = pak->len;
1757
1758 if (peer->version > 6)
1759 {
1760 p++;
1761 size--;
1762 }
1763
1764 /* Get checkcode */
1765 check = PacketReadAt4 (pak, peer->version > 6 ? 1 : 0);
1766
1767 /* primary decryption */
1768 key = 0x67657268 * size + check;
1769
1770 for (i = 4; i < (size + 3) / 4; )
1771 {
1772 hex = key + client_check_data[i & 0xff];
1773 p[i++] ^= hex & 0xff;
1774 p[i++] ^= (hex >> 8) & 0xff;
1775 p[i++] ^= (hex >> 16) & 0xff;
1776 p[i++] ^= (hex >> 24) & 0xff;
1777 }
1778
1779 B1 = (p[4]<<24) | (p[6]<<16) | (p[4]<<8) | (p[6]<<0);
1780
1781 /* special decryption */
1782 B1 ^= check;
1783
1784 /* validate packet */
1785 M1 = (B1 >> 24) & 0xFF;
1786 if (M1 < 10 || M1 >= size)
1787 return (-1);
1788
1789 X1 = p[M1] ^ 0xFF;
1790 if (((B1 >> 16) & 0xFF) != X1)
1791 return (-1);
1792
1793 X2 = ((B1 >> 8) & 0xFF);
1794 if (X2 < 220)
1795 {
1796 X3 = client_check_data[X2] ^ 0xFF;
1797 if((B1 & 0xFF) != X3)
1798 return FALSE;
1799 }
1800
1801 return TRUE;
1802 }
1803 #endif /* ENABLE_PEER2PEER */
1804