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