/[cvs]/eggdrop1.4/src/dcc.c
ViewVC logotype

Contents of /eggdrop1.4/src/dcc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.20 - (show annotations) (download) (as text)
Wed Dec 15 02:32:58 1999 UTC (19 years, 9 months ago) by guppy
Branch: MAIN
Changes since 1.19: +23 -9 lines
File MIME type: text/x-chdr
id-header patch, finally, we have id tags for each file

1 /*
2 * dcc.c -- handles:
3 * activity on a dcc socket
4 * disconnect on a dcc socket
5 * ...and that's it! (but it's a LOT)
6 *
7 * dprintf'ized, 27oct1995
8 *
9 * $Id$
10 */
11 /*
12 * Copyright (C) 1997 Robey Pointer
13 * Copyright (C) 1999 Eggheads
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30 #include "main.h"
31 #include <ctype.h>
32 #include <errno.h>
33 #include "modules.h"
34 #include "tandem.h"
35
36 /* includes for botnet md5 challenge/response code <cybah> */
37 #include "md5/global.h"
38 #include "md5/md5.h"
39
40 extern struct userrec *userlist;
41 extern struct chanset_t *chanset;
42 extern Tcl_Interp *interp;
43 extern time_t now;
44 extern int egg_numver, connect_timeout, conmask, backgrd, max_dcc;
45 extern int make_userfile, default_flags, debug_output, ignore_time;
46 extern char botnetnick[], ver[], origbotname[], notify_new[];
47
48 struct dcc_t *dcc = 0; /* dcc list */
49 int dcc_total = 0; /* total dcc's */
50 char tempdir[121] = ""; /* temporary directory (default: current dir) */
51 int require_p = 0; /* require 'p' access to get on the party line? */
52 int allow_new_telnets = 0; /* allow people to introduce themselves via telnet */
53 int stealth_telnets = 0; /* be paranoid? <cybah> */
54 int use_telnet_banner = 0; /* display telnet banner? [seC] */
55 char network[41] = "unknown-net"; /* name of the IRC network you're on */
56 int password_timeout = 180; /* time to wait for a password from a user */
57 int bot_timeout = 60; /* bot timeout value */
58 int identtimeout = 5; /* timeout value for ident lookups */
59 int protect_telnet = 1; /* even bother with ident lookups :) */
60 int flood_telnet_thr = 5; /* number of telnet connections to be considered a flood */
61 int flood_telnet_time = 60; /* in how many seconds? */
62 extern int min_dcc_port, max_dcc_port; /* valid portrange for telnets */
63 extern int par_telnet_flood; /* trigger telnet flood for +f ppl? */
64 char bannerfile[121] = "telnet-banner"; /* file displayed on telnet login */
65
66 static void strip_telnet(int sock, char *buf, int *len)
67 {
68 unsigned char *p = (unsigned char *) buf, *o = (unsigned char *) buf;
69 int mark;
70
71 while (*p != 0) {
72 while ((*p != 255) && (*p != 0))
73 *o++ = *p++;
74 if (*p == 255) {
75 p++;
76 mark = 2;
77 if (!*p)
78 mark = 1; /* bogus */
79 if ((*p >= 251) && (*p <= 254)) {
80 mark = 3;
81 if (!*(p + 1))
82 mark = 2; /* bogus */
83 }
84 if (*p == 251) {
85 /* WILL X -> response: DONT X */
86 /* except WILL ECHO which we just smile and ignore */
87 if (!(*(p + 1) == 1)) {
88 write(sock, "\377\376", 2);
89 write(sock, p + 1, 1);
90 }
91 }
92 if (*p == 253) {
93 /* DO X -> response: WONT X */
94 /* except DO ECHO which we just smile and ignore */
95 if (!(*(p + 1) == 1)) {
96 write(sock, "\377\374", 2);
97 write(sock, p + 1, 1);
98 }
99 }
100 if (*p == 246) {
101 /* "are you there?" */
102 /* response is: "hell yes!" */
103 write(sock, "\r\nHell, yes!\r\n", 14);
104 }
105 /* anything else can probably be ignored */
106 p += mark - 1;
107 *len = *len - mark;
108 }
109 }
110 *o = *p;
111 }
112
113 static void greet_new_bot(int idx)
114 {
115 int bfl = bot_flags(dcc[idx].user);
116 int i;
117
118 dcc[idx].timeval = now;
119 dcc[idx].u.bot->version[0] = 0;
120 dcc[idx].u.bot->numver = 0;
121 if (bfl & BOT_REJECT) {
122 putlog(LOG_BOTS, "*", DCC_REJECT, dcc[idx].nick);
123 dprintf(idx, "error You are being rejected.\n");
124 dprintf(idx, "bye\n");
125 killsock(dcc[idx].sock);
126 lostdcc(idx);
127 return;
128 }
129 if (bfl & BOT_LEAF)
130 dcc[idx].status |= STAT_LEAF;
131 dcc[idx].status |= STAT_LINKING;
132 #ifndef NO_OLD_BOTNET
133 dprintf(idx, "version %d %d %s <%s>\n", egg_numver, HANDLEN, ver, network);
134 #else
135 dprintf(idx, "v %d %d %s <%s>\n", egg_numver, HANDLEN, ver, network);
136 #endif
137 for (i = 0; i < dcc_total; i++)
138 if (dcc[i].type == &DCC_FORK_BOT) {
139 killsock(dcc[i].sock);
140 lostdcc(i);
141 i--;
142 }
143 }
144
145 static void bot_version(int idx, char *par)
146 {
147 char x[1024];
148 int l;
149
150 Context;
151 dcc[idx].timeval = now;
152 if ((par[0] >= '0') && (par[0] <= '9')) {
153 char *work;
154
155 work = newsplit(&par);
156 dcc[idx].u.bot->numver = atoi(work);
157 } else
158 dcc[idx].u.bot->numver = 0;
159
160 #ifndef NO_OLD_BOTNET
161 if (b_numver(idx) < NEAT_BOTNET) {
162 #if HANDLEN != 9
163 dprintf(idx, "error Non-matching handle length: mine %d, yours 9\n",
164 HANDLEN);
165 dprintf(idx, "bye\n");
166 killsock(dcc[idx].sock);
167 lostdcc(idx);
168 return;
169 #else
170 dprintf(idx, "thisbot %s\n", botnetnick);
171 #endif
172 } else {
173 #endif
174 dprintf(idx, "tb %s\n", botnetnick);
175 l = atoi(newsplit(&par));
176 if (l != HANDLEN) {
177 dprintf(idx, "error Non-matching handle length: mine %d, yours %d\n",
178 HANDLEN, l);
179 dprintf(idx, "bye\n");
180 killsock(dcc[idx].sock);
181 lostdcc(idx);
182 return;
183 }
184 #ifndef NO_OLD_BOTNET
185 }
186 #endif
187 strncpy(dcc[idx].u.bot->version, par, 120);
188 dcc[idx].u.bot->version[120] = 0;
189 putlog(LOG_BOTS, "*", DCC_LINKED, dcc[idx].nick);
190 chatout("*** Linked to %s\n", dcc[idx].nick);
191 botnet_send_nlinked(idx, dcc[idx].nick, botnetnick, '!',
192 dcc[idx].u.bot->numver);
193 dump_links(idx);
194 dcc[idx].type = &DCC_BOT;
195 addbot(dcc[idx].nick, dcc[idx].nick, botnetnick, '-',
196 dcc[idx].u.bot->numver);
197 check_tcl_link(dcc[idx].nick, botnetnick);
198 simple_sprintf(x, "v %d", dcc[idx].u.bot->numver);
199 bot_share(idx, x);
200 dprintf(idx, "el\n");
201 }
202
203 void failed_link(int idx)
204 {
205 char s[81], s1[512];
206
207 if (dcc[idx].port >= dcc[idx].u.bot->port + 3) {
208 if (dcc[idx].u.bot->linker[0]) {
209 sprintf(s, "Couldn't link to %s.", dcc[idx].nick);
210 strcpy(s1, dcc[idx].u.bot->linker);
211 add_note(s1, botnetnick, s, -2, 0);
212 }
213 if (dcc[idx].u.bot->numver >= (-1))
214 putlog(LOG_BOTS, "*", DCC_LINKFAIL, dcc[idx].nick);
215 killsock(dcc[idx].sock);
216 strcpy(s, dcc[idx].nick);
217 lostdcc(idx);
218 autolink_cycle(s); /* check for more auto-connections */
219 return;
220 }
221 /* try next port */
222 killsock(dcc[idx].sock);
223 dcc[idx].sock = getsock(SOCK_STRONGCONN);
224 dcc[idx].port++;
225 dcc[idx].timeval = now;
226 if (open_telnet_raw(dcc[idx].sock, dcc[idx].host, dcc[idx].port) < 0) {
227 failed_link(idx);
228 }
229 }
230
231 static void cont_link(int idx, char *buf, int i)
232 {
233 char x[1024];
234 int atr = bot_flags(dcc[idx].user);
235
236 Context;
237 if (atr & BOT_HUB) {
238 /* disconnect all +a bots because we just got a hub */
239 for (i = 0; i < dcc_total; i++) {
240 if ((i != idx) && (bot_flags(dcc[i].user) & BOT_ALT)) {
241 if ((dcc[i].type == &DCC_FORK_BOT) ||
242 (dcc[i].type == &DCC_BOT_NEW)) {
243 killsock(dcc[i].sock);
244 lostdcc(i);
245 }
246 }
247 }
248 /* just those currently in the process of linking */
249 if (in_chain(dcc[idx].nick)) {
250 i = nextbot(dcc[idx].nick);
251 if (i > 0) {
252 simple_sprintf(x, "Unlinked %s (restructure)", dcc[i].nick);
253 chatout("*** %s\n", x);
254 botnet_send_unlinked(i, dcc[i].nick, x);
255 dprintf(i, "bye\n");
256 killsock(dcc[i].sock);
257 lostdcc(i);
258 }
259 }
260 }
261 dcc[idx].type = &DCC_BOT_NEW;
262 dcc[idx].u.bot->numver = 0;
263
264 /* Don't send our password here, just the username. The code later on
265 * will determine if the password needs to be sent in cleartext or if we
266 * can send an MD5 digest. <cybah>
267 */
268
269 dprintf(idx, "%s\n", botnetnick);
270 return;
271 }
272
273 /* This function generates a digest by combining 'challenge' with
274 * 'password' and then sends it to the other bot. <Cybah>
275 */
276 static void dcc_bot_digest(int idx, char *challenge, char *password)
277 {
278 MD5_CTX md5context;
279 char DigestString[33]; /* 32 for digest in hex + null */
280 unsigned char Digest[16];
281 int i;
282
283 MD5Init(&md5context);
284 MD5Update(&md5context, (unsigned char *)challenge, strlen(challenge));
285 MD5Update(&md5context, (unsigned char *)password, strlen(password));
286 MD5Final(Digest, &md5context);
287
288 for(i=0;i<16;i++)
289 sprintf(DigestString + (i*2), "%.2x", Digest[i]);
290 dprintf(idx, "digest %s\n", DigestString);
291 putlog(LOG_BOTS, "*", "Received challenge from %s... sending response ...", dcc[idx].nick);
292 }
293
294 static void dcc_bot_new(int idx, char *buf, int x)
295 {
296 struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick);
297 char *code;
298
299 strip_telnet(dcc[idx].sock, buf, &x);
300 code = newsplit(&buf);
301 if (!strcasecmp(code, "*hello!")) {
302 greet_new_bot(idx);
303 } else if (!strcasecmp(code, "version") || !strcasecmp(code, "v")) {
304 bot_version(idx, buf);
305 } else if (!strcasecmp(code, "badpass")) {
306 /* we entered the wrong password */
307 putlog(LOG_BOTS, "*", DCC_BADPASS, dcc[idx].nick);
308 } else if (!strcasecmp(code, "passreq")) {
309 char *pass = get_user(&USERENTRY_PASS, u);
310
311 if (!pass || !strcmp(pass, "-")) {
312 putlog(LOG_BOTS, "*", DCC_PASSREQ, dcc[idx].nick);
313 dprintf(idx, "-\n");
314 } else {
315 /* Determine if the other end supports an MD5 digest instead of a
316 * cleartext password. <Cybah>
317 */
318 if(buf && buf[0] && strchr(buf, '<') && strchr(buf+1, '>')) {
319 dcc_bot_digest(idx, buf, pass);
320 } else {
321 dprintf(idx, "%s\n", pass);
322 }
323 }
324 } else if (!strcasecmp(code, "error")) {
325 putlog(LOG_BOTS, "*", DCC_LINKERROR, dcc[idx].nick, buf);
326 }
327 /* ignore otherwise */
328 }
329
330 static void eof_dcc_bot_new(int idx)
331 {
332 Context;
333 putlog(LOG_BOTS, "*", DCC_LOSTBOT, dcc[idx].nick, dcc[idx].port);
334 killsock(dcc[idx].sock);
335 lostdcc(idx);
336 }
337
338 static void timeout_dcc_bot_new(int idx)
339 {
340 putlog(LOG_BOTS, "*", DCC_TIMEOUT, dcc[idx].nick,
341 dcc[idx].host, dcc[idx].port);
342 killsock(dcc[idx].sock);
343 lostdcc(idx);
344 }
345
346 static void display_dcc_bot_new(int idx, char *buf)
347 {
348 sprintf(buf, "bot* waited %lus", now - dcc[idx].timeval);
349 }
350
351 static int expmem_dcc_bot_(void *x)
352 {
353 return sizeof(struct bot_info);
354 }
355
356 static void free_dcc_bot_(int n, void *x)
357 {
358 if (dcc[n].type == &DCC_BOT) {
359 unvia(n, findbot(dcc[n].nick));
360 rembot(dcc[n].nick);
361 }
362 nfree(x);
363 }
364
365 struct dcc_table DCC_BOT_NEW =
366 {
367 "BOT_NEW",
368 0,
369 eof_dcc_bot_new,
370 dcc_bot_new,
371 &bot_timeout,
372 timeout_dcc_bot_new,
373 display_dcc_bot_new,
374 expmem_dcc_bot_,
375 free_dcc_bot_,
376 0
377 };
378
379 /* hash function for tandem bot commands */
380 extern botcmd_t C_bot[];
381
382 static void dcc_bot(int idx, char *code, int i)
383 {
384 char *msg;
385 int f;
386
387 Context;
388 strip_telnet(dcc[idx].sock, code, &i);
389 if (debug_output) {
390 if (code[0] == 's')
391 putlog(LOG_BOTSHARE, "*", "{%s} %s", dcc[idx].nick, code + 2);
392 else
393 putlog(LOG_BOTNET, "*", "[%s] %s", dcc[idx].nick, code);
394 }
395 msg = strchr(code, ' ');
396 if (msg) {
397 *msg = 0;
398 msg++;
399 } else
400 msg = "";
401 f = 0;
402 i = 0;
403 while ((C_bot[i].name != NULL) && (!f)) {
404 int y = strcasecmp(code, C_bot[i].name);
405
406 if (y == 0) {
407 /* found a match */
408 (C_bot[i].func) (idx, msg);
409 f = 1;
410 } else if (y < 0)
411 return;
412 i++;
413 }
414 }
415
416 static void eof_dcc_bot(int idx)
417 {
418 char x[1024];
419
420 simple_sprintf(x, "Lost bot: %s", dcc[idx].nick);
421 putlog(LOG_BOTS, "*", "%s.", x);
422 chatout("*** %s\n", x);
423 botnet_send_unlinked(idx, dcc[idx].nick, x);
424 killsock(dcc[idx].sock);
425 lostdcc(idx);
426 }
427
428 static void display_dcc_bot(int idx, char *buf)
429 {
430 int i = simple_sprintf(buf, "bot flags: ");
431
432 buf[i++] = b_status(idx) & STAT_PINGED ? 'P' : 'p';
433 buf[i++] = b_status(idx) & STAT_SHARE ? 'U' : 'u';
434 buf[i++] = b_status(idx) & STAT_CALLED ? 'C' : 'c';
435 buf[i++] = b_status(idx) & STAT_OFFERED ? 'O' : 'o';
436 buf[i++] = b_status(idx) & STAT_SENDING ? 'S' : 's';
437 buf[i++] = b_status(idx) & STAT_GETTING ? 'G' : 'g';
438 buf[i++] = b_status(idx) & STAT_WARNED ? 'W' : 'w';
439 buf[i++] = b_status(idx) & STAT_LEAF ? 'L' : 'l';
440 buf[i++] = b_status(idx) & STAT_LINKING ? 'I' : 'i';
441 buf[i++] = b_status(idx) & STAT_AGGRESSIVE ? 'a' : 'A';
442 buf[i++] = 0;
443 }
444
445 static void display_dcc_fork_bot(int idx, char *buf)
446 {
447 sprintf(buf, "conn bot");
448 }
449
450 struct dcc_table DCC_BOT =
451 {
452 "BOT",
453 DCT_BOT,
454 eof_dcc_bot,
455 dcc_bot,
456 0,
457 0,
458 display_dcc_bot,
459 expmem_dcc_bot_,
460 free_dcc_bot_,
461 0
462 };
463
464 struct dcc_table DCC_FORK_BOT =
465 {
466 "FORK_BOT",
467 0,
468 failed_link,
469 cont_link,
470 &connect_timeout,
471 failed_link,
472 display_dcc_fork_bot,
473 expmem_dcc_bot_,
474 free_dcc_bot_,
475 0
476 };
477
478 /* This function generates a digest by combining a challenge consisting of
479 * our process id + connection time + botnetnick. The digest is then compared
480 * to the one given by the remote bot. Returns 1 if the digest matches,
481 * otherwise returns 0. <Cybah>
482 */
483 static int dcc_bot_check_digest(int idx, char *digest)
484 {
485 MD5_CTX md5context;
486 char DigestString[33]; /* 32 for digest in hex + null */
487 unsigned char Digest[16];
488 int i;
489 char *password = get_user(&USERENTRY_PASS, dcc[idx].user);
490
491 MD5Init(&md5context);
492
493 #ifdef HAVE_SNPRINTF
494 snprintf(DigestString, 33, "<%x%x@", getpid(), (unsigned int)dcc[idx].timeval);
495 #else
496 sprintf(DigestString, "<%x%x@", getpid(), (unsigned int)dcc[idx].timeval);
497 #endif
498 MD5Update(&md5context, (unsigned char *)DigestString, strlen(DigestString));
499 MD5Update(&md5context, (unsigned char *)botnetnick, strlen(botnetnick));
500 MD5Update(&md5context, (unsigned char *)">", 1);
501 MD5Update(&md5context, (unsigned char *)password, strlen(password));
502
503 MD5Final(Digest, &md5context);
504
505 for(i=0;i<16;i++)
506 sprintf(DigestString + (i*2), "%.2x", Digest[i]);
507
508 if(!strcmp(DigestString, digest)) {
509 return 1;
510 }
511 putlog(LOG_BOTS, "*", "Response (password hash) from %s incorrect", dcc[idx].nick);
512 return 0;
513 }
514
515 static void dcc_chat_pass(int idx, char *buf, int atr)
516 {
517 if (!atr)
518 return;
519 strip_telnet(dcc[idx].sock, buf, &atr);
520 atr = dcc[idx].user ? dcc[idx].user->flags : 0;
521
522 /* Check for MD5 digest from remote _bot_. <cybah> */
523 if ((atr & USER_BOT) && !strncasecmp(buf, "digest ", 7)) {
524 if(dcc_bot_check_digest(idx, buf+7)) {
525 nfree(dcc[idx].u.chat);
526 dcc[idx].type = &DCC_BOT_NEW;
527 dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
528 dcc[idx].status = STAT_CALLED;
529 dprintf(idx, "*hello!\n");
530 greet_new_bot(idx);
531 return;
532 } else {
533 /* invalid password/digest */
534 dprintf(idx, "badpass\n");
535 putlog(LOG_MISC, "*", DCC_BADLOGIN, dcc[idx].nick, dcc[idx].host,
536 dcc[idx].port);
537 killsock(dcc[idx].sock);
538 lostdcc(idx);
539 return;
540 }
541 }
542
543 if (u_pass_match(dcc[idx].user, buf)) {
544 if (atr & USER_BOT) {
545 nfree(dcc[idx].u.chat);
546 dcc[idx].type = &DCC_BOT_NEW;
547 dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
548
549 dcc[idx].status = STAT_CALLED;
550 dprintf(idx, "*hello!\n");
551 greet_new_bot(idx);
552 } else {
553 /* log entry for successful login -slennox 3/28/1999 */
554 putlog(LOG_MISC, "*", DCC_LOGGEDIN, dcc[idx].nick,
555 dcc[idx].host, dcc[idx].port);
556 if (dcc[idx].u.chat->away) {
557 nfree(dcc[idx].u.chat->away);
558 dcc[idx].u.chat->away = NULL;
559 }
560 dcc[idx].type = &DCC_CHAT;
561 dcc[idx].status &= ~STAT_CHAT;
562 dcc[idx].u.chat->con_flags = (atr & USER_MASTER) ? conmask : 0;
563 dcc[idx].u.chat->channel = -2;
564 if (dcc[idx].status & STAT_TELNET)
565 dprintf(idx, "\377\374\001\n"); /* turn echo back on */
566 dcc_chatter(idx);
567 }
568 } else {
569 if (atr & USER_BOT)
570 dprintf(idx, "badpass\n");
571 else
572 dprintf(idx, DCC_HOUSTON);
573 putlog(LOG_MISC, "*", DCC_BADLOGIN, dcc[idx].nick,
574 dcc[idx].host, dcc[idx].port);
575 if (dcc[idx].u.chat->away) { /* su from a dumb user */
576 if (dcc[idx].status & STAT_TELNET)
577 dprintf(idx, "\377\374\001\n"); /* turn echo back on */
578 dcc[idx].user = get_user_by_handle(userlist, dcc[idx].u.chat->away);
579 strcpy(dcc[idx].nick, dcc[idx].u.chat->away);
580 nfree(dcc[idx].u.chat->away);
581 nfree(dcc[idx].u.chat->su_nick);
582 dcc[idx].u.chat->away = NULL;
583 dcc[idx].u.chat->su_nick = NULL;
584 dcc[idx].type = &DCC_CHAT;
585 if (dcc[idx].u.chat->channel < 100000)
586 botnet_send_join_idx(idx, -1);
587 chanout_but(-1, dcc[idx].u.chat->channel, DCC_JOIN, dcc[idx].nick);
588 } else {
589 killsock(dcc[idx].sock);
590 lostdcc(idx);
591 }
592 }
593 }
594
595 static void eof_dcc_general(int idx)
596 {
597 putlog(LOG_MISC, "*", DCC_LOSTDCC, dcc[idx].nick,
598 dcc[idx].host, dcc[idx].port);
599 killsock(dcc[idx].sock);
600 lostdcc(idx);
601 }
602
603 static void tout_dcc_chat_pass(int idx)
604 {
605 dprintf(idx, "Timeout.\n");
606 putlog(LOG_MISC, "*", DCC_PWDTIMEOUT, dcc[idx].nick,
607 dcc[idx].host);
608 killsock(dcc[idx].sock);
609 lostdcc(idx);
610 }
611
612 static void display_dcc_chat_pass(int idx, char *buf)
613 {
614 sprintf(buf, "pass waited %lus", now - dcc[idx].timeval);
615 }
616
617 static int expmem_dcc_general(void *x)
618 {
619 register struct chat_info *p = (struct chat_info *) x;
620 int tot = sizeof(struct chat_info);
621
622 if (p->away)
623 tot += strlen(p->away) + 1;
624 if (p->buffer) {
625 struct msgq *q = p->buffer;
626
627 while (q) {
628 tot += sizeof(struct list_type);
629
630 tot += q->len + 1;
631 q = q->next;
632 }
633 }
634 if (p->su_nick)
635 tot += strlen(p->su_nick) + 1;
636 return tot;
637 }
638
639 static void kill_dcc_general(int idx, void *x)
640 {
641 register struct chat_info *p = (struct chat_info *) x;
642
643 if (p) {
644 if (p->buffer) {
645 struct msgq *r = dcc[idx].u.chat->buffer, *q;
646
647 while (r) {
648 q = r->next;
649 nfree(r->msg);
650 nfree(r);
651 r = q;
652 }
653 }
654 if (p->away) {
655 nfree(p->away);
656 }
657 nfree(p);
658 }
659 }
660
661 /* Remove the color control codes that mIRC,pIRCh etc use to make
662 * their client seem so fecking cool! (Sorry, Khaled, you are a nice
663 * guy, but when you added this feature you forced people to either
664 * use your *SHAREWARE* client or face screenfulls of crap!) */
665 static void strip_mirc_codes(int flags, char *text)
666 {
667 char *dd = text;
668
669 while (*text) {
670 switch (*text) {
671 case 2: /* Bold text */
672 if (flags & STRIP_BOLD) {
673 text++;
674 continue;
675 }
676 break;
677 case 3: /* mIRC colors? */
678 if (flags & STRIP_COLOR) {
679 if (isdigit(text[1])) { /* Is the first char a number? */
680 text += 2; /* Skip over the ^C and the first digit */
681 if (isdigit(*text))
682 text++; /* Is this a double digit number? */
683 if (*text == ',') { /* Do we have a background color next? */
684 if (isdigit(text[1]))
685 text += 2; /* Skip over the first background digit */
686 if (isdigit(*text))
687 text++; /* Is it a double digit? */
688 }
689 } else
690 text++;
691 continue;
692 }
693 break;
694 case 7:
695 if (flags & STRIP_BELLS) {
696 text++;
697 continue;
698 }
699 break;
700 case 0x16: /* Reverse video */
701 if (flags & STRIP_REV) {
702 text++;
703 continue;
704 }
705 break;
706 case 0x1f: /* Underlined text */
707 if (flags & STRIP_UNDER) {
708 text++;
709 continue;
710 }
711 break;
712 case 033:
713 if (flags & STRIP_ANSI) {
714 text++;
715 if (*text == '[') {
716 text++;
717 while ((*text == ';') || isdigit(*text))
718 text++;
719 if (*text)
720 text++; /* also kill the following char */
721 }
722 continue;
723 }
724 break;
725 }
726 *dd++ = *text++; /* Move on to the next char */
727 }
728 *dd = 0;
729 }
730
731 static void append_line(int idx, char *line)
732 {
733 int l = strlen(line);
734 struct msgq *p, *q;
735 struct chat_info *c = (dcc[idx].type == &DCC_CHAT) ? dcc[idx].u.chat :
736 dcc[idx].u.file->chat;
737
738 if (c->current_lines > 1000) {
739 p = c->buffer;
740 /* they're probably trying to fill up the bot nuke the sods :) */
741 while (p) { /* flush their queue */
742 q = p->next;
743 nfree(p->msg);
744 nfree(p);
745 p = q;
746 }
747 c->buffer = 0;
748 dcc[idx].status &= ~STAT_PAGE;
749 do_boot(idx, botnetnick, "too many pages - senq full");
750 return;
751 }
752 if ((c->line_count < c->max_line) && (c->buffer == NULL)) {
753 c->line_count++;
754 tputs(dcc[idx].sock, line, l);
755 } else {
756 c->current_lines++;
757 if (c->buffer == NULL)
758 q = NULL;
759 else {
760 q = c->buffer;
761 while (q->next != NULL)
762 q = q->next;
763 }
764 p = get_data_ptr(sizeof(struct msgq));
765
766 p->len = l;
767 p->msg = get_data_ptr(l + 1);
768 p->next = NULL;
769 strcpy(p->msg, line);
770 if (q == NULL)
771 c->buffer = p;
772 else
773 q->next = p;
774 }
775 }
776
777 static void out_dcc_general(int idx, char *buf, void *x)
778 {
779 register struct chat_info *p = (struct chat_info *) x;
780 char *y = buf;
781
782 strip_mirc_codes(p->strip_flags, buf);
783 if (dcc[idx].status & STAT_TELNET)
784 y = add_cr(buf);
785 if (dcc[idx].status & STAT_PAGE)
786 append_line(idx, y);
787 else
788 tputs(dcc[idx].sock, y, strlen(y));
789 }
790
791 struct dcc_table DCC_CHAT_PASS =
792 {
793 "CHAT_PASS",
794 0,
795 eof_dcc_general,
796 dcc_chat_pass,
797 &password_timeout,
798 tout_dcc_chat_pass,
799 display_dcc_chat_pass,
800 expmem_dcc_general,
801 kill_dcc_general,
802 out_dcc_general
803 };
804
805 /* make sure ansi code is just for color-changing */
806 static int check_ansi(char *v)
807 {
808 int count = 2;
809
810 if (*v++ != '\033')
811 return 1;
812 if (*v++ != '[')
813 return 1;
814 while (*v) {
815 if (*v == 'm')
816 return 0;
817 if ((*v != ';') && ((*v < '0') || (*v > '9')))
818 return count;
819 v++;
820 count++;
821 }
822 return count;
823 }
824
825 static void eof_dcc_chat(int idx)
826 {
827 Context;
828 putlog(LOG_MISC, "*", DCC_LOSTDCC, dcc[idx].nick,
829 dcc[idx].host, dcc[idx].port);
830 Context;
831 if (dcc[idx].u.chat->channel >= 0) {
832 chanout_but(idx, dcc[idx].u.chat->channel, "*** %s lost dcc link.\n",
833 dcc[idx].nick);
834 Context;
835 if (dcc[idx].u.chat->channel < 100000)
836 botnet_send_part_idx(idx, "lost dcc link");
837 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
838 dcc[idx].u.chat->channel);
839 }
840 Context;
841 check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
842 Context;
843 killsock(dcc[idx].sock);
844 Context;
845 lostdcc(idx);
846 Context;
847 }
848
849 static void dcc_chat(int idx, char *buf, int i)
850 {
851 int nathan = 0, doron = 0, fixed = 0;
852 char *v, *d;
853
854 Context;
855 strip_telnet(dcc[idx].sock, buf, &i);
856 if (buf[0] && (buf[0] != '.') &&
857 detect_dcc_flood(&dcc[idx].timeval, dcc[idx].u.chat, idx))
858 return;
859 dcc[idx].timeval = now;
860 if (buf[0])
861 strcpy(buf, check_tcl_filt(idx, buf));
862 if (buf[0]) {
863 /* check for beeps and cancel annoying ones */
864 v = buf;
865 d = buf;
866 while (*v)
867 switch (*v) {
868 case 7: /* beep - no more than 3 */
869 nathan++;
870 if (nathan > 3)
871 v++;
872 else
873 *d++ = *v++;
874 break;
875 case 8: /* backspace - for lame telnet's :) */
876 if (d > buf) {
877 d--;
878 }
879 v++;
880 break;
881 case 27: /* ESC - ansi code? */
882 doron = check_ansi(v);
883 /* if it's valid, append a return-to-normal code at the end */
884 if (!doron) {
885 *d++ = *v++;
886 fixed = 1;
887 } else
888 v += doron;
889 break;
890 case '\r': /* weird pseudo-linefeed */
891 v++;
892 break;
893 default:
894 *d++ = *v++;
895 }
896 if (fixed)
897 strcpy(d, "\033[0m");
898 else
899 *d = 0;
900 if (buf[0]) { /* nothing to say - maybe paging... */
901 if ((buf[0] == '.') || (dcc[idx].u.chat->channel < 0)) {
902 if (buf[0] == '.')
903 buf++;
904 v = newsplit(&buf);
905 rmspace(buf);
906 if (check_tcl_dcc(v, idx, buf)) {
907 if (dcc[idx].u.chat->channel >= 0)
908 check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock,
909 dcc[idx].u.chat->channel);
910 check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
911 dprintf(idx, "*** Ja mata!\n");
912 flush_lines(idx, dcc[idx].u.chat);
913 putlog(LOG_MISC, "*", DCC_CLOSED, dcc[idx].nick,
914 dcc[idx].host);
915 if (dcc[idx].u.chat->channel >= 0) {
916 chanout_but(-1, dcc[idx].u.chat->channel,
917 "*** %s left the party line%s%s\n",
918 dcc[idx].nick, buf[0] ? ": " : ".", buf);
919 if (dcc[idx].u.chat->channel < 100000)
920 botnet_send_part_idx(idx, buf);
921 }
922 if (dcc[idx].u.chat->su_nick) {
923 dcc[idx].user = get_user_by_handle(userlist, dcc[idx].u.chat->su_nick);
924 strcpy(dcc[idx].nick, dcc[idx].u.chat->su_nick);
925 dcc[idx].type = &DCC_CHAT;
926 if (dcc[idx].u.chat->channel < 100000)
927 botnet_send_join_idx(idx, -1);
928 dprintf(idx, "Returning to real nick %s!\r\n", dcc[idx].u.chat->su_nick);
929 nfree(dcc[idx].u.chat->su_nick);
930 dcc[idx].u.chat->su_nick = NULL;
931 /* chanout_but(-1, dcc[idx].u.chat->channel, "*** %s has rejoined the party line.\n", dcc[idx].nick); */
932 dcc_chatter(idx);
933 return;
934 } else if ((dcc[idx].sock != STDOUT) || backgrd) {
935 killsock(dcc[idx].sock);
936 lostdcc(idx);
937 return;
938 } else {
939 dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n");
940 dcc_chatter(idx);
941 return;
942 }
943 }
944 } else if (buf[0] == ',') {
945 int me = 0;
946
947 if ((buf[1] == 'm') && (buf[2] == 'e') && buf[3] == ' ')
948 me = 1;
949 for (i = 0; i < dcc_total; i++) {
950 int ok = 0;
951
952 if (dcc[i].type->flags & DCT_MASTER) {
953 if ((dcc[i].type != &DCC_CHAT) ||
954 (dcc[i].u.chat->channel >= 0))
955 if ((i != idx) || (dcc[idx].status & STAT_ECHO))
956 ok = 1;
957 }
958 if (ok) {
959 struct userrec *u = get_user_by_handle(userlist, dcc[i].nick);
960
961 if (u && (u->flags & USER_MASTER)) {
962 if (me)
963 dprintf(i, "-> %s%s\n", dcc[idx].nick, buf + 3);
964 else
965 dprintf(i, "-%s-> %s\n", dcc[idx].nick, buf + 1);
966 }
967 }
968 }
969 } else if (buf[0] == '\'') {
970 int me = 0;
971
972 if ((buf[1] == 'm') && (buf[2] == 'e') &&
973 ((buf[3] == ' ') || (buf[3] == '\'') || (buf[3] == ',')))
974 me = 1;
975 for (i = 0; i < dcc_total; i++) {
976 if (dcc[i].type->flags & DCT_CHAT) {
977 if (me)
978 dprintf(i, "=> %s%s\n", dcc[idx].nick, buf + 3);
979 else
980 dprintf(i, "=%s=> %s\n", dcc[idx].nick, buf + 1);
981 }
982 }
983 } else {
984 if (dcc[idx].u.chat->away != NULL)
985 not_away(idx);
986 if (dcc[idx].status & STAT_ECHO)
987 chanout_but(-1, dcc[idx].u.chat->channel,
988 "<%s> %s\n", dcc[idx].nick, buf);
989 else
990 chanout_but(idx, dcc[idx].u.chat->channel, "<%s> %s\n",
991 dcc[idx].nick, buf);
992 botnet_send_chan(-1, botnetnick, dcc[idx].nick,
993 dcc[idx].u.chat->channel, buf);
994 check_tcl_chat(dcc[idx].nick, dcc[idx].u.chat->channel, buf);
995 }
996 }
997 }
998 if (dcc[idx].type == &DCC_CHAT) /* could have change to files */
999 if (dcc[idx].status & STAT_PAGE)
1000 flush_lines(idx, dcc[idx].u.chat);
1001 }
1002
1003 static void display_dcc_chat(int idx, char *buf)
1004 {
1005 int i = simple_sprintf(buf, "chat flags: ");
1006
1007 buf[i++] = dcc[idx].status & STAT_CHAT ? 'C' : 'c';
1008 buf[i++] = dcc[idx].status & STAT_PARTY ? 'P' : 'p';
1009 buf[i++] = dcc[idx].status & STAT_TELNET ? 'T' : 't';
1010 buf[i++] = dcc[idx].status & STAT_ECHO ? 'E' : 'e';
1011 buf[i++] = dcc[idx].status & STAT_PAGE ? 'P' : 'p';
1012 simple_sprintf(buf + i, "/%d", dcc[idx].u.chat->channel);
1013 }
1014
1015 struct dcc_table DCC_CHAT =
1016 {
1017 "CHAT",
1018 DCT_CHAT | DCT_MASTER | DCT_SHOWWHO | DCT_VALIDIDX | DCT_SIMUL |
1019 DCT_CANBOOT | DCT_REMOTEWHO,
1020 eof_dcc_chat,
1021 dcc_chat,
1022 0,
1023 0,
1024 display_dcc_chat,
1025 expmem_dcc_general,
1026 kill_dcc_general,
1027 out_dcc_general
1028 };
1029
1030 static int lasttelnets;
1031 static char lasttelnethost[81];
1032 static time_t lasttelnettime;
1033
1034 /* a modified detect_flood for incoming telnet flood protection */
1035 static int detect_telnet_flood(char *floodhost)
1036 {
1037 struct flag_record fr =
1038 {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
1039 Context;
1040 get_user_flagrec(get_user_by_host(floodhost), &fr, NULL);
1041 Context;
1042 if (flood_telnet_thr == 0 || (glob_friend(fr) && !par_telnet_flood))
1043 return 0; /* no flood protection */
1044 if (strcasecmp(lasttelnethost, floodhost) != 0) { /* new */
1045 strcpy(lasttelnethost, floodhost);
1046 lasttelnettime = now;
1047 lasttelnets = 0;
1048 return 0;
1049 }
1050 if (lasttelnettime < now - flood_telnet_time) {
1051 /* flood timer expired, reset it */
1052 lasttelnettime = now;
1053 lasttelnets = 0;
1054 return 0;
1055 }
1056 lasttelnets++;
1057 if (lasttelnets >= flood_telnet_thr) { /* FLOOD */
1058 /* reset counters */
1059 lasttelnets = 0;
1060 lasttelnettime = 0;
1061 lasttelnethost[0] = 0;
1062 putlog(LOG_MISC, "*", IRC_TELNETFLOOD, floodhost);
1063 addignore(floodhost, origbotname, "Telnet connection flood",
1064 now + (60 * ignore_time));
1065 return 1;
1066 }
1067 return 0;
1068 }
1069
1070 static void dcc_telnet_got_ident(int, char *);
1071
1072 static void dcc_telnet(int idx, char *buf, int i)
1073 {
1074 unsigned long ip;
1075 unsigned short port;
1076 int j = 0, sock;
1077 char s[UHOSTLEN], s2[UHOSTLEN + 20];
1078
1079 Context;
1080 if (dcc_total + 1 > max_dcc) {
1081 j = answer(dcc[idx].sock, s, &ip, &port, 0);
1082 if (j != -1) {
1083 dprintf(-j, "Sorry, too many connections already.\r\n");
1084 killsock(j);
1085 }
1086 return;
1087 }
1088 Context;
1089 sock = answer(dcc[idx].sock, s, &ip, &port, 0);
1090 while ((sock == -1) && (errno == EAGAIN))
1091 sock = answer(sock, s, &ip, &port, 0);
1092 if (sock < 0) {
1093 neterror(s);
1094 putlog(LOG_MISC, "*", DCC_FAILED, s);
1095 killsock(sock);
1096 return;
1097 }
1098 /* <bindle> [09:37] Telnet connection: 168.246.255.191/0
1099 * <bindle> [09:37] Lost connection while identing [168.246.255.191/0]
1100 */
1101 Context;
1102 /* use dcc-portrange x:x on incoming telnets too, dw */
1103 if ((port < min_dcc_port) || (port > max_dcc_port)) {
1104 putlog(LOG_BOTS, "*", DCC_BADSRC, s, port);
1105 killsock(sock);
1106 return;
1107 }
1108 Context;
1109 /* deny ips that ends with 0 or 255, dw */
1110 if ((ip & 0xff) == 0 || (ip & 0xff) == 0xff) {
1111 putlog(LOG_BOTS, "*", DCC_BADIP, s, port);
1112 killsock(sock);
1113 return;
1114 }
1115 if (dcc[idx].host[0] == '@') {
1116 /* restrict by hostname */
1117 if (!wild_match(dcc[idx].host + 1, s)) {
1118 putlog(LOG_BOTS, "*", DCC_BADHOST, s);
1119 killsock(sock);
1120 return;
1121 }
1122 }
1123 Context;
1124 sprintf(s2, "telnet!telnet@%s", s);
1125 if (match_ignore(s2) || detect_telnet_flood(s2)) {
1126 killsock(sock);
1127 return;
1128 }
1129 Context;
1130 i = new_dcc(&DCC_IDENTWAIT, 0);
1131 dcc[i].sock = sock;
1132 dcc[i].addr = ip;
1133 dcc[i].port = port;
1134 dcc[i].timeval = now;
1135 dcc[i].u.ident_sock = dcc[idx].sock;
1136 strncpy(dcc[i].host, s, UHOSTMAX);
1137 dcc[i].host[UHOSTMAX] = 0;
1138 strcpy(dcc[i].nick, "*");
1139 sock = open_telnet(s, 113);
1140 putlog(LOG_MISC, "*", DCC_TELCONN, s, port);
1141 s[0] = 0;
1142 Context;
1143 if (sock < 0) {
1144 if (sock == -2)
1145 strcpy(s, "DNS lookup failed for ident");
1146 else
1147 neterror(s);
1148 } else {
1149 j = new_dcc(&DCC_IDENT, 0);
1150 if (j < 0) {
1151 killsock(sock);
1152 strcpy(s, "No Free DCC's");
1153 }
1154 }
1155 Context;
1156 if (s[0]) {
1157 putlog(LOG_MISC, "*", DCC_IDENTFAIL, dcc[i].host, s);
1158 sprintf(s, "telnet@%s", dcc[i].host);
1159 dcc_telnet_got_ident(i, s);
1160 return;
1161 }
1162 Context;
1163 dcc[j].sock = sock;
1164 dcc[j].port = 113;
1165 dcc[j].addr = ip;
1166 strcpy(dcc[j].host, dcc[i].host);
1167 strcpy(dcc[j].nick, "*");
1168 dcc[j].u.ident_sock = dcc[i].sock;
1169 dcc[j].timeval = now;
1170 dprintf(j, "%d, %d\n", dcc[i].port, dcc[idx].port);
1171 }
1172
1173 static void eof_dcc_telnet(int idx)
1174 {
1175 putlog(LOG_MISC, "*", DCC_PORTDIE,
1176 dcc[idx].port);
1177 killsock(dcc[idx].sock);
1178 lostdcc(idx);
1179 }
1180
1181 static void display_telnet(int idx, char *buf)
1182 {
1183 sprintf(buf, "lstn %d", dcc[idx].port);
1184 }
1185
1186 struct dcc_table DCC_TELNET =
1187 {
1188 "TELNET",
1189 DCT_LISTEN,
1190 eof_dcc_telnet,
1191 dcc_telnet,
1192 0,
1193 0,
1194 display_telnet,
1195 0,
1196 0,
1197 0
1198 };
1199
1200 static void dcc_telnet_id(int idx, char *buf, int atr)
1201 {
1202 int ok = 0;
1203 struct flag_record fr =
1204 {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0};
1205
1206 Context;
1207 strip_telnet(dcc[idx].sock, buf, &atr);
1208 buf[HANDLEN] = 0;
1209 /* toss out bad nicknames */
1210 if ((dcc[idx].nick[0] != '@') && (!wild_match(dcc[idx].nick, buf))) {
1211 dprintf(idx, "Sorry, that nickname format is invalid.\r\n");
1212 putlog(LOG_BOTS, "*", DCC_BADNICK, dcc[idx].host);
1213 killsock(dcc[idx].sock);
1214 lostdcc(idx);
1215 return;
1216 }
1217 dcc[idx].user = get_user_by_handle(userlist, buf);
1218 get_user_flagrec(dcc[idx].user, &fr, NULL);
1219 /* make sure users-only/bots-only connects are honored */
1220 if ((dcc[idx].status & STAT_BOTONLY) && !glob_bot(fr)) {
1221 dprintf(idx, "This telnet port is for bots only.\r\n");
1222 putlog(LOG_BOTS, "*", DCC_NONBOT, dcc[idx].host);
1223 killsock(dcc[idx].sock);
1224 lostdcc(idx);
1225 return;
1226 }
1227 if ((dcc[idx].status & STAT_USRONLY) && glob_bot(fr)) {
1228 dprintf(idx, "error Only users may connect at this port.\n");
1229 putlog(LOG_BOTS, "*", DCC_NONUSER, dcc[idx].host);
1230 killsock(dcc[idx].sock);
1231 lostdcc(idx);
1232 return;
1233 }
1234 dcc[idx].status &= ~(STAT_BOTONLY | STAT_USRONLY);
1235 if ((!strcasecmp(buf, "NEW")) &&
1236 ((allow_new_telnets) || (make_userfile))) {
1237 dcc[idx].type = &DCC_TELNET_NEW;
1238 dcc[idx].timeval = now;
1239 dprintf(idx, "\r\n");
1240 dprintf(idx, IRC_TELNET, IRC_TELNET_ARGS);
1241 dprintf(idx, IRC_TELNET1);
1242 dprintf(idx, "\r\nEnter the nickname you would like to use.\r\n");
1243 return;
1244 }
1245 if (chan_op(fr)) {
1246 if (!require_p)
1247 ok = 1;
1248 }
1249 if (glob_party(fr) || glob_bot(fr))
1250 ok = 1;
1251 if (glob_xfer(fr)) {
1252 module_entry *me = module_find("filesys", 0, 0);
1253
1254 if (me && me->funcs[FILESYS_ISVALID] && (me->funcs[FILESYS_ISVALID]) ())
1255 ok = 1;
1256 }
1257 if (!ok) {
1258 dprintf(idx, "You don't have access.\r\n");
1259 putlog(LOG_BOTS, "*", DCC_INVHANDLE, dcc[idx].host, buf);
1260 killsock(dcc[idx].sock);
1261 lostdcc(idx);
1262 return;
1263 }
1264 if (glob_bot(fr)) {
1265 if (!strcasecmp(botnetnick, buf)) {
1266 dprintf(idx, "error You cannot link using my botnetnick.\n");
1267 putlog(LOG_BOTS, "*", DCC_MYBOTNETNICK, dcc[idx].host);
1268 killsock(dcc[idx].sock);
1269 lostdcc(idx);
1270 return;
1271 } else if (in_chain(buf)) {
1272 dprintf(idx, "error Already connected.\n");
1273 putlog(LOG_BOTS, "*", DCC_DUPLICATE,
1274 dcc[idx].host);
1275 killsock(dcc[idx].sock);
1276 lostdcc(idx);
1277 return;
1278 }
1279 }
1280 /* no password set? */
1281 if (u_pass_match(dcc[idx].user, "-")) {
1282 if (glob_bot(fr)) {
1283 char ps[20];
1284
1285 makepass(ps);
1286 set_user(&USERENTRY_PASS, dcc[idx].user, ps);
1287 correct_handle(buf);
1288 strcpy(dcc[idx].nick, buf);
1289 nfree(dcc[idx].u.chat);
1290 dcc[idx].u.bot = get_data_ptr(sizeof(struct bot_info));
1291
1292 dcc[idx].type = &DCC_BOT_NEW;
1293 dcc[idx].status = STAT_CALLED;
1294 dprintf(idx, "*hello!\n");
1295 greet_new_bot(idx);
1296 #ifdef NO_OLD_BOTNET
1297 dprintf(idx, "h %s\n", ps);
1298 #else
1299 dprintf(idx, "handshake %s\n", ps);
1300 #endif
1301 return;
1302 }
1303 dprintf(idx, "Can't telnet until you have a password set.\r\n");
1304 putlog(LOG_MISC, "*", DCC_NOPASS, buf, dcc[idx].host);
1305 killsock(dcc[idx].sock);
1306 lostdcc(idx);
1307 return;
1308 }
1309 ok = 0;
1310 dcc[idx].type = &DCC_CHAT_PASS;
1311 dcc[idx].timeval = now;
1312 if (glob_botmast(fr))
1313 ok = 1;
1314 else if (chan_op(fr)) {
1315 if (!require_p)
1316 ok = 1;
1317 else if (glob_party(fr))
1318 ok = 1;
1319 } else if (glob_party(fr)) {
1320 ok = 1;
1321 dcc[idx].status |= STAT_PARTY;
1322 }
1323 if (glob_bot(fr))
1324 ok = 1;
1325 if (!ok) {
1326 struct chat_info *ci;
1327
1328 ci = dcc[idx].u.chat;
1329 dcc[idx].u.file = get_data_ptr(sizeof(struct file_info));
1330
1331 dcc[idx].u.file->chat = ci;
1332 }
1333 correct_handle(buf);
1334 strcpy(dcc[idx].nick, buf);
1335
1336 if (glob_bot(fr)) {
1337 /* Must generate a string consisting of our process ID and the current
1338 * time. The bot will add it's password to the end and use it to generate
1339 * an MD5 checksum (always 128bit). The checksum is sent back and this
1340 * end does the same. The remote bot is only allowed access if the
1341 * checksums match. Please don't fuck with 'timeval', or the digest we
1342 * generate later for authentication will not be correct - you've been
1343 * warned ;) <Cybah>
1344 */
1345 putlog(LOG_BOTS, "*", "Challenging %s...", dcc[idx].nick);
1346 dprintf(idx, "passreq <%x%x@%s>\n", getpid(), dcc[idx].timeval, botnetnick);
1347 } else {
1348 /* *note* The MD5 digest used above to prevent cleartext passwords
1349 * being sent across the net will _only_ work when we have the cleartext
1350 * password. User passwords are encrypted (with blowfish usually) so the
1351 * same thing cant be done. Botnet passwords are always stored in
1352 * cleartext, or at least something that can be reversed. <Cybah>
1353 */
1354 dprintf(idx, "\n%s\377\373\001\n",DCC_ENTERPASS);
1355 /* turn off remote telnet echo: IAC WILL ECHO */
1356 }
1357 }
1358
1359 static void eof_dcc_telnet_id(int idx)
1360 {
1361 putlog(LOG_MISC, "*", DCC_LOSTCON, dcc[idx].host,
1362 dcc[idx].port);
1363 killsock(dcc[idx].sock);
1364 lostdcc(idx);
1365 }
1366
1367 static void timeout_dcc_telnet_id(int idx)
1368 {
1369 dprintf(idx, "Timeout.\n");
1370 putlog(LOG_MISC, "*", DCC_TTIMEOUT, dcc[idx].host);
1371 killsock(dcc[idx].sock);
1372 lostdcc(idx);
1373 }
1374
1375 static void display_dcc_telnet_id(int idx, char *buf)
1376 {
1377 sprintf(buf, "t-in waited %lus", now - dcc[idx].timeval);
1378 }
1379
1380 struct dcc_table DCC_TELNET_ID =
1381 {
1382 "TELNET_ID",
1383 0,
1384 eof_dcc_telnet_id,
1385 dcc_telnet_id,
1386 &password_timeout,
1387 timeout_dcc_telnet_id,
1388 display_dcc_telnet_id,
1389 expmem_dcc_general,
1390 kill_dcc_general,
1391 out_dcc_general
1392 };
1393
1394 static void dcc_telnet_new(int idx, char *buf, int x)
1395 {
1396 int ok = 1;
1397 char work[1024], *p, *q, *r;
1398
1399 buf[HANDLEN] = 0;
1400 strip_telnet(dcc[idx].sock, buf, &x);
1401 strcpy(dcc[idx].nick, buf);
1402 dcc[idx].timeval = now;
1403 for (x = 0; x < strlen(buf); x++)
1404 if ((buf[x] <= 32) || (buf[x] >= 127))
1405 ok = 0;
1406 if (!ok) {
1407 dprintf(idx, "\nYou can't use weird symbols in your nick.\n");
1408 dprintf(idx, "Try another one please:\n");
1409 } else if (strchr("-,+*=:!.@#;$", buf[0]) != NULL) {
1410 dprintf(idx, "\nYou can't start your nick with the character '%c'\n", buf[0]);
1411 dprintf(idx, "Try another one please:\n");
1412 } else if (get_user_by_handle(userlist, buf)) {
1413 dprintf(idx, "\nSorry, that nickname is taken already.\n");
1414 dprintf(idx, "Try another one please:\n");
1415 return;
1416 } else if (!strcasecmp(buf, origbotname) || !strcasecmp(buf, botnetnick)) {
1417 dprintf(idx, "Sorry, can't use my name for a nick.\n");
1418 } else {
1419 if (make_userfile)
1420 userlist = adduser(userlist, buf, "telnet!*@*", "-",
1421 sanity_check(default_flags | USER_PARTY |
1422 USER_MASTER | USER_OWNER));
1423 else {
1424 p = strchr(dcc[idx].host, '@');
1425 if (p) {
1426 q = p;
1427 *q = 0;
1428 p++;
1429 r = strchr(p, '.');
1430 if (!r)
1431 simple_sprintf(work, "telnet!%s@%s", dcc[idx].host, p);
1432 else
1433 simple_sprintf(work, "telnet!%s@*%s", dcc[idx].host, r);
1434 *q = '@';
1435 } else
1436 simple_sprintf(work, "telnet!*@*%s", dcc[idx].host);
1437 userlist = adduser(userlist, buf, work, "-",
1438 sanity_check(USER_PARTY | default_flags));
1439 }
1440 reaffirm_owners();
1441 dcc[idx].status = STAT_ECHO | STAT_TELNET;
1442 dcc[idx].type = &DCC_CHAT; /* just so next line will work */
1443 dcc[idx].user = get_user_by_handle(userlist, buf);
1444 check_dcc_attrs(dcc[idx].user, USER_PARTY | default_flags);
1445 dcc[idx].type = &DCC_TELNET_PW;
1446 if (make_userfile) {
1447 dprintf(idx, "\nYOU ARE THE MASTER/OWNER ON THIS BOT NOW\n");
1448 dprintf(idx, IRC_LIMBO);
1449 putlog(LOG_MISC, "*", DCC_INSTCOMPL, buf);
1450 make_userfile = 0;
1451 write_userfile(-1);
1452 add_note(buf, botnetnick, "Welcome to eggdrop! :)", -1, 0);
1453 }
1454 dprintf(idx, "\nOkay, now choose and enter a password:\n");
1455 dprintf(idx, "(Only the first 15 letters are significant.)\n");
1456 }
1457 }
1458
1459 static void dcc_telnet_pw(int idx, char *buf, int x)
1460 {
1461 char *newpass;
1462 int ok;
1463
1464 strip_telnet(dcc[idx].sock, buf, &x);
1465 buf[16] = 0;
1466 ok = 1;
1467 if (strlen(buf) < 4) {
1468 dprintf(idx, "\nTry to use at least 4 characters in your password.\n");
1469 dprintf(idx, "Choose and enter a password:\n");
1470 return;
1471 }
1472 for (x = 0; x < strlen(buf); x++)
1473 if ((buf[x] <= 32) || (buf[x] == 127))
1474 ok = 0;
1475 if (!ok) {
1476 dprintf(idx, "\nYou can't use weird symbols in your password.\n");
1477 dprintf(idx, "Try another one please:\n");
1478 return;
1479 }
1480 putlog(LOG_MISC, "*", DCC_NEWUSER, dcc[idx].nick, dcc[idx].host,
1481 dcc[idx].port);
1482 if (notify_new[0]) {
1483 char s[121], s1[121], s2[121];
1484
1485 sprintf(s, "Introduced to %s, %s", dcc[idx].nick, dcc[idx].host);
1486 strcpy(s1, notify_new);
1487 splitc(s2, s1, ',');
1488 while (s2[0]) {
1489 rmspace(s2);
1490 add_note(s2, botnetnick, s, -1, 0);
1491 splitc(s2, s1, ',');
1492 }
1493 rmspace(s1);
1494 add_note(s1, botnetnick, s, -1, 0);
1495 }
1496 newpass = newsplit(&buf);
1497 set_user(&USERENTRY_PASS, dcc[idx].user, newpass);
1498 dprintf(idx, "\nRemember that! You'll need it next time you log in.\n");
1499 dprintf(idx, "You now have an account on %s...\n\n\n", botnetnick);
1500 dcc[idx].type = &DCC_CHAT;
1501 dcc[idx].u.chat->channel = -2;
1502 dcc_chatter(idx);
1503 }
1504
1505 static void eof_dcc_telnet_new(int idx)
1506 {
1507 putlog(LOG_MISC, "*", DCC_LOSTNEWUSER, dcc[idx].host, dcc[idx].port);
1508 killsock(dcc[idx].sock);
1509 lostdcc(idx);
1510 }
1511
1512 static void eof_dcc_telnet_pw(int idx)
1513 {
1514 putlog(LOG_MISC, "*", DCC_LOSTNEWUSR2, dcc[idx].nick, dcc[idx].host,
1515 dcc[idx].port);
1516 deluser(dcc[idx].nick);
1517 killsock(dcc[idx].sock);
1518 lostdcc(idx);
1519 }
1520
1521 static void tout_dcc_telnet_new(int idx)
1522 {
1523 dprintf(idx, "Guess you're not there. Bye.\n");
1524 putlog(LOG_MISC, "*", DCC_TIMEOUTUSER, dcc[idx].host,
1525 dcc[idx].port);
1526 killsock(dcc[idx].sock);
1527 lostdcc(idx);
1528 }
1529
1530 static void tout_dcc_telnet_pw(int idx)
1531 {
1532 dprintf(idx, "Guess you're not there. Bye.\n");
1533 putlog(LOG_MISC, "*", DCC_TIMEOUTUSR2, dcc[idx].nick,
1534 dcc[idx].host, dcc[idx].port);
1535 killsock(dcc[idx].sock);
1536 lostdcc(idx);
1537 }
1538
1539 static void display_dcc_telnet_new(int idx, char *buf)
1540 {
1541 sprintf(buf, "new waited %lus", now - dcc[idx].timeval);
1542 }
1543
1544 static void display_dcc_telnet_pw(int idx, char *buf)
1545 {
1546 sprintf(buf, "newp waited %lus", now - dcc[idx].timeval);
1547 }
1548
1549 struct dcc_table DCC_TELNET_NEW =
1550 {
1551 "TELNET_NEW",
1552 0,
1553 eof_dcc_telnet_new,
1554 dcc_telnet_new,
1555 &password_timeout,
1556 tout_dcc_telnet_new,
1557 display_dcc_telnet_new,
1558 expmem_dcc_general,
1559 kill_dcc_general,
1560 out_dcc_general
1561 };
1562
1563 struct dcc_table DCC_TELNET_PW =
1564 {
1565 "TELNET_PW",
1566 0,
1567 eof_dcc_telnet_pw,
1568 dcc_telnet_pw,
1569 &password_timeout,
1570 tout_dcc_telnet_pw,
1571 display_dcc_telnet_pw,
1572 expmem_dcc_general,
1573 kill_dcc_general,
1574 out_dcc_general
1575 };
1576
1577 static int call_tcl_func(char *name, int idx, char *args)
1578 {
1579 char s[11];
1580
1581 sprintf(s, "%d", idx);
1582 Tcl_SetVar(interp, "_n", s, 0);
1583 Tcl_SetVar(interp, "_a", args, 0);
1584 if (Tcl_VarEval(interp, name, " $_n $_a", NULL) == TCL_ERROR) {
1585 putlog(LOG_MISC, "*", DCC_TCLERROR, name, interp->result);
1586 return -1;
1587 }
1588 return (atoi(interp->result));
1589 }
1590
1591 static void dcc_script(int idx, char *buf, int len)
1592 {
1593 void *old = NULL;
1594 long oldsock = dcc[idx].sock;
1595
1596 strip_telnet(dcc[idx].sock, buf, &len);
1597 if (!len)
1598 return;
1599 dcc[idx].timeval = now;
1600 if (call_tcl_func(dcc[idx].u.script->command, dcc[idx].sock, buf)) {
1601 Context;
1602 if ((dcc[idx].sock != oldsock) || (idx>max_dcc))
1603 return; /* drummer: this happen after killdcc */
1604 old = dcc[idx].u.script->u.other;
1605 dcc[idx].type = dcc[idx].u.script->type;
1606 nfree(dcc[idx].u.script);
1607 dcc[idx].u.other = old;
1608 if (dcc[idx].type == &DCC_SOCKET) {
1609 /* kill the whole thing off */
1610 killsock(dcc[idx].sock);
1611 lostdcc(idx);
1612 return;
1613 }
1614 if (dcc[idx].type == &DCC_CHAT) {
1615 if (dcc[idx].u.chat->channel >= 0) {
1616 chanout_but(-1, dcc[idx].u.chat->channel,DCC_JOIN, dcc[idx].nick);
1617 Context;
1618 if (dcc[idx].u.chat->channel < 10000)
1619 botnet_send_join_idx(idx, -1);
1620 check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
1621 geticon(idx), dcc[idx].sock, dcc[idx].host);
1622 }
1623 check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
1624 }
1625 }
1626 }
1627
1628 static void eof_dcc_script(int idx)
1629 {
1630 void *old;
1631 int oldflags;
1632
1633 Context;
1634 /* This will stop a killdcc from working, incase the script tries
1635 * to kill it's controlling socket while handling an EOF <cybah> */
1636 oldflags = dcc[idx].type->flags;
1637 dcc[idx].type->flags &= ~(DCT_VALIDIDX);
1638 /* tell the script they're gone: */
1639 call_tcl_func(dcc[idx].u.script->command, dcc[idx].sock, "");
1640 /* restore the flags */
1641 dcc[idx].type->flags = oldflags;
1642 Context;
1643 old = dcc[idx].u.script->u.other;
1644 dcc[idx].type = dcc[idx].u.script->type;
1645 nfree(dcc[idx].u.script);
1646 dcc[idx].u.other = old;
1647 /* then let it fall thru to the real one */
1648 if (dcc[idx].type && dcc[idx].type->eof)
1649 dcc[idx].type->eof(idx);
1650 else {
1651 putlog(LOG_MISC, "*", DCC_DEADSOCKET, dcc[idx].sock,
1652 dcc[idx].type->name);
1653 killsock(dcc[idx].sock);
1654 lostdcc(idx);
1655 }
1656 }
1657
1658 static void display_dcc_script(int idx, char *buf)
1659 {
1660 sprintf(buf, "scri %s", dcc[idx].u.script->command);
1661 }
1662
1663 static int expmem_dcc_script(void *x)
1664 {
1665 register struct script_info *p = (struct script_info *) x;
1666 int tot = sizeof(struct script_info);
1667
1668 if (p->type && p->u.other)
1669 tot += p->type->expmem(p->u.other);
1670 return tot;
1671 }
1672
1673 static void kill_dcc_script(int idx, void *x)
1674 {
1675 register struct script_info *p = (struct script_info *) x;
1676
1677 if (p->type && p->u.other)
1678 p->type->kill(idx, p->u.other);
1679 nfree(p);
1680 }
1681
1682 static void out_dcc_script(int idx, char *buf, void *x)
1683 {
1684 register struct script_info *p = (struct script_info *) x;
1685
1686 if (p && p->type && p->u.other)
1687 p->type->output(idx, buf, p->u.other);
1688 else
1689 tputs(dcc[idx].sock, buf, strlen(buf));
1690 }
1691
1692 struct dcc_table DCC_SCRIPT =
1693 {
1694 "SCRIPT",
1695 DCT_VALIDIDX,
1696 eof_dcc_script,
1697 dcc_script,
1698 0,
1699 0,
1700 display_dcc_script,
1701 expmem_dcc_script,
1702 kill_dcc_script,
1703 out_dcc_script
1704 };
1705
1706 static void dcc_socket(int idx, char *buf, int len)
1707 {
1708 }
1709
1710 static void eof_dcc_socket(int idx)
1711 {
1712 killsock(dcc[idx].sock);
1713 lostdcc(idx);
1714 }
1715
1716 static void display_dcc_socket(int idx, char *buf)
1717 {
1718 strcpy(buf, "sock (stranded)");
1719 }
1720
1721 struct dcc_table DCC_SOCKET =
1722 {
1723 "SOCKET",
1724 DCT_VALIDIDX,
1725 eof_dcc_socket,
1726 dcc_socket,
1727 0,
1728 0,
1729 display_dcc_socket,
1730 0,
1731 0,
1732 0
1733 };
1734
1735 static void display_dcc_lost(int idx, char *buf)
1736 {
1737 strcpy(buf, "lost");
1738 }
1739
1740 struct dcc_table DCC_LOST =
1741 {
1742 "LOST",
1743 0,
1744 0,
1745 dcc_socket,
1746 0,
1747 0,
1748 display_dcc_lost,
1749 0,
1750 0,
1751 0
1752 };
1753
1754 void dcc_identwait(int idx, char *buf, int len)
1755 {
1756 /* ignore anything now */
1757 Context;
1758 }
1759
1760 void eof_dcc_identwait(int idx)
1761 {
1762 int i;
1763
1764 putlog(LOG_MISC, "*", DCC_LOSTCONN, dcc[idx].host, dcc[idx].port);
1765 for (i = 0; i < dcc_total; i++)
1766 if ((dcc[i].type == &DCC_IDENT) &&
1767 (dcc[i].u.ident_sock == dcc[idx].sock)) {
1768 killsock(dcc[i].sock); /* cleanup ident socket */
1769 dcc[i].u.other = 0;
1770 lostdcc(i);
1771 break;
1772 }
1773 killsock(dcc[idx].sock); /* cleanup waiting socket */
1774 dcc[idx].u.other = 0;
1775 lostdcc(idx);
1776 }
1777
1778 static void display_dcc_identwait(int idx, char *buf)
1779 {
1780 sprintf(buf, "idtw waited %lus", now - dcc[idx].timeval);
1781 }
1782
1783 struct dcc_table DCC_IDENTWAIT =
1784 {
1785 "IDENTWAIT",
1786 0,
1787 eof_dcc_identwait,
1788 dcc_identwait,
1789 0,
1790 0,
1791 display_dcc_identwait,
1792 0,
1793 0,
1794 0
1795 };
1796
1797 void dcc_ident(int idx, char *buf, int len)
1798 {
1799 char response[512], uid[512], buf1[UHOSTLEN];
1800 int i, sock = dcc[idx].sock;
1801
1802 Context;
1803 sscanf(buf, "%*[^:]:%[^:]:%*[^:]:%[^\n]\n", response, uid);
1804 rmspace(response);
1805 if (response[0] != 'U') {
1806 dcc[idx].timeval = now;
1807 return;
1808 }
1809 rmspace(uid);
1810 uid[20] = 0; /* 20 character ident max */
1811 for (i = 0; i < dcc_total; i++)
1812 if ((dcc[i].type == &DCC_IDENTWAIT) &&
1813 (dcc[i].sock == dcc[idx].u.ident_sock)) {
1814 simple_sprintf(buf1, "%s@%s", uid, dcc[idx].host);
1815 dcc_telnet_got_ident(i, buf1);
1816 }
1817 idx = findanyidx(sock);
1818 dcc[idx].u.other = 0;
1819 killsock(dcc[idx].sock);
1820 lostdcc(idx);
1821 }
1822
1823 void eof_dcc_ident(int idx)
1824 {
1825 char buf[UHOSTLEN];
1826 int i, sock = dcc[idx].sock;
1827
1828 for (i = 0; i < dcc_total; i++)
1829 if ((dcc[i].type == &DCC_IDENTWAIT) &&
1830 (dcc[i].sock == dcc[idx].u.ident_sock)) {
1831 putlog(LOG_MISC, "*", DCC_EOFIDENT);
1832 simple_sprintf(buf, "telnet@%s", dcc[idx].host);
1833 dcc_telnet_got_ident(i, buf);
1834 }
1835 idx = findanyidx(sock); /* sanity */
1836 if (idx >= 0) {
1837 killsock(dcc[idx].sock);
1838 dcc[idx].u.other = 0;
1839 lostdcc(idx);
1840 }
1841 }
1842
1843 static void display_dcc_ident(int idx, char *buf)
1844 {
1845 sprintf(buf, "idnt (sock %d)", dcc[idx].u.ident_sock);
1846 }
1847
1848 struct dcc_table DCC_IDENT =
1849 {
1850 "IDENT",
1851 0,
1852 eof_dcc_ident,
1853 dcc_ident,
1854 &identtimeout,
1855 eof_dcc_ident,
1856 display_dcc_ident,
1857 0,
1858 0,
1859 0
1860 };
1861
1862 void dcc_telnet_got_ident(int i, char *host)
1863 {
1864 int idx;
1865 char x[1024];
1866
1867 for (idx = 0; idx < dcc_total; idx++)
1868 if ((dcc[idx].type == &DCC_TELNET) &&
1869 (dcc[idx].sock == dcc[i].u.ident_sock))
1870 break;
1871 dcc[i].u.other = 0;
1872 if (dcc_total == idx) {
1873 putlog(LOG_MISC, "*", DCC_LOSTIDENT);
1874 killsock(dcc[i].sock);
1875 lostdcc(i);
1876 return;
1877 }
1878 strncpy(dcc[i].host, host, UHOSTMAX);
1879 dcc[i].host[UHOSTMAX] = 0;
1880 simple_sprintf(x, "telnet!%s", dcc[i].host);
1881 if (protect_telnet && !make_userfile) {
1882 struct userrec *u;
1883 int ok = 1;
1884
1885 Context;
1886 u = get_user_by_host(x);
1887 /* not a user or +p & require p OR +o */
1888 if (!u)
1889 ok = 0;
1890 else if (require_p && !(u->flags & USER_PARTY))
1891 ok = 0;
1892 else if (!require_p && !(u->flags & USER_OP))
1893 ok = 0;
1894 if (!ok && u && (u->flags & USER_BOT))
1895 ok = 1;
1896 if (!ok) {
1897 putlog(LOG_MISC, "*", DCC_NOACCESS, dcc[i].host);
1898 killsock(dcc[i].sock);
1899 lostdcc(i);
1900 return;
1901 }
1902 }
1903 Context;
1904 if (match_ignore(x)) {
1905 killsock(dcc[i].sock);
1906 lostdcc(i);
1907 return;
1908 }
1909 /* script? */
1910 if (!strcmp(dcc[idx].nick, "(script)")) {
1911 dcc[i].type = &DCC_SOCKET;
1912 dcc[i].u.other = NULL;
1913 strcpy(dcc[i].nick, "*");
1914 check_tcl_listen(dcc[idx].host, dcc[i].sock);
1915 return;
1916 }
1917 dcc[i].type = &DCC_TELNET_ID;
1918 dcc[i].u.chat = get_data_ptr(sizeof(struct chat_info));
1919 bzero(dcc[i].u.chat, sizeof(struct chat_info));
1920
1921 /* copy acceptable-nick/host mask */
1922 dcc[i].status = STAT_TELNET | STAT_ECHO;
1923 if (!strcmp(dcc[idx].nick, "(bots)"))
1924 dcc[i].status |= STAT_BOTONLY;
1925 if (!strcmp(dcc[idx].nick, "(users)"))
1926 dcc[i].status |= STAT_USRONLY;
1927 /* copy acceptable-nick/host mask */
1928 strncpy(dcc[i].nick, dcc[idx].host, HANDLEN);
1929 dcc[i].nick[HANDLEN] = 0;
1930 dcc[i].timeval = now;
1931 strcpy(dcc[i].u.chat->con_chan, chanset ? chanset->name : "*");
1932 /* Displays a customizable banner. [seC] */
1933 if (use_telnet_banner)
1934 show_banner(i);
1935 /* This is so we dont tell someone doing a portscan anything
1936 * about ourselves. <cybah> */
1937 if (stealth_telnets)
1938 sub_lang(i, MISC_BANNER_STEALTH);
1939 else {
1940 dprintf(i, "\r\n\r\n");
1941 sub_lang(i, MISC_BANNER);
1942 }
1943 if (allow_new_telnets)
1944 dprintf(i, "(If you are new, enter 'NEW' here.)\r\n");
1945 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23