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