/[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.10 - (show annotations) (download) (as text)
Wed Sep 29 00:49:21 1999 UTC (19 years, 11 months ago) by guppy
Branch: MAIN
Changes since 1.9: +13 -0 lines
File MIME type: text/x-chdr
more patches

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23