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