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

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

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


Revision 1.3 - (show annotations) (download) (as text)
Tue Aug 31 18:21:47 2010 UTC (8 years, 10 months ago) by pseudo
Branch: MAIN
Changes since 1.2: +2 -2 lines
File MIME type: text/x-chdr
Made dcc_telnet_new() allow non-latin characters in new handles like other handle validation functions.

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23