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

Contents of /eggdrop1.9/src/dcc.c

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


Revision 1.7 - (show annotations) (download) (as text)
Tue Oct 26 21:38:37 1999 UTC (20 years, 1 month ago) by fabian
Branch: MAIN
Changes since 1.6: +16 -22 lines
File MIME type: text/x-chdr
resync 940380771-940924890

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23