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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23