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

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

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


Revision 1.6 - (hide annotations) (download) (as text)
Sun Oct 31 14:40:38 2010 UTC (8 years, 11 months ago) by pseudo
Branch: MAIN
Branch point for: gettext
Changes since 1.5: +4 -2 lines
File MIME type: text/x-chdr
Fixed dcc_telnet_pass() to not use a constant string with fingerprint authentication, because strip_telnet() may attempt to write to it later.

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