/[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.4 - (hide annotations) (download) (as text)
Tue Oct 19 12:13:33 2010 UTC (8 years, 8 months ago) by pseudo
Branch: MAIN
Changes since 1.3: +133 -19 lines
File MIME type: text/x-chdr
Added full SSL support including Tcl commands.
Added support for certificate authentication.
Added support for botnet and partyline encryption using ssl.
Documented the new features and commands.
Fixed add_server() problems with IPv6 addresses in the server list.

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