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