1 /*
2  * botnet.c -- handles:
3  *   keeping track of which bot's connected where in the chain
4  *   dumping a list of bots or a bot tree to a user
5  *   channel name associations on the party line
6  *   rejecting a bot
7  *   linking, unlinking, and relaying to another bot
8  *   pinging the bots periodically and checking leaf status
9  */
10 /*
11  * Copyright (C) 1997 Robey Pointer
12  * Copyright (C) 1999 - 2021 Eggheads Development Team
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28 
29 #include "main.h"
30 #include "tandem.h"
31 
32 extern int dcc_total, backgrd, connect_timeout, max_dcc, egg_numver;
33 extern struct userrec *userlist;
34 extern struct dcc_t *dcc;
35 extern time_t now;
36 extern Tcl_Interp *interp;
37 
38 tand_t *tandbot;                   /* Keep track of tandem bots on the botnet */
39 party_t *party;                    /* Keep track of people on the botnet */
40 static int party_size = 0;
41 int tands = 0;                     /* Number of bots on the botnet */
42 int parties = 0;                   /* Number of people on the botnet */
43 char botnetnick[HANDLEN + 1] = ""; /* Botnet nickname */
44 int share_unlinks = 0;             /* Allow remote unlinks of my sharebots? */
45 #ifdef TLS
46 int tls_vfybots = 0;               /* Verify SSL certificates from bots? */
47 #endif
48 
expmem_botnet()49 int expmem_botnet()
50 {
51   int size = 0, i;
52 
53   size = tands * sizeof(tand_t);
54   size += party_size * sizeof(party_t);
55   for (i = 0; i < parties; i++) {
56     if (party[i].away)
57       size += strlen(party[i].away) + 1;
58     if (party[i].from)
59       size += strlen(party[i].from) + 1;
60   }
61   return size;
62 }
63 
init_bots()64 void init_bots()
65 {
66   tandbot = NULL;
67 }
68 
findbot(char * who)69 tand_t *findbot(char *who)
70 {
71   tand_t *ptr;
72 
73   for (ptr = tandbot; ptr; ptr = ptr->next)
74     if (!strcasecmp(ptr->bot, who))
75       return ptr;
76   return NULL;
77 }
78 
79 /* Add a tandem bot to our chain list
80  */
addbot(char * who,char * from,char * next,char flag,int vernum)81 void addbot(char *who, char *from, char *next, char flag, int vernum)
82 {
83   tand_t **ptr = &tandbot, *ptr2;
84 
85   while (*ptr) {
86     if (!strcasecmp((*ptr)->bot, who))
87       putlog(LOG_BOTS, "*", "!!! Duplicate botnet bot entry!!");
88     ptr = &((*ptr)->next);
89   }
90   ptr2 = nmalloc(sizeof(tand_t));
91   strncpy(ptr2->bot, who, HANDLEN);
92   ptr2->bot[HANDLEN] = 0;
93   ptr2->share = flag;
94   ptr2->ver = vernum;
95   ptr2->next = *ptr;
96   *ptr = ptr2;
97   /* May be via itself */
98   ptr2->via = findbot(from);
99   if (!strcasecmp(next, botnetnick))
100     ptr2->uplink = (tand_t *) 1;
101   else
102     ptr2->uplink = findbot(next);
103   tands++;
104 }
105 
updatebot(int idx,char * who,char share,int vernum)106 void updatebot(int idx, char *who, char share, int vernum)
107 {
108   tand_t *ptr = findbot(who);
109 
110   if (ptr) {
111     if (share)
112       ptr->share = share;
113     if (vernum)
114       ptr->ver = vernum;
115     botnet_send_update(idx, ptr);
116   }
117 }
118 
119 /* For backward 1.0 compatibility:
120  * grab the (first) sock# for a user on another bot
121  */
partysock(char * bot,char * nick)122 int partysock(char *bot, char *nick)
123 {
124   int i;
125 
126   for (i = 0; i < parties; i++) {
127     if ((!strcasecmp(party[i].bot, bot)) &&
128         (!strcasecmp(party[i].nick, nick)))
129       return party[i].sock;
130   }
131   return 0;
132 }
133 
134 /* Set the botnetnick and truncate as necessary */
set_botnetnick(const char * newnick)135 void set_botnetnick(const char *newnick) {
136   strlcpy(botnetnick, newnick, sizeof botnetnick);
137 }
138 
139 /* New botnet member
140  */
addparty(char * bot,char * nick,int chan,char flag,int sock,char * from,int * idx)141 int addparty(char *bot, char *nick, int chan, char flag, int sock,
142              char *from, int *idx)
143 {
144   int i;
145 
146   for (i = 0; i < parties; i++) {
147     /* Just changing the channel of someone already on? */
148     if (!strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
149       int oldchan = party[i].chan;
150 
151       party[i].chan = chan;
152       party[i].timer = now;
153       if (from[0]) {
154         if (flag == ' ')
155           flag = '-';
156         party[i].flag = flag;
157         if (party[i].from)
158           nfree(party[i].from);
159         party[i].from = nmalloc(strlen(from) + 1);
160         strcpy(party[i].from, from);
161       }
162       *idx = i;
163       return oldchan;
164     }
165   }
166   /* New member */
167   if (!party_size) {
168       party_size = 1;
169       party = nmalloc(party_size * sizeof(party_t));
170   }
171   else if (parties == party_size) {
172     party_size <<= 1;
173     party = nrealloc(party, party_size * sizeof(party_t));
174     debug1("botnet: party size doubled to %i.", party_size);
175   }
176   strncpy(party[parties].nick, nick, HANDLEN);
177   party[parties].nick[HANDLEN] = 0;
178   strncpy(party[parties].bot, bot, HANDLEN);
179   party[parties].bot[HANDLEN] = 0;
180   party[parties].chan = chan;
181   party[parties].sock = sock;
182   party[parties].status = 0;
183   party[parties].away = 0;
184   party[parties].timer = now;   /* cope. */
185   if (from[0]) {
186     if (flag == ' ')
187       flag = '-';
188     party[parties].flag = flag;
189     party[parties].from = nmalloc(strlen(from) + 1);
190     strcpy(party[parties].from, from);
191   } else {
192     party[parties].flag = ' ';
193     party[parties].from = nmalloc(10);
194     strcpy(party[parties].from, "(unknown)");
195   }
196   *idx = parties;
197   parties++;
198   return -1;
199 }
200 
201 /* Alter status flags for remote party-line user.
202  */
partystat(char * bot,int sock,int add,int rem)203 void partystat(char *bot, int sock, int add, int rem)
204 {
205   int i;
206 
207   for (i = 0; i < parties; i++) {
208     if ((!strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
209       party[i].status |= add;
210       party[i].status &= ~rem;
211     }
212   }
213 }
214 
215 /* Other bot is sharing idle info.
216  */
partysetidle(char * bot,int sock,int secs)217 void partysetidle(char *bot, int sock, int secs)
218 {
219   int i;
220 
221   for (i = 0; i < parties; i++) {
222     if ((!strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
223       party[i].timer = (now - (time_t) secs);
224     }
225   }
226 }
227 
228 /* Return someone's chat channel.
229  */
getparty(char * bot,int sock)230 int getparty(char *bot, int sock)
231 {
232   int i;
233 
234   for (i = 0; i < parties; i++) {
235     if (!strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
236       return i;
237     }
238   }
239   return -1;
240 }
241 
242 /* Un-idle someone
243  */
partyidle(char * bot,char * nick)244 int partyidle(char *bot, char *nick)
245 {
246   int i, ok = 0;
247 
248   for (i = 0; i < parties; i++) {
249     if ((!strcasecmp(party[i].bot, bot)) &&
250         (!strcasecmp(party[i].nick, nick))) {
251       party[i].timer = now;
252       ok = 1;
253     }
254   }
255   return ok;
256 }
257 
258 /* Change someone's nick
259  */
partynick(char * bot,int sock,char * nick)260 int partynick(char *bot, int sock, char *nick)
261 {
262   char work[HANDLEN + 1];
263   int i;
264 
265   for (i = 0; i < parties; i++) {
266     if (!strcasecmp(party[i].bot, bot) && (party[i].sock == sock)) {
267       strcpy(work, party[i].nick);
268       strncpy(party[i].nick, nick, HANDLEN);
269       party[i].nick[HANDLEN] = 0;
270       strcpy(nick, work);
271       return i;
272     }
273   }
274   return -1;
275 }
276 
277 /* Set away message
278  */
partyaway(char * bot,int sock,char * msg)279 void partyaway(char *bot, int sock, char *msg)
280 {
281   int i;
282 
283   for (i = 0; i < parties; i++) {
284     if ((!strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
285       if (party[i].away)
286         nfree(party[i].away);
287       if (msg[0]) {
288         party[i].away = nmalloc(strlen(msg) + 1);
289         strcpy(party[i].away, msg);
290       } else
291         party[i].away = 0;
292     }
293   }
294 }
295 
296 /* Remove a tandem bot from the chain list. */
rembot(char * whoin)297 void rembot(char *whoin)
298 {
299   tand_t **ptr = &tandbot, *ptr2;
300   struct userrec *u;
301   char *who = NULL;
302   size_t len = 0;
303 
304   /* Need to save the nick for later as it MAY be a pointer to ptr->bot, and we free(ptr) in here. */
305   len = strlen(whoin);
306   who = nmalloc(len + 1);
307   strlcpy(who, whoin, len + 1);
308 
309   while (*ptr) {
310     if (!strcasecmp((*ptr)->bot, who))
311       break;
312     ptr = &((*ptr)->next);
313   }
314   if (!*ptr) {
315     /* May have just .unlink *'d. */
316     nfree(who);
317     return;
318   }
319   check_tcl_disc(who);
320 
321   u = get_user_by_handle(userlist, who);
322   if (u != NULL)
323     touch_laston(u, "unlinked", now);
324 
325   ptr2 = *ptr;
326   *ptr = ptr2->next;
327   nfree(ptr2);
328   tands--;
329 
330   dupwait_notify(who);
331   nfree(who);
332 }
333 
remparty(char * bot,int sock)334 void remparty(char *bot, int sock)
335 {
336   int i;
337 
338   for (i = 0; i < parties; i++)
339     if ((!strcasecmp(party[i].bot, bot)) && (party[i].sock == sock)) {
340       parties--;
341       if (party[i].from)
342         nfree(party[i].from);
343       if (party[i].away)
344         nfree(party[i].away);
345       if (i < parties) {
346         strcpy(party[i].bot, party[parties].bot);
347         strcpy(party[i].nick, party[parties].nick);
348         party[i].chan = party[parties].chan;
349         party[i].sock = party[parties].sock;
350         party[i].flag = party[parties].flag;
351         party[i].status = party[parties].status;
352         party[i].timer = party[parties].timer;
353         party[i].from = party[parties].from;
354         party[i].away = party[parties].away;
355       }
356     }
357 }
358 
359 /* Cancel every user that was on a certain bot
360  */
rempartybot(char * bot)361 void rempartybot(char *bot)
362 {
363   int i;
364 
365   for (i = 0; i < parties; i++)
366     if (!strcasecmp(party[i].bot, bot)) {
367       if (party[i].chan >= 0)
368         check_tcl_chpt(bot, party[i].nick, party[i].sock, party[i].chan);
369       remparty(bot, party[i].sock);
370       i--;
371     }
372 }
373 
374 /* Remove every bot linked 'via' bot <x>
375  */
unvia(int idx,tand_t * who)376 void unvia(int idx, tand_t *who)
377 {
378   tand_t *bot, *bot2;
379 
380   if (!who)
381     return;                     /* Safety */
382   rempartybot(who->bot);
383   bot = tandbot;
384   while (bot) {
385     if (bot->uplink == who) {
386       unvia(idx, bot);
387       bot2 = bot->next;
388       rembot(bot->bot);
389       bot = bot2;
390     } else
391       bot = bot->next;
392   }
393 #ifndef NO_OLD_BOTNET
394   /* Every bot unvia's bots behind anyway, so why send msg's for
395    * EVERY one? - will this break things?!
396    */
397   tandout_but(idx, "unlinked %s\n", who->bot);
398 #endif
399 }
400 
401 /* Return index into dcc list of the bot that connects us to bot <x>
402  */
nextbot(char * who)403 int nextbot(char *who)
404 {
405   int j;
406   tand_t *bot = findbot(who);
407 
408   if (!bot)
409     return -1;
410 
411   for (j = 0; j < dcc_total; j++)
412     if (bot->via && !strcasecmp(bot->via->bot, dcc[j].nick) &&
413         (dcc[j].type == &DCC_BOT))
414       return j;
415   return -1;                    /* We're not connected to 'via' */
416 }
417 
418 /* Return name of the bot that is directly connected to bot X
419  */
lastbot(char * who)420 char *lastbot(char *who)
421 {
422   tand_t *bot = findbot(who);
423 
424   if (!bot)
425     return "*";
426   else if (bot->uplink == (tand_t *) 1)
427     return botnetnick;
428   else
429     return bot->uplink->bot;
430 }
431 
432 /* Modern version of 'whom' (use local data)
433  */
answer_local_whom(int idx,int chan)434 void answer_local_whom(int idx, int chan)
435 {
436   char format[81];
437   char c, idle[64];
438   int i, t, nicklen, botnicklen, total = 0;
439 
440   if (chan == -1)
441     dprintf(idx, "%s (+: %s, *: %s)\n", BOT_BOTNETUSERS, BOT_PARTYLINE,
442             BOT_LOCALCHAN);
443   else if (chan > 0) {
444     simple_sprintf(idle, "assoc %d", chan);
445     if ((Tcl_Eval(interp, idle) != TCL_OK) || tcl_resultempty())
446       dprintf(idx, "%s %s%d:\n", BOT_USERSONCHAN,
447               (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
448     else
449       dprintf(idx, "%s '%s%s' (%s%d):\n", BOT_USERSONCHAN,
450               (chan < GLOBAL_CHANS) ? "" : "*", tcl_resultstring(),
451               (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS);
452   }
453   /* Find longest nick and botnick */
454   nicklen = botnicklen = 0;
455   for (i = 0; i < dcc_total; i++)
456     if (dcc[i].type == &DCC_CHAT) {
457       if ((chan == -1) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
458         t = strlen(dcc[i].nick);
459         if (t > nicklen)
460           nicklen = t;
461         t = strlen(botnetnick);
462         if (t > botnicklen)
463           botnicklen = t;
464       }
465     }
466   for (i = 0; i < parties; i++) {
467     if ((chan == -1) || ((chan >= 0) && (party[i].chan == chan))) {
468       t = strlen(party[i].nick);
469       if (t > nicklen)
470         nicklen = t;
471       t = strlen(party[i].bot);
472       if (t > botnicklen)
473         botnicklen = t;
474     }
475   }
476   if (nicklen < 9)
477     nicklen = 9;
478   if (botnicklen < 9)
479     botnicklen = 9;
480 
481   egg_snprintf(format, sizeof format, "%%-%us   %%-%us  %%s\n",
482                nicklen, botnicklen);
483   dprintf(idx, format, " Nick", " Bot", " Host");
484   dprintf(idx, format, "----------", "---------", "--------------------");
485   egg_snprintf(format, sizeof format, "%%c%%-%us %%c %%-%us  %%s%%s\n",
486                nicklen, botnicklen);
487   for (i = 0; i < dcc_total; i++)
488     if (dcc[i].type == &DCC_CHAT) {
489       if ((chan == -1) || ((chan >= 0) && (dcc[i].u.chat->channel == chan))) {
490         c = geticon(i);
491         if (c == '-')
492           c = ' ';
493         if (now - dcc[i].timeval > 300) {
494           unsigned long days, hrs, mins;
495 
496           days = (now - dcc[i].timeval) / 86400;
497           hrs = ((now - dcc[i].timeval) - (days * 86400)) / 3600;
498           mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60;
499           if (days > 0)
500             sprintf(idle, " [idle %lud%luh]", days, hrs);
501           else if (hrs > 0)
502             sprintf(idle, " [idle %luh%lum]", hrs, mins);
503           else
504             sprintf(idle, " [idle %lum]", mins);
505         } else
506           idle[0] = 0;
507         total++;
508         dprintf(idx, format, c, dcc[i].nick,
509                 (dcc[i].u.chat->channel == 0) && (chan == -1) ? '+' :
510                 (dcc[i].u.chat->channel >= GLOBAL_CHANS) &&
511                 (chan == -1) ? '*' : ' ', botnetnick, dcc[i].host, idle);
512         if (dcc[i].u.chat->away != NULL)
513           dprintf(idx, "   AWAY: %s\n", dcc[i].u.chat->away);
514       }
515     }
516   for (i = 0; i < parties; i++) {
517     if ((chan == -1) || ((chan >= 0) && (party[i].chan == chan))) {
518       c = party[i].flag;
519       if (c == '-')
520         c = ' ';
521       if (party[i].timer == 0L)
522         strcpy(idle, " [idle?]");
523       else if (now - party[i].timer > 300) {
524         unsigned long days, hrs, mins;
525 
526         days = (now - party[i].timer) / 86400;
527         hrs = ((now - party[i].timer) - (days * 86400)) / 3600;
528         mins = ((now - party[i].timer) - (hrs * 3600)) / 60;
529         if (days > 0)
530           sprintf(idle, " [idle %lud%luh]", days, hrs);
531         else if (hrs > 0)
532           sprintf(idle, " [idle %luh%lum]", hrs, mins);
533         else
534           sprintf(idle, " [idle %lum]", mins);
535       } else
536         idle[0] = 0;
537       total++;
538       dprintf(idx, format, c, party[i].nick,
539               (party[i].chan == 0) && (chan == -1) ? '+' : ' ',
540               party[i].bot, party[i].from, idle);
541       if (party[i].status & PLSTAT_AWAY)
542         dprintf(idx, "   %s: %s\n", MISC_AWAY,
543                 party[i].away ? party[i].away : "");
544     }
545   }
546   dprintf(idx, "Total users: %d\n", total);
547 }
548 
549 /* Show z a list of all bots connected
550  */
tell_bots(int idx)551 void tell_bots(int idx)
552 {
553   char s[512];
554   int i;
555   tand_t *bot;
556 
557   if (!tands) {
558     dprintf(idx, "%s\n", BOT_NOBOTSLINKED);
559     return;
560   }
561   strcpy(s, botnetnick);
562   i = strlen(botnetnick);
563 
564   for (bot = tandbot; bot; bot = bot->next) {
565     if (i > (500 - HANDLEN)) {
566       dprintf(idx, "Bots: %s\n", s);
567       s[0] = 0;
568       i = 0;
569     }
570     if (i) {
571       s[i++] = ',';
572       s[i++] = ' ';
573     }
574     strcpy(s + i, bot->bot);
575     i += strlen(bot->bot);
576   }
577   if (s[0])
578     dprintf(idx, "Bots: %s\n", s);
579   dprintf(idx, "%s: %d\n", MISC_TOTAL, tands + 1);
580 }
581 
582 /* Show a simpleton bot tree
583  */
tell_bottree(int idx,int showver)584 void tell_bottree(int idx, int showver)
585 {
586   char s[161];
587   tand_t *last[20], *this, *bot, *bot2 = NULL;
588   int lev = 0, more = 1, mark[20], ok, cnt, i, imark;
589   char work[1024];
590   int tothops = 0;
591 
592   if (tands == 0) {
593     dprintf(idx, "%s\n", BOT_NOBOTSLINKED);
594     return;
595   }
596   s[0] = 0;
597   i = 0;
598 
599   for (bot = tandbot; bot; bot = bot->next)
600     if (!bot->uplink) {
601       if (i) {
602         s[i++] = ',';
603         s[i++] = ' ';
604       }
605       strcpy(s + i, bot->bot);
606       i += strlen(bot->bot);
607     }
608   if (s[0])
609     dprintf(idx, "(%s %s)\n", BOT_NOTRACEINFO, s);
610   if (showver)
611     dprintf(idx, "%s (%d.%d.%d.%d)\n", botnetnick,
612             egg_numver / 1000000,
613             egg_numver % 1000000 / 10000,
614             egg_numver % 10000 / 100, egg_numver % 100);
615   else
616     dprintf(idx, "%s\n", botnetnick);
617   this = (tand_t *) 1;
618   work[0] = 0;
619   while (more) {
620     if (lev == 20) {
621       dprintf(idx, "\n%s\n", BOT_COMPLEXTREE);
622       return;
623     }
624     cnt = 0;
625     tothops += lev;
626     for (bot = tandbot; bot; bot = bot->next)
627       if (bot->uplink == this)
628         cnt++;
629     if (cnt) {
630       imark = 0;
631       for (i = 0; i < lev; i++) {
632         if (mark[i])
633           strcpy(work + imark, "  |  ");
634         else
635           strcpy(work + imark, "     ");
636         imark += 5;
637       }
638       if (cnt > 1)
639         strcpy(work + imark, "  |-");
640       else
641         strcpy(work + imark, "  `-");
642       s[0] = 0;
643       bot = tandbot;
644       while (!s[0]) {
645         if (bot->uplink == this) {
646           if (bot->ver) {
647             i = sprintf(s, "%c%s", bot->share, bot->bot);
648             if (showver)
649               sprintf(s + i, " (%d.%d.%d.%d)",
650                       bot->ver / 1000000,
651                       bot->ver % 1000000 / 10000,
652                       bot->ver % 10000 / 100, bot->ver % 100);
653           } else
654             sprintf(s, "-%s", bot->bot);
655         } else
656           bot = bot->next;
657       }
658       dprintf(idx, "%s%s\n", work, s);
659       if (cnt > 1)
660         mark[lev] = 1;
661       else
662         mark[lev] = 0;
663       work[0] = 0;
664       last[lev] = this;
665       this = bot;
666       lev++;
667       more = 1;
668     } else {
669       while (cnt == 0) {
670         /* No subtrees from here */
671         if (lev == 0) {
672           dprintf(idx, "(( tree error ))\n");
673           return;
674         }
675         ok = 0;
676         for (bot = tandbot; bot; bot = bot->next) {
677           if (bot->uplink == last[lev - 1]) {
678             if (this == bot)
679               ok = 1;
680             else if (ok) {
681               cnt++;
682               if (cnt == 1) {
683                 bot2 = bot;
684                 if (bot->ver) {
685                   i = sprintf(s, "%c%s", bot->share, bot->bot);
686                   if (showver)
687                     sprintf(s + i, " (%d.%d.%d.%d)",
688                             bot->ver / 1000000,
689                             bot->ver % 1000000 / 10000,
690                             bot->ver % 10000 / 100, bot->ver % 100);
691                 } else
692                   sprintf(s, "-%s", bot->bot);
693               }
694             }
695           }
696         }
697         if (cnt) {
698           imark = 0;
699           for (i = 1; i < lev; i++) {
700             if (mark[i - 1])
701               strcpy(work + imark, "  |  ");
702             else
703               strcpy(work + imark, "     ");
704             imark += 5;
705           }
706           more = 1;
707           if (cnt > 1)
708             dprintf(idx, "%s  |-%s\n", work, s);
709           else
710             dprintf(idx, "%s  `-%s\n", work, s);
711           this = bot2;
712           work[0] = 0;
713           if (cnt > 1)
714             mark[lev - 1] = 1;
715           else
716             mark[lev - 1] = 0;
717         } else {
718           /* This was the last child */
719           lev--;
720           if (lev == 0) {
721             more = 0;
722             cnt = 999;
723           } else {
724             more = 1;
725             this = last[lev];
726           }
727         }
728       }
729     }
730   }
731   /* Hop information: (9d) */
732   dprintf(idx, "Average hops: %3.1f, total bots: %d\n",
733           ((float) tothops) / ((float) tands), tands + 1);
734 }
735 
736 /* Dump list of links to a new bot
737  */
dump_links(int z)738 void dump_links(int z)
739 {
740   int i, l;
741   char x[1024];
742   tand_t *bot;
743 
744   for (bot = tandbot; bot; bot = bot->next) {
745     char *p;
746 
747     if (bot->uplink == (tand_t *) 1)
748       p = botnetnick;
749     else
750       p = bot->uplink->bot;
751 #ifndef NO_OLD_BOTNET
752     if (b_numver(z) < NEAT_BOTNET)
753       l = simple_sprintf(x, "nlinked %s %s %c%d\n", bot->bot,
754                          p, bot->share, bot->ver);
755     else
756 #endif
757       l = simple_sprintf(x, "n %s %s %c%D\n", bot->bot, p,
758                          bot->share, bot->ver);
759     dprint(z, x, l);
760   }
761   if (!(bot_flags(dcc[z].user) & BOT_ISOLATE)) {
762     /* Dump party line members */
763     for (i = 0; i < dcc_total; i++) {
764       if (dcc[i].type == &DCC_CHAT) {
765         if ((dcc[i].u.chat->channel >= 0) &&
766             (dcc[i].u.chat->channel < GLOBAL_CHANS)) {
767 #ifndef NO_OLD_BOTNET
768           if (b_numver(z) < NEAT_BOTNET)
769             l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
770                                botnetnick, dcc[i].nick,
771                                dcc[i].u.chat->channel, geticon(i),
772                                dcc[i].sock, dcc[i].host);
773           else
774 #endif
775             l = simple_sprintf(x, "j !%s %s %D %c%D %s\n",
776                                botnetnick, dcc[i].nick,
777                                dcc[i].u.chat->channel, geticon(i),
778                                dcc[i].sock, dcc[i].host);
779           dprint(z, x, l);
780 #ifndef NO_OLD_BOTNET
781           if (b_numver(z) < NEAT_BOTNET) {
782             if (dcc[i].u.chat->away) {
783               l = simple_sprintf(x, "away %s %d %s\n", botnetnick,
784                                  dcc[i].sock, dcc[i].u.chat->away);
785               dprint(z, x, l);
786             }
787             l = simple_sprintf(x, "idle %s %d %d\n", botnetnick,
788                                dcc[i].sock, now - dcc[i].timeval);
789           } else
790 #endif
791             l = simple_sprintf(x, "i %s %D %D %s\n", botnetnick,
792                                dcc[i].sock, now - dcc[i].timeval,
793                                dcc[i].u.chat->away ? dcc[i].u.chat->away : "");
794           dprint(z, x, l);
795         }
796       }
797     }
798     for (i = 0; i < parties; i++) {
799 #ifndef NO_OLD_BOTNET
800       if (b_numver(z) < NEAT_BOTNET)
801         l = simple_sprintf(x, "join %s %s %d %c%d %s\n",
802                            party[i].bot, party[i].nick,
803                            party[i].chan, party[i].flag,
804                            party[i].sock, party[i].from);
805       else
806 #endif
807         l = simple_sprintf(x, "j %s %s %D %c%D %s\n",
808                            party[i].bot, party[i].nick,
809                            party[i].chan, party[i].flag,
810                            party[i].sock, party[i].from);
811       dprint(z, x, l);
812       if ((party[i].status & PLSTAT_AWAY) || (party[i].timer != 0)) {
813 #ifndef NO_OLD_BOTNET
814         if (b_numver(z) < NEAT_BOTNET) {
815           if (party[i].status & PLSTAT_AWAY) {
816             l = simple_sprintf(x, "away %s %d %s\n", party[i].bot,
817                                party[i].sock, party[i].away);
818             dprint(z, x, l);
819           }
820           l = simple_sprintf(x, "idle %s %d %d\n", party[i].bot,
821                              party[i].sock, now - party[i].timer);
822         } else
823 #endif
824           l = simple_sprintf(x, "i %s %D %D %s\n", party[i].bot,
825                              party[i].sock, now - party[i].timer,
826                              party[i].away ? party[i].away : "");
827         dprint(z, x, l);
828       }
829     }
830   }
831 }
832 
in_chain(char * who)833 int in_chain(char *who)
834 {
835   if (findbot(who))
836     return 1;
837   if (!strcasecmp(who, botnetnick))
838     return 1;
839   return 0;
840 }
841 
bots_in_subtree(tand_t * bot)842 int bots_in_subtree(tand_t *bot)
843 {
844   int nr = 1;
845   tand_t *b;
846 
847   if (!bot)
848     return 0;
849   for (b = tandbot; b; b = b->next) {
850     if (b->bot[0] && (b->uplink == bot)) {
851       nr += bots_in_subtree(b);
852     }
853   }
854   return nr;
855 }
856 
users_in_subtree(tand_t * bot)857 int users_in_subtree(tand_t *bot)
858 {
859   int i, nr;
860   tand_t *b;
861 
862   nr = 0;
863   if (!bot)
864     return 0;
865   for (i = 0; i < parties; i++)
866     if (!strcasecmp(party[i].bot, bot->bot))
867       nr++;
868   for (b = tandbot; b; b = b->next)
869     if (b->bot[0] && (b->uplink == bot))
870       nr += users_in_subtree(b);
871   return nr;
872 }
873 
874 /* Break link with a tandembot
875  */
botunlink(int idx,char * nick,char * reason,char * from)876 int botunlink(int idx, char *nick, char *reason, char *from)
877 {
878   char s[20];
879   int i;
880   int bots, users;
881   tand_t *bot;
882 
883   if (nick[0] == '*')
884     dprintf(idx, "%s\n", BOT_UNLINKALL);
885   for (i = 0; i < dcc_total; i++) {
886     if ((nick[0] == '*') || !strcasecmp(dcc[i].nick, nick)) {
887       if (dcc[i].type == &DCC_FORK_BOT) {
888         if (idx >= 0)
889           dprintf(idx, "%s: %s -> %s.\n", BOT_KILLLINKATTEMPT,
890                   dcc[i].nick, dcc[i].host);
891         putlog(LOG_BOTS, "*", "%s: %s -> %s:%d",
892                BOT_KILLLINKATTEMPT, dcc[i].nick, dcc[i].host, dcc[i].port);
893         killsock(dcc[i].sock);
894         lostdcc(i);
895         if (nick[0] != '*')
896           return 1;
897       } else if (dcc[i].type == &DCC_BOT_NEW) {
898         if (idx >= 0)
899           dprintf(idx, "%s %s.\n", BOT_ENDLINKATTEMPT, dcc[i].nick);
900         putlog(LOG_BOTS, "*", "%s %s @ %s:%d",
901                "Stopped trying to link", dcc[i].nick, dcc[i].host, dcc[i].port);
902         killsock(dcc[i].sock);
903         lostdcc(i);
904         if (nick[0] != '*')
905           return 1;
906       } else if (dcc[i].type == &DCC_BOT) {
907         char s[1024];
908 
909         if (idx >= 0)
910           dprintf(idx, "%s %s.\n", BOT_BREAKLINK, dcc[i].nick);
911         else if ((idx == -3) && (b_status(i) & STAT_SHARE) && !share_unlinks)
912           return -1;
913         bot = findbot(dcc[i].nick);
914         bots = bots_in_subtree(bot);
915         users = users_in_subtree(bot);
916         if (reason && reason[0]) {
917           simple_sprintf(s, "%s %s (%s (%s)) (lost %d bot%s and %d user%s)",
918                          BOT_UNLINKEDFROM, dcc[i].nick, reason, from, bots,
919                          (bots != 1) ? "s" : "", users, (users != 1) ?
920                          "s" : "");
921           dprintf(i, "bye %s\n", reason);
922         } else {
923           simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
924                          BOT_UNLINKEDFROM, dcc[i].nick, from, bots,
925                          (bots != 1) ? "s" : "", users,
926                          (users != 1) ? "s" : "");
927           dprintf(i, "bye No reason\n");
928         }
929         putlog(LOG_BOTS, "*", "%s.", s);
930         dprintf(idx, "%s.\n", s);
931         botnet_send_unlinked(i, dcc[i].nick, s);
932         killsock(dcc[i].sock);
933         lostdcc(i);
934         if (nick[0] != '*')
935           return 1;
936       }
937     }
938   }
939   if (idx >= 0 && nick[0] != '*')
940     dprintf(idx, "%s\n", BOT_NOTCONNECTED);
941   if (nick[0] != '*') {
942     bot = findbot(nick);
943     if (bot) {
944       /* The internal bot list is desynched from the dcc list
945        * sometimes. While we still search for the bug, provide
946        * an easy way to clear out those `ghost'-bots.
947        * Fabian (2000-08-02)  */
948       char *ghost = "BUG!!: Found bot `%s' in internal bot list, but it\n"
949                     "   shouldn't have been there! Removing.\n"
950                     "   This is a known bug we haven't fixed yet. If this\n"
951                     "   bot is the newest eggdrop version available and you\n"
952                     "   know a *reliable* way to reproduce the bug, please\n"
953                     "   contact us - we need your help!\n";
954       if (idx >= 0)
955         dprintf(idx, ghost, nick);
956       else
957         putlog(LOG_MISC, "*", ghost, nick);
958       rembot(bot->bot);
959       return 1;
960     }
961   }
962   if (nick[0] == '*') {
963     dprintf(idx, "%s\n", BOT_WIPEBOTTABLE);
964     while (tandbot)
965       rembot(tandbot->bot);
966     while (parties) {
967       parties--;
968       /* Assert? */
969       if (party[i].chan >= 0)
970         check_tcl_chpt(party[i].bot, party[i].nick, party[i].sock,
971                        party[i].chan);
972     }
973     strcpy(s, "killassoc &");
974     Tcl_Eval(interp, s);
975   }
976   return 0;
977 }
978 
979 static void botlink_resolve_success(int);
980 static void botlink_resolve_failure(int);
981 
982 /* Link to another bot
983  */
botlink(char * linker,int idx,char * nick)984 int botlink(char *linker, int idx, char *nick)
985 {
986   struct bot_addr *bi;
987   struct userrec *u;
988   int i;
989 
990   u = get_user_by_handle(userlist, nick);
991   if (!u || !(u->flags & USER_BOT)) {
992     if (idx >= 0)
993       dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
994   } else if (!strcasecmp(nick, botnetnick)) {
995     if (idx >= 0)
996       dprintf(idx, "%s\n", BOT_CANTLINKMYSELF);
997   } else if (in_chain(nick) && (idx != -3)) {
998     if (idx >= 0)
999       dprintf(idx, "%s\n", BOT_ALREADYLINKED);
1000   } else if (bot_flags(u) & BOT_REJECT) {
1001     if (idx >= 0) {
1002       dprintf(idx, "%s %s\n", BOT_REJECTING, nick);
1003     }
1004   } else {
1005     for (i = 0; i < dcc_total; i++)
1006       if ((dcc[i].user == u) &&
1007           ((dcc[i].type == &DCC_FORK_BOT) || (dcc[i].type == &DCC_BOT_NEW))) {
1008         if (idx >= 0)
1009           dprintf(idx, "%s\n", BOT_ALREADYLINKING);
1010         return 0;
1011       }
1012     /* Address to connect to is in 'info' */
1013     bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1014     if (!bi || !strlen(bi->address) || !bi->telnet_port ||
1015         (bi->telnet_port <= 0)) {
1016       if (idx >= 0) {
1017         dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
1018         dprintf(idx, "%s .chaddr %s %s\n",
1019                 MISC_USEFORMAT, nick, MISC_CHADDRFORMAT);
1020       }
1021     } else if (dcc_total == max_dcc && increase_socks_max()) {
1022       if (idx >= 0)
1023         dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
1024     } else {
1025       correct_handle(nick);
1026 
1027       if (idx > -2)
1028 #ifdef IPV6
1029       {
1030         if (strchr(bi->address, ':'))
1031           putlog(LOG_BOTS, "*", "%s %s at [%s]:%d ...", BOT_LINKING, nick,
1032                  bi->address, bi->telnet_port);
1033         else
1034           putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
1035                  bi->address, bi->telnet_port);
1036       }
1037 #else
1038         putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick,
1039                bi->address, bi->telnet_port);
1040 #endif
1041       i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1042       dcc[i].timeval = now;
1043       dcc[i].port = bi->telnet_port;
1044 #ifdef TLS
1045       dcc[i].ssl = (bi->ssl & TLS_BOT);
1046 #endif
1047       dcc[i].user = u;
1048       strcpy(dcc[i].nick, nick);
1049       strcpy(dcc[i].host, bi->address);
1050       dcc[i].u.dns->ibuf = idx;
1051       dcc[i].u.dns->cptr = get_data_ptr(strlen(linker) + 1);
1052       strcpy(dcc[i].u.dns->cptr, linker);
1053       dcc[i].u.dns->host = get_data_ptr(strlen(dcc[i].host) + 1);
1054       strcpy(dcc[i].u.dns->host, dcc[i].host);
1055       dcc[i].u.dns->dns_success = botlink_resolve_success;
1056       dcc[i].u.dns->dns_failure = botlink_resolve_failure;
1057       dcc[i].u.dns->dns_type = RES_IPBYHOST;
1058       dcc[i].u.dns->type = &DCC_FORK_BOT;
1059       dcc_dnsipbyhost(bi->address);
1060       return 1;
1061     }
1062   }
1063   return 0;
1064 }
1065 
botlink_resolve_failure(int i)1066 static void botlink_resolve_failure(int i)
1067 {
1068   char s[81];
1069 
1070   putlog(LOG_BOTS, "*", DCC_LINKFAIL, dcc[i].nick);
1071   strcpy(s, dcc[i].nick);
1072   nfree(dcc[i].u.dns->cptr);
1073   lostdcc(i);
1074   autolink_cycle(s);            /* Check for more auto-connections */
1075 }
1076 
botlink_resolve_success(int i)1077 static void botlink_resolve_success(int i)
1078 {
1079   int idx = dcc[i].u.dns->ibuf;
1080   char *linker = dcc[i].u.dns->cptr;
1081 
1082   changeover_dcc(i, &DCC_FORK_BOT, sizeof(struct bot_info));
1083   dcc[i].timeval = now;
1084   strlcpy(dcc[i].u.bot->linker, linker, sizeof dcc[i].u.bot->linker);
1085   strcpy(dcc[i].u.bot->version, "(primitive bot)");
1086   dcc[i].u.bot->numver = idx;
1087   dcc[i].u.bot->port = dcc[i].port;     /* Remember where i started */
1088 #ifdef TLS
1089   dcc[i].u.bot->ssl = dcc[i].ssl;       /* Remember where I started */
1090 #endif
1091   nfree(linker);
1092   setsnport(dcc[i].sockname, dcc[i].port);
1093   dcc[i].sock = getsock(dcc[i].sockname.family, SOCK_STRONGCONN);
1094   if (dcc[i].sock < 0 || open_telnet_raw(dcc[i].sock, &dcc[i].sockname) < 0) {
1095     failed_link(i);
1096   }
1097 #ifdef TLS
1098   else if (dcc[i].ssl && ssl_handshake(dcc[i].sock, TLS_CONNECT,
1099            tls_vfybots, LOG_BOTS, dcc[i].host, NULL)) {
1100     failed_link(i);
1101   }
1102 #endif
1103 }
1104 
failed_tandem_relay(int idx)1105 static void failed_tandem_relay(int idx)
1106 {
1107   int uidx = -1, i;
1108 
1109   for (i = 0; i < dcc_total; i++)
1110     if ((dcc[i].type == &DCC_PRE_RELAY) &&
1111         (dcc[i].u.relay->sock == dcc[idx].sock))
1112       uidx = i;
1113   if (uidx < 0) {
1114     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
1115            dcc[idx].sock, dcc[idx].u.relay->sock);
1116     killsock(dcc[idx].sock);
1117     lostdcc(idx);
1118     return;
1119   }
1120   if (dcc[idx].port >= dcc[idx].u.relay->port + 3) {
1121     struct chat_info *ci = dcc[uidx].u.relay->chat;
1122 
1123     dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
1124     dcc[uidx].status = dcc[uidx].u.relay->old_status;
1125     nfree(dcc[uidx].u.relay);
1126     dcc[uidx].u.chat = ci;
1127     dcc[uidx].type = &DCC_CHAT;
1128     killsock(dcc[idx].sock);
1129     lostdcc(idx);
1130     return;
1131   }
1132   killsock(dcc[idx].sock);
1133   if (!dcc[idx].sockname.addrlen)
1134     (void) setsockname(&dcc[idx].sockname, dcc[idx].host, dcc[idx].port, 0);
1135   dcc[idx].sock = getsock(dcc[idx].sockname.family, SOCK_STRONGCONN);
1136   dcc[uidx].u.relay->sock = dcc[idx].sock;
1137   dcc[idx].port++;
1138   dcc[idx].timeval = now;
1139   if (dcc[idx].sock < 0 ||
1140       open_telnet_raw(dcc[idx].sock, &dcc[idx].sockname) < 0)
1141     failed_tandem_relay(idx);
1142 #ifdef TLS
1143   else if (dcc[idx].ssl && ssl_handshake(dcc[idx].sock, TLS_CONNECT,
1144            tls_vfybots, LOG_BOTS, dcc[idx].host, NULL))
1145     failed_tandem_relay(idx);
1146 #endif
1147 }
1148 
1149 
1150 static void tandem_relay_resolve_failure(int);
1151 static void tandem_relay_resolve_success(int);
1152 
1153 /* Relay to another tandembot
1154  */
tandem_relay(int idx,char * nick,int i)1155 void tandem_relay(int idx, char *nick, int i)
1156 {
1157   struct userrec *u;
1158   struct bot_addr *bi;
1159   struct chat_info *ci;
1160 
1161   u = get_user_by_handle(userlist, nick);
1162   if (!u || !(u->flags & USER_BOT)) {
1163     dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN);
1164     return;
1165   }
1166   if (!strcasecmp(nick, botnetnick)) {
1167     dprintf(idx, "%s\n", BOT_CANTRELAYMYSELF);
1168     return;
1169   }
1170   /* Address to connect to is in 'info' */
1171   bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u);
1172   if (!bi || !strlen(bi->address) || !bi->relay_port || (bi->relay_port <= 0)) {
1173     dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick);
1174     dprintf(idx, "%s .chaddr %s %s\n", MISC_USEFORMAT, nick,
1175             MISC_CHADDRFORMAT);
1176     return;
1177   }
1178   i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
1179   if (i < 0) {
1180     dprintf(idx, "%s\n", DCC_TOOMANYDCCS1);
1181     return;
1182   }
1183 
1184   dcc[i].sock = getsock(AF_INET, SOCK_STRONGCONN | SOCK_VIRTUAL);
1185   if (dcc[i].sock < 0) {
1186     lostdcc(i);
1187     dprintf(idx, "%s\n", MISC_NOFREESOCK);
1188     return;
1189   }
1190 
1191   dcc[i].port = bi->relay_port;
1192 #ifdef TLS
1193   dcc[i].ssl = (bi->ssl & TLS_RELAY);
1194 #endif
1195   dcc[i].addr = 0L;
1196   strcpy(dcc[i].nick, nick);
1197   dcc[i].user = u;
1198   strcpy(dcc[i].host, bi->address);
1199 #ifdef IPV6
1200   if (strchr(bi->address, ':'))
1201     dprintf(idx, "%s %s @ [%s]:%d ...\n", BOT_CONNECTINGTO, nick,
1202             bi->address, bi->relay_port);
1203   else
1204 #endif
1205   dprintf(idx, "%s %s @ %s:%d ...\n", BOT_CONNECTINGTO, nick,
1206           bi->address, bi->relay_port);
1207   dprintf(idx, "%s\n", BOT_BYEINFO1);
1208   dcc[idx].type = &DCC_PRE_RELAY;
1209   ci = dcc[idx].u.chat;
1210   dcc[idx].u.relay = get_data_ptr(sizeof(struct relay_info));
1211   dcc[idx].u.relay->chat = ci;
1212   dcc[idx].u.relay->old_status = dcc[idx].status;
1213   dcc[i].timeval = now;
1214   dcc[idx].u.relay->sock = dcc[i].sock;
1215   dcc[i].u.dns->ibuf = dcc[idx].sock;
1216   dcc[i].u.dns->host = get_data_ptr(strlen(bi->address) + 1);
1217   strcpy(dcc[i].u.dns->host, bi->address);
1218   dcc[i].u.dns->dns_success = tandem_relay_resolve_success;
1219   dcc[i].u.dns->dns_failure = tandem_relay_resolve_failure;
1220   dcc[i].u.dns->dns_type = RES_IPBYHOST;
1221   dcc[i].u.dns->type = &DCC_FORK_RELAY;
1222   dcc_dnsipbyhost(bi->address);
1223 }
1224 
tandem_relay_resolve_failure(int idx)1225 static void tandem_relay_resolve_failure(int idx)
1226 {
1227   struct chat_info *ci;
1228   int uidx = -1, i;
1229 
1230   for (i = 0; i < dcc_total; i++)
1231     if ((dcc[i].type == &DCC_PRE_RELAY) &&
1232         (dcc[i].u.relay->sock == dcc[idx].sock)) {
1233       uidx = i;
1234       break;
1235     }
1236   if (uidx < 0) {
1237     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
1238            dcc[idx].sock, dcc[idx].u.relay->sock);
1239     killsock(dcc[idx].sock);
1240     lostdcc(idx);
1241     return;
1242   }
1243   ci = dcc[uidx].u.relay->chat;
1244   dprintf(uidx, "%s %s.\n", BOT_CANTLINKTO, dcc[idx].nick);
1245   dcc[uidx].status = dcc[uidx].u.relay->old_status;
1246   nfree(dcc[uidx].u.relay);
1247   dcc[uidx].u.chat = ci;
1248   dcc[uidx].type = &DCC_CHAT;
1249   killsock(dcc[idx].sock);
1250   lostdcc(idx);
1251 }
1252 
tandem_relay_resolve_success(int i)1253 static void tandem_relay_resolve_success(int i)
1254 {
1255   int sock = dcc[i].u.dns->ibuf;
1256 
1257   changeover_dcc(i, &DCC_FORK_RELAY, sizeof(struct relay_info));
1258   dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info));
1259 
1260   dcc[i].u.relay->sock = sock;
1261   dcc[i].u.relay->port = dcc[i].port;
1262   dcc[i].u.relay->chat->away = NULL;
1263   dcc[i].u.relay->chat->msgs_per_sec = 0;
1264   dcc[i].u.relay->chat->con_flags = 0;
1265   dcc[i].u.relay->chat->buffer = NULL;
1266   dcc[i].u.relay->chat->max_line = 0;
1267   dcc[i].u.relay->chat->line_count = 0;
1268   dcc[i].u.relay->chat->current_lines = 0;
1269   dcc[i].timeval = now;
1270 #ifdef IPV6
1271   if (dcc[i].sockname.family == AF_INET6) {
1272     killsock(dcc[i].sock);
1273     dcc[i].sock = getsock(AF_INET6, SOCK_STRONGCONN | SOCK_VIRTUAL);
1274     dcc[i].sockname.addr.s6.sin6_port = htons(dcc[i].port);
1275     dcc[i].u.relay->sock = dcc[i].sock;
1276   } else
1277 #endif
1278     dcc[i].sockname.addr.s4.sin_port = htons(dcc[i].port);
1279   if (open_telnet_raw(dcc[i].sock, &dcc[i].sockname) < 0)
1280     failed_tandem_relay(i);
1281 #ifdef TLS
1282   else if (dcc[i].ssl && ssl_handshake(dcc[i].sock, TLS_CONNECT,
1283            tls_vfybots, LOG_BOTS, dcc[i].host, NULL))
1284     failed_tandem_relay(i);
1285 #endif
1286 }
1287 
1288 /* Input from user before connect is ready
1289  */
pre_relay(int idx,char * buf,int i)1290 static void pre_relay(int idx, char *buf, int i)
1291 {
1292   int tidx = -1;
1293 
1294   for (i = 0; i < dcc_total; i++)
1295     if ((dcc[i].type == &DCC_FORK_RELAY) &&
1296         (dcc[i].u.relay->sock == dcc[idx].sock)) {
1297       tidx = i;
1298       break;
1299     }
1300   if (tidx < 0) {
1301     /* Now try to find it among the DNSWAIT sockets instead. */
1302     for (i = 0; i < dcc_total; i++)
1303       if ((dcc[i].type == &DCC_DNSWAIT) &&
1304           (dcc[i].sock == dcc[idx].u.relay->sock)) {
1305         tidx = i;
1306         break;
1307       }
1308   }
1309   if (tidx < 0) {
1310     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
1311            dcc[idx].sock, dcc[idx].u.relay->sock);
1312     killsock(dcc[idx].sock);
1313     lostdcc(idx);
1314     return;
1315   }
1316   if (!strcasecmp(buf, "*bye*")) {
1317     /* Disconnect */
1318     struct chat_info *ci = dcc[idx].u.relay->chat;
1319 
1320     dprintf(idx, "%s %s.\n", BOT_ABORTRELAY1, dcc[tidx].nick);
1321     dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
1322     putlog(LOG_MISC, "*", "%s %s -> %s", BOT_ABORTRELAY3, dcc[idx].nick,
1323            dcc[tidx].nick);
1324     dcc[idx].status = dcc[idx].u.relay->old_status;
1325     nfree(dcc[idx].u.relay);
1326     dcc[idx].u.chat = ci;
1327     dcc[idx].type = &DCC_CHAT;
1328     killsock(dcc[tidx].sock);
1329     lostdcc(tidx);
1330     return;
1331   }
1332 }
1333 
1334 /* User disconnected before her relay had finished connecting
1335  */
failed_pre_relay(int idx)1336 static void failed_pre_relay(int idx)
1337 {
1338   int tidx = -1, i;
1339 
1340   for (i = 0; i < dcc_total; i++)
1341     if ((dcc[i].type == &DCC_FORK_RELAY) &&
1342         (dcc[i].u.relay->sock == dcc[idx].sock)) {
1343       tidx = i;
1344       break;
1345     }
1346   if (tidx < 0) {
1347     /* Now try to find it among the DNSWAIT sockets instead. */
1348     for (i = 0; i < dcc_total; i++)
1349       if ((dcc[i].type == &DCC_DNSWAIT) &&
1350           (dcc[i].sock == dcc[idx].u.relay->sock)) {
1351         tidx = i;
1352         break;
1353       }
1354   }
1355   if (tidx < 0) {
1356     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
1357            dcc[idx].sock, dcc[idx].u.relay->sock);
1358     killsock(dcc[idx].sock);
1359     lostdcc(idx);
1360     return;
1361   }
1362   putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
1363          dcc[idx].host, dcc[idx].port);
1364   putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPINGRELAY, dcc[tidx].nick);
1365   if ((dcc[tidx].sock != STDOUT) || backgrd) {
1366     if (idx > tidx) {
1367       int t = tidx;
1368 
1369       tidx = idx;
1370       idx = t;
1371     }
1372     killsock(dcc[tidx].sock);
1373     lostdcc(tidx);
1374   } else
1375     fatal("Lost my terminal?!", 0);
1376   killsock(dcc[idx].sock);
1377   lostdcc(idx);
1378 }
1379 
cont_tandem_relay(int idx,char * buf,int i)1380 static void cont_tandem_relay(int idx, char *buf, int i)
1381 {
1382   int uidx = -1;
1383   struct relay_info *ri;
1384 
1385   for (i = 0; i < dcc_total; i++)
1386     if ((dcc[i].type == &DCC_PRE_RELAY) &&
1387         (dcc[i].u.relay->sock == dcc[idx].sock))
1388       uidx = i;
1389   if (uidx < 0) {
1390     putlog(LOG_MISC, "*", "%s  %d -> %d", BOT_CANTFINDRELAYUSER,
1391            dcc[i].sock, dcc[i].u.relay->sock);
1392     killsock(dcc[i].sock);
1393     lostdcc(i);
1394     return;
1395   }
1396   dcc[idx].type = &DCC_RELAY;
1397   dcc[idx].u.relay->sock = dcc[uidx].sock;
1398   dcc[uidx].u.relay->sock = dcc[idx].sock;
1399   dprintf(uidx, "%s %s ...\n", BOT_RELAYSUCCESS, dcc[idx].nick);
1400   dprintf(uidx, "%s\n\n", BOT_BYEINFO2);
1401   putlog(LOG_MISC, "*", "%s %s -> %s", BOT_RELAYLINK,
1402          dcc[uidx].nick, dcc[idx].nick);
1403   ri = dcc[uidx].u.relay;       /* YEAH */
1404   dcc[uidx].type = &DCC_CHAT;
1405   dcc[uidx].u.chat = ri->chat;
1406   if (dcc[uidx].u.chat->channel >= 0) {
1407     chanout_but(-1, dcc[uidx].u.chat->channel, "*** %s %s\n",
1408                 dcc[uidx].nick, BOT_PARTYLEFT);
1409     if (dcc[uidx].u.chat->channel < GLOBAL_CHANS)
1410       botnet_send_part_idx(uidx, NULL);
1411     check_tcl_chpt(botnetnick, dcc[uidx].nick, dcc[uidx].sock,
1412                    dcc[uidx].u.chat->channel);
1413   }
1414   check_tcl_chof(dcc[uidx].nick, dcc[uidx].sock);
1415   dcc[uidx].type = &DCC_RELAYING;
1416   dcc[uidx].u.relay = ri;
1417 }
1418 
eof_dcc_relay(int idx)1419 static void eof_dcc_relay(int idx)
1420 {
1421   int j;
1422   struct chat_info *ci;
1423 
1424   for (j = 0; j < dcc_total; j++)
1425     if (dcc[j].sock == dcc[idx].u.relay->sock)
1426       break;
1427   if (j == dcc_total) {
1428     killsock(dcc[idx].sock);
1429     lostdcc(idx);
1430     return;
1431   }
1432   dcc[j].status = dcc[j].u.relay->old_status;
1433   /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1434   if (dcc[j].status & STAT_TELNET)
1435     dprintf(j, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1436   putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_ENDRELAY1, dcc[j].nick,
1437          dcc[idx].nick);
1438   dprintf(j, "\n\n*** %s %s\n", BOT_ENDRELAY2, botnetnick);
1439   ci = dcc[j].u.relay->chat;
1440   nfree(dcc[j].u.relay);
1441   dcc[j].u.chat = ci;
1442   dcc[j].type = &DCC_CHAT;
1443   if (dcc[j].u.chat->channel >= 0) {
1444     chanout_but(-1, dcc[j].u.chat->channel, "*** %s %s.\n",
1445                 dcc[j].nick, BOT_PARTYREJOINED);
1446     if (dcc[j].u.chat->channel < GLOBAL_CHANS)
1447       botnet_send_join_idx(j, -1);
1448   }
1449   check_tcl_chon(dcc[j].nick, dcc[j].sock);
1450   check_tcl_chjn(botnetnick, dcc[j].nick, dcc[j].u.chat->channel,
1451                  geticon(j), dcc[j].sock, dcc[j].host);
1452   killsock(dcc[idx].sock);
1453   lostdcc(idx);
1454 }
1455 
eof_dcc_relaying(int idx)1456 static void eof_dcc_relaying(int idx)
1457 {
1458   int j, x = dcc[idx].u.relay->sock;
1459 
1460   putlog(LOG_MISC, "*", "%s [%s]%s/%d", BOT_LOSTDCCUSER, dcc[idx].nick,
1461          dcc[idx].host, dcc[idx].port);
1462   killsock(dcc[idx].sock);
1463   lostdcc(idx);
1464   for (j = 0; (dcc[j].sock != x) || (dcc[j].type == &DCC_FORK_RELAY); j++);
1465   putlog(LOG_MISC, "*", "(%s %s)", BOT_DROPPEDRELAY, dcc[j].nick);
1466   killsock(dcc[j].sock);
1467   lostdcc(j);                   /* Drop connection to the bot */
1468 }
1469 
dcc_relay(int idx,char * buf,int j)1470 static void dcc_relay(int idx, char *buf, int j)
1471 {
1472   unsigned char *src, *dst;
1473 
1474   for (j = 0; dcc[j].sock != dcc[idx].u.relay->sock ||
1475        dcc[j].type != &DCC_RELAYING; j++);
1476   /* If redirecting to a non-telnet user, swallow telnet IAC, escape sequences
1477    * and CR. */
1478   if (!(dcc[j].status & STAT_TELNET)) {
1479     src = (unsigned char *) buf;
1480     dst = (unsigned char *) buf;
1481     while (*src) {
1482       /* Search for IAC, escape sequences and CR. */
1483       if (*src == TLN_IAC) {
1484         src++;
1485         if ((*src >= TLN_WILL) && (*src <= TLN_DONT)) {
1486           src++;
1487           if (*src)
1488             src++;
1489         }
1490         else if (*src)
1491           src++;
1492       } else if (*src == ESC) {
1493         src++;
1494         if (*src == '[') { /* CSI */
1495           src++;
1496           /* Search for the end of the escape sequence. */
1497           while (*src && *src++ != 'm');
1498         }
1499       } else if (*src == '\r') /* CR */
1500         src++;
1501       else {
1502         if (src > dst)
1503           *dst = *src;
1504         src++;
1505         dst++;
1506       }
1507     }
1508     if (src > dst)
1509       *dst = 0;
1510     if (!buf[0])
1511       dprintf(-dcc[idx].u.relay->sock, " \n");
1512     else
1513       dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1514     return;
1515   }
1516   /* Telnet user */
1517   if (!buf[0])
1518     dprintf(-dcc[idx].u.relay->sock, " \r\n");
1519   else
1520     dprintf(-dcc[idx].u.relay->sock, "%s\r\n", buf);
1521 }
1522 
dcc_relaying(int idx,char * buf,int j)1523 static void dcc_relaying(int idx, char *buf, int j)
1524 {
1525   struct chat_info *ci;
1526 
1527   if (strcasecmp(buf, "*bye*")) {
1528     dprintf(-dcc[idx].u.relay->sock, "%s\n", buf);
1529     return;
1530   }
1531   for (j = 0; (dcc[j].sock != dcc[idx].u.relay->sock) ||
1532        (dcc[j].type != &DCC_RELAY); j++);
1533   dcc[idx].status = dcc[idx].u.relay->old_status;
1534   /* In case echo was off, turn it back on (send IAC WON'T ECHO): */
1535   if (dcc[idx].status & STAT_TELNET)
1536     dprintf(idx, TLN_IAC_C TLN_WONT_C TLN_ECHO_C "\n");
1537   dprintf(idx, "\n(%s %s.)\n", BOT_BREAKRELAY, dcc[j].nick);
1538   dprintf(idx, "%s %s.\n\n", BOT_ABORTRELAY2, botnetnick);
1539   putlog(LOG_MISC, "*", "%s: %s -> %s", BOT_RELAYBROKEN,
1540          dcc[idx].nick, dcc[j].nick);
1541   if (dcc[idx].u.relay->chat->channel >= 0) {
1542     chanout_but(-1, dcc[idx].u.relay->chat->channel,
1543                 "*** %s joined the party line.\n", dcc[idx].nick);
1544     if (dcc[idx].u.relay->chat->channel < GLOBAL_CHANS)
1545       botnet_send_join_idx(idx, -1);
1546   }
1547   ci = dcc[idx].u.relay->chat;
1548   nfree(dcc[idx].u.relay);
1549   dcc[idx].u.chat = ci;
1550   dcc[idx].type = &DCC_CHAT;
1551   check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
1552   if (dcc[idx].u.chat->channel >= 0)
1553     check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
1554                    geticon(idx), dcc[idx].sock, dcc[idx].host);
1555   killsock(dcc[j].sock);
1556   lostdcc(j);
1557 }
1558 
display_relay(int i,char * other)1559 static void display_relay(int i, char *other)
1560 {
1561   sprintf(other, "rela  -> sock %d", dcc[i].u.relay->sock);
1562 }
1563 
display_relaying(int i,char * other)1564 static void display_relaying(int i, char *other)
1565 {
1566   sprintf(other, ">rly  -> sock %d", dcc[i].u.relay->sock);
1567 }
1568 
display_tandem_relay(int i,char * other)1569 static void display_tandem_relay(int i, char *other)
1570 {
1571   strcpy(other, "other  rela");
1572 }
1573 
display_pre_relay(int i,char * other)1574 static void display_pre_relay(int i, char *other)
1575 {
1576   strcpy(other, "other  >rly");
1577 }
1578 
expmem_relay(void * x)1579 static int expmem_relay(void *x)
1580 {
1581   struct relay_info *p = (struct relay_info *) x;
1582   int tot = sizeof(struct relay_info);
1583 
1584   if (p->chat)
1585     tot += DCC_CHAT.expmem(p->chat);
1586   return tot;
1587 }
1588 
kill_relay(int idx,void * x)1589 static void kill_relay(int idx, void *x)
1590 {
1591   struct relay_info *p = (struct relay_info *) x;
1592 
1593   if (p->chat)
1594     DCC_CHAT.kill(idx, p->chat);
1595   nfree(p);
1596 }
1597 
1598 struct dcc_table DCC_RELAY = {
1599   "RELAY",
1600   0,                            /* Flags */
1601   eof_dcc_relay,
1602   dcc_relay,
1603   NULL,
1604   NULL,
1605   display_relay,
1606   expmem_relay,
1607   kill_relay,
1608   NULL
1609 };
1610 
out_relay(int idx,char * buf,void * x)1611 static void out_relay(int idx, char *buf, void *x)
1612 {
1613   struct relay_info *p = (struct relay_info *) x;
1614 
1615   if (p && p->chat)
1616     DCC_CHAT.output(idx, buf, p->chat);
1617   else
1618     tputs(dcc[idx].sock, buf, strlen(buf));
1619 }
1620 
1621 struct dcc_table DCC_RELAYING = {
1622   "RELAYING",
1623   0,                            /* Flags */
1624   eof_dcc_relaying,
1625   dcc_relaying,
1626   NULL,
1627   NULL,
1628   display_relaying,
1629   expmem_relay,
1630   kill_relay,
1631   out_relay
1632 };
1633 
1634 struct dcc_table DCC_FORK_RELAY = {
1635   "FORK_RELAY",
1636   0,                            /* Flags */
1637   failed_tandem_relay,
1638   cont_tandem_relay,
1639   &connect_timeout,
1640   failed_tandem_relay,
1641   display_tandem_relay,
1642   expmem_relay,
1643   kill_relay,
1644   NULL
1645 };
1646 
1647 struct dcc_table DCC_PRE_RELAY = {
1648   "PRE_RELAY",
1649   0,                            /* Flags */
1650   failed_pre_relay,
1651   pre_relay,
1652   NULL,
1653   NULL,
1654   display_pre_relay,
1655   expmem_relay,
1656   kill_relay,
1657   NULL
1658 };
1659 
1660 /* Once a minute, send 'ping' to each bot -- no exceptions
1661  */
check_botnet_pings()1662 void check_botnet_pings()
1663 {
1664   int i;
1665   int bots, users;
1666   tand_t *bot;
1667 
1668   for (i = 0; i < dcc_total; i++)
1669     if (dcc[i].type == &DCC_BOT)
1670       if (dcc[i].status & STAT_PINGED) {
1671         char s[1024];
1672 
1673         bot = findbot(dcc[i].nick);
1674         bots = bots_in_subtree(bot);
1675         users = users_in_subtree(bot);
1676         simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)",
1677                        BOT_PINGTIMEOUT, dcc[i].nick, bots,
1678                        (bots != 1) ? "s" : "", users, (users != 1) ? "s" : "");
1679         putlog(LOG_BOTS, "*", "%s.", s);
1680         botnet_send_unlinked(i, dcc[i].nick, s);
1681         killsock(dcc[i].sock);
1682         lostdcc(i);
1683       }
1684   for (i = 0; i < dcc_total; i++)
1685     if (dcc[i].type == &DCC_BOT) {
1686       botnet_send_ping(i);
1687       dcc[i].status |= STAT_PINGED;
1688     }
1689   for (i = 0; i < dcc_total; i++)
1690     if ((dcc[i].type == &DCC_BOT) && (dcc[i].status & STAT_LEAF)) {
1691       tand_t *bot, *via = findbot(dcc[i].nick);
1692 
1693       for (bot = tandbot; bot; bot = bot->next) {
1694         if ((via == bot->via) && (bot != via)) {
1695           /* Not leaflike behavior */
1696           if (dcc[i].status & STAT_WARNED) {
1697             char s[1024];
1698 
1699             dprintf(i, "bye %s\n", BOT_BOTNOTLEAFLIKE);
1700             bot = findbot(dcc[i].nick);
1701             bots = bots_in_subtree(bot);
1702             users = users_in_subtree(bot);
1703             simple_sprintf(s, "%s %s (%s) (lost %d bot%s and %d user%s)",
1704                            BOT_DISCONNECTED, dcc[i].nick, BOT_BOTNOTLEAFLIKE,
1705                            bots, (bots != 1) ? "s" : "", users, (users != 1) ?
1706                            "s" : "");
1707             putlog(LOG_BOTS, "*", "%s.", s);
1708             botnet_send_unlinked(i, dcc[i].nick, s);
1709             killsock(dcc[i].sock);
1710             lostdcc(i);
1711           } else {
1712             botnet_send_reject(i, botnetnick, NULL, bot->bot, NULL, NULL);
1713             dcc[i].status |= STAT_WARNED;
1714           }
1715         } else
1716           dcc[i].status &= ~STAT_WARNED;
1717       }
1718     }
1719 }
1720 
zapfbot(int idx)1721 void zapfbot(int idx)
1722 {
1723   char s[1024];
1724   int bots, users;
1725   tand_t *bot;
1726 
1727   bot = findbot(dcc[idx].nick);
1728   bots = bots_in_subtree(bot);
1729   users = users_in_subtree(bot);
1730   simple_sprintf(s, "%s: %s (lost %d bot%s and %d user%s)", BOT_BOTDROPPED,
1731                  dcc[idx].nick, bots, (bots != 1) ? "s" : "", users,
1732                  (users != 1) ? "s" : "");
1733   putlog(LOG_BOTS, "*", "%s.", s);
1734   botnet_send_unlinked(idx, dcc[idx].nick, s);
1735   killsock(dcc[idx].sock);
1736   lostdcc(idx);
1737 }
1738 
restart_chons()1739 void restart_chons()
1740 {
1741   int i;
1742 
1743   /* Dump party line members */
1744   for (i = 0; i < dcc_total; i++) {
1745     if (dcc[i].type == &DCC_CHAT) {
1746       check_tcl_chon(dcc[i].nick, dcc[i].sock);
1747       check_tcl_chjn(botnetnick, dcc[i].nick, dcc[i].u.chat->channel,
1748                      geticon(i), dcc[i].sock, dcc[i].host);
1749     }
1750   }
1751   for (i = 0; i < parties; i++) {
1752     check_tcl_chjn(party[i].bot, party[i].nick, party[i].chan,
1753                    party[i].flag, party[i].sock, party[i].from);
1754   }
1755 }
1756