/[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.1 - (hide annotations) (download) (as text)
Mon Jul 26 21:11:06 2010 UTC (9 years, 1 month ago) by simple
Branch: MAIN
Branch point for: eggheads
File MIME type: text/x-chdr
Initial revision

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