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

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

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


Revision 1.4 - (hide annotations) (download) (as text)
Fri Nov 26 13:20:29 2010 UTC (8 years, 10 months ago) by pseudo
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +2 -2 lines
File MIME type: text/x-chdr
Added a little hack to send starttls before password exchange during the initial handshake.

1 simple 1.1 /*
2     * dccutil.c -- handles:
3     * lots of little functions to send formatted text to
4     * varying types of connections
5     * '.who', '.whom', and '.dccstat' code
6     * memory management for dcc structures
7     * timeout checking for dcc connections
8     *
9 pseudo 1.4 * $Id: dccutil.c,v 1.3 2010/10/19 12:13:33 pseudo Exp $
10 simple 1.1 */
11     /*
12     * Copyright (C) 1997 Robey Pointer
13     * Copyright (C) 1999 - 2010 Eggheads Development Team
14     *
15     * This program is free software; you can redistribute it and/or
16     * modify it under the terms of the GNU General Public License
17     * as published by the Free Software Foundation; either version 2
18     * of the License, or (at your option) any later version.
19     *
20     * This program is distributed in the hope that it will be useful,
21     * but WITHOUT ANY WARRANTY; without even the implied warranty of
22     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23     * GNU General Public License for more details.
24     *
25     * You should have received a copy of the GNU General Public License
26     * along with this program; if not, write to the Free Software
27     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28     */
29    
30     #include <sys/stat.h>
31     #include "main.h"
32     #include <errno.h>
33     #include "chan.h"
34     #include "modules.h"
35     #include "tandem.h"
36    
37     extern struct dcc_t *dcc;
38     extern int dcc_total, dcc_flood_thr, backgrd, copy_to_tmp, max_socks;
39     extern char botnetnick[], version[];
40     extern time_t now;
41     extern sock_list *socklist;
42    
43     char motdfile[121] = "text/motd"; /* File where the motd is stored */
44     int connect_timeout = 15; /* How long to wait before a telnet
45     * connection times out */
46    
47     int reserved_port_min = 0;
48     int reserved_port_max = 0;
49    
50     int max_dcc = 0; /* indicates the current dcc limit in the main thread */
51    
52     /* This function is called to enlarge the static sockettable in a thread.
53     * It keeps the mainthread dcc table enlarging with the main thread sockettable
54     * If this fails because the upper limit max_socks is reached, -1 is returned.
55     * If this was called from the main thread, it updates the socklist variable
56     *
57     * increase_socks_max() can be called by Tcl threads
58     */
59     int increase_socks_max()
60     {
61     struct threaddata *td = threaddata();
62     int osock = td->MAXSOCKS;
63    
64     if (max_socks < 1)
65     max_socks = 1;
66    
67     if (td->MAXSOCKS == max_socks) {
68     putlog(LOG_MISC, "*", "Maximum socket limit reached. Consider raising max-socks.");
69     return -1;
70     }
71    
72     td->MAXSOCKS += 10;
73     if (td->MAXSOCKS > max_socks)
74     td->MAXSOCKS = max_socks;
75    
76     if (td->socklist)
77     td->socklist = nrealloc(td->socklist, sizeof(sock_list) * td->MAXSOCKS);
78     else
79     td->socklist = nmalloc(sizeof(sock_list) * td->MAXSOCKS);
80     for (; osock < td->MAXSOCKS; osock++)
81     td->socklist[osock].flags = SOCK_UNUSED;
82    
83     if (td->mainthread) {
84     max_dcc = td->MAXSOCKS - 10;
85     if (max_dcc < 1)
86     max_dcc = 1;
87     if (dcc)
88     dcc = nrealloc(dcc, sizeof(struct dcc_t) * max_dcc);
89     else
90     dcc = nmalloc(sizeof(struct dcc_t) * max_dcc);
91     socklist = td->socklist;
92     }
93    
94     return 0;
95     }
96    
97     int expmem_dccutil()
98     {
99     int tot, i;
100    
101     tot = sizeof(struct dcc_t) * max_dcc;
102     tot += sizeof(sock_list) * threaddata()->MAXSOCKS;
103    
104     for (i = 0; i < dcc_total; i++) {
105     if (dcc[i].type && dcc[i].type->expmem)
106     tot += dcc[i].type->expmem(dcc[i].u.other);
107     }
108     return tot;
109     }
110    
111     int findidx(int z)
112     {
113     int j;
114    
115     for (j = 0; j < dcc_total; j++)
116     if ((dcc[j].sock == z) && (dcc[j].type->flags & DCT_VALIDIDX))
117     return j;
118     return -1;
119     }
120    
121     int findanyidx(register int z)
122     {
123     register int j;
124    
125     for (j = 0; j < dcc_total; j++)
126     if (dcc[j].sock == z)
127     return j;
128     return -1;
129     }
130    
131     /* Replace \n with \r\n */
132     char *add_cr(char *buf)
133     {
134     static char WBUF[1024];
135     char *p, *q;
136    
137     for (p = buf, q = WBUF; *p; p++, q++) {
138     if (*p == '\n')
139     *q++ = '\r';
140     *q = *p;
141     }
142     *q = *p;
143     return WBUF;
144     }
145    
146     extern void (*qserver) (int, char *, int);
147    
148     void dprintf EGG_VARARGS_DEF(int, arg1)
149     {
150 pseudo 1.4 char buf[1024];
151 simple 1.1 char *format;
152     int idx, len;
153     va_list va;
154    
155     idx = EGG_VARARGS_START(int, arg1, va);
156     format = va_arg(va, char *);
157    
158     egg_vsnprintf(buf, 1023, format, va);
159     va_end(va);
160     /* We can not use the return value vsnprintf() to determine where
161     * to null terminate. The C99 standard specifies that vsnprintf()
162     * shall return the number of bytes that would be written if the
163     * buffer had been large enough, rather then -1.
164     */
165     /* We actually can, since if it's < 0 or >= sizeof(buf), we know it wrote
166     * sizeof(buf) bytes. But we're not doing that anyway.
167     */
168     buf[sizeof(buf) - 1] = 0;
169     len = strlen(buf);
170    
171     if (idx < 0) {
172     tputs(-idx, buf, len);
173     } else if (idx > 0x7FF0) {
174     switch (idx) {
175     case DP_LOG:
176     putlog(LOG_MISC, "*", "%s", buf);
177     break;
178     case DP_STDOUT:
179     tputs(STDOUT, buf, len);
180     break;
181     case DP_STDERR:
182     tputs(STDERR, buf, len);
183     break;
184     case DP_SERVER:
185     case DP_HELP:
186     case DP_MODE:
187     case DP_MODE_NEXT:
188     case DP_SERVER_NEXT:
189     case DP_HELP_NEXT:
190     qserver(idx, buf, len);
191     break;
192     }
193     return;
194     } else {
195     if (len > 500) { /* Truncate to fit */
196     buf[500] = 0;
197     strcat(buf, "\n");
198     len = 501;
199     }
200     if (dcc[idx].type && ((long) (dcc[idx].type->output) == 1)) {
201     char *p = add_cr(buf);
202    
203     tputs(dcc[idx].sock, p, strlen(p));
204     } else if (dcc[idx].type && dcc[idx].type->output)
205     dcc[idx].type->output(idx, buf, dcc[idx].u.other);
206     else
207     tputs(dcc[idx].sock, buf, len);
208     }
209     }
210    
211     void chatout EGG_VARARGS_DEF(char *, arg1)
212     {
213     int i, len;
214     char *format;
215     char s[601];
216     va_list va;
217    
218     format = EGG_VARARGS_START(char *, arg1, va);
219    
220     egg_vsnprintf(s, 511, format, va);
221     va_end(va);
222     len = strlen(s);
223     if (len > 511)
224     len = 511;
225     s[len + 1] = 0;
226    
227     for (i = 0; i < dcc_total; i++)
228     if (dcc[i].type == &DCC_CHAT)
229     if (dcc[i].u.chat->channel >= 0)
230     dprintf(i, "%s", s);
231    
232     }
233    
234     /* Print to all on this channel but one.
235     */
236     void chanout_but EGG_VARARGS_DEF(int, arg1)
237     {
238     int i, x, chan, len;
239     char *format;
240     char s[601];
241     va_list va;
242    
243     x = EGG_VARARGS_START(int, arg1, va);
244     chan = va_arg(va, int);
245     format = va_arg(va, char *);
246    
247     egg_vsnprintf(s, 511, format, va);
248     va_end(va);
249     len = strlen(s);
250     if (len > 511)
251     len = 511;
252     s[len + 1] = 0;
253    
254     for (i = 0; i < dcc_total; i++)
255     if ((dcc[i].type == &DCC_CHAT) && (i != x))
256     if (dcc[i].u.chat->channel == chan)
257     dprintf(i, "%s", s);
258    
259     }
260    
261     void dcc_chatter(int idx)
262     {
263     int i, j;
264     struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
265    
266     get_user_flagrec(dcc[idx].user, &fr, NULL);
267     show_motd(idx);
268     i = dcc[idx].u.chat->channel;
269     dcc[idx].u.chat->channel = 234567;
270     j = dcc[idx].sock;
271     strcpy(dcc[idx].u.chat->con_chan, "***");
272     check_tcl_chon(dcc[idx].nick, dcc[idx].sock);
273     /* Still there? */
274     if ((idx >= dcc_total) || (dcc[idx].sock != j))
275     return; /* Nope */
276     /* Tcl script may have taken control */
277     if (dcc[idx].type == &DCC_CHAT) {
278     if (!strcmp(dcc[idx].u.chat->con_chan, "***"))
279     strcpy(dcc[idx].u.chat->con_chan, "*");
280     if (dcc[idx].u.chat->channel == 234567) {
281     /* If the chat channel has already been altered it's *highly*
282     * probably join/part messages have been broadcast everywhere,
283     * so dont bother sending them
284     */
285     if (i == -2)
286     i = 0;
287     dcc[idx].u.chat->channel = i;
288     if ((dcc[idx].u.chat->channel >= 0) &&
289     (dcc[idx].u.chat->channel < GLOBAL_CHANS))
290     botnet_send_join_idx(idx, -1);
291     check_tcl_chjn(botnetnick, dcc[idx].nick, dcc[idx].u.chat->channel,
292     geticon(idx), dcc[idx].sock, dcc[idx].host);
293     }
294     /* But *do* bother with sending it locally */
295     if (!dcc[idx].u.chat->channel) {
296     chanout_but(-1, 0, "*** %s joined the party line.\n", dcc[idx].nick);
297     } else if (dcc[idx].u.chat->channel > 0) {
298     chanout_but(-1, dcc[idx].u.chat->channel,
299     "*** %s joined the channel.\n", dcc[idx].nick);
300     }
301     }
302     }
303    
304     /* Closes an open FD for transfer sockets. */
305     void killtransfer(int n)
306     {
307     int i, ok = 1;
308    
309     if (dcc[n].type->flags & DCT_FILETRAN) {
310     if (dcc[n].u.xfer->f) {
311     fclose(dcc[n].u.xfer->f);
312     dcc[n].u.xfer->f = NULL;
313     }
314     if (dcc[n].u.xfer->filename && copy_to_tmp) {
315     for (i = 0; i < dcc_total; i++) {
316     if ((i != n) && (dcc[i].type->flags & DCT_FILETRAN) &&
317     (dcc[i].u.xfer->filename) &&
318     (!strcmp(dcc[i].u.xfer->filename, dcc[n].u.xfer->filename))) {
319     ok = 0;
320     break;
321     }
322     }
323     if (ok)
324     unlink(dcc[n].u.xfer->filename);
325     }
326     }
327     }
328    
329     /* Mark an entry as lost and deconstruct it's contents. It will be securely
330     * removed from the dcc list in the main loop.
331     */
332     void lostdcc(int n)
333     {
334     /* Make sure it's a valid dcc index. */
335     if (n < 0 || n >= max_dcc)
336     return;
337    
338     if (dcc[n].type && dcc[n].type->kill)
339     dcc[n].type->kill(n, dcc[n].u.other);
340     else if (dcc[n].u.other)
341     nfree(dcc[n].u.other);
342     egg_bzero(&dcc[n], sizeof(struct dcc_t));
343    
344     dcc[n].sock = -1;
345     dcc[n].type = &DCC_LOST;
346     }
347    
348     /* Remove entry from dcc list. Think twice before using this function,
349     * because it invalidates any variables that point to a specific dcc
350     * entry!
351     *
352     * Note: The entry will be deconstructed if it was not deconstructed
353     * already. This case should normally not occur.
354     */
355     void removedcc(int n)
356     {
357     if (dcc[n].type && dcc[n].type->kill)
358     dcc[n].type->kill(n, dcc[n].u.other);
359     else if (dcc[n].u.other)
360     nfree(dcc[n].u.other);
361     dcc_total--;
362     if (n < dcc_total)
363     egg_memcpy(&dcc[n], &dcc[dcc_total], sizeof(struct dcc_t));
364     else
365     egg_bzero(&dcc[n], sizeof(struct dcc_t)); /* drummer */
366     }
367    
368     /* Clean up sockets that were just left for dead.
369     */
370     void dcc_remove_lost(void)
371     {
372     int i;
373    
374     for (i = 0; i < dcc_total; i++) {
375     if (dcc[i].type == &DCC_LOST) {
376     dcc[i].type = NULL;
377     dcc[i].sock = -1;
378     removedcc(i);
379     i--;
380     }
381     }
382     }
383    
384     /* Show list of current dcc's to a dcc-chatter
385     * positive value: idx given -- negative value: sock given
386     */
387     void tell_dcc(int zidx)
388     {
389 pseudo 1.2 int i, j, nicklen = 0;
390 simple 1.1 char other[160];
391     char format[81];
392    
393     /* calculate max nicklen */
394     for (i = 0; i < dcc_total; i++) {
395     if (strlen(dcc[i].nick) > nicklen)
396     nicklen = strlen(dcc[i].nick);
397     }
398     if (nicklen < 9)
399     nicklen = 9;
400    
401 pseudo 1.2 j = 60 - nicklen;
402     if (j < 15)
403     j = 15;
404     if (j > 40)
405     j = 40;
406    
407 pseudo 1.3 egg_snprintf(format, sizeof format, "%%-3s %%-%u.%us %%-6s %%-%u.%us %%s\n",
408 pseudo 1.2 j, j, nicklen, nicklen);
409 pseudo 1.3 dprintf(zidx, format, "IDX", "ADDR", "+ PORT", "NICK", "TYPE INFO");
410 pseudo 1.2 dprintf(zidx, format, "---",
411 pseudo 1.3 "------------------------------------------------------", "------",
412 pseudo 1.2 "--------------------------------", "----- ---------");
413 pseudo 1.3 egg_snprintf(format, sizeof format, "%%-3d %%-%u.%us %%c%%5d %%-%u.%us %%s\n",
414 pseudo 1.2 j, j, nicklen, nicklen);
415 simple 1.1
416     /* Show server */
417     for (i = 0; i < dcc_total; i++) {
418     if (dcc[i].type && dcc[i].type->display)
419     dcc[i].type->display(i, other);
420     else {
421     sprintf(other, "?:%lX !! ERROR !!", (long) dcc[i].type);
422     break;
423     }
424 pseudo 1.3 dprintf(zidx, format, dcc[i].sock, iptostr(&dcc[i].sockname.addr.sa),
425     #ifdef TLS
426     dcc[i].ssl ? '+' : ' ', dcc[i].port, dcc[i].nick, other);
427     #else
428     ' ', dcc[i].port, dcc[i].nick, other);
429     #endif
430 simple 1.1 }
431     }
432    
433     /* Mark someone on dcc chat as no longer away
434     */
435     void not_away(int idx)
436     {
437     if (dcc[idx].u.chat->away == NULL) {
438     dprintf(idx, "You weren't away!\n");
439     return;
440     }
441     if (dcc[idx].u.chat->channel >= 0) {
442     chanout_but(-1, dcc[idx].u.chat->channel,
443     "*** %s is no longer away.\n", dcc[idx].nick);
444     if (dcc[idx].u.chat->channel < GLOBAL_CHANS) {
445     botnet_send_away(-1, botnetnick, dcc[idx].sock, NULL, idx);
446     }
447     }
448     dprintf(idx, "You're not away any more.\n");
449     nfree(dcc[idx].u.chat->away);
450     dcc[idx].u.chat->away = NULL;
451     check_tcl_away(botnetnick, dcc[idx].sock, NULL);
452     }
453    
454     void set_away(int idx, char *s)
455     {
456     if (s == NULL) {
457     not_away(idx);
458     return;
459     }
460     if (!s[0]) {
461     not_away(idx);
462     return;
463     }
464     if (dcc[idx].u.chat->away != NULL)
465     nfree(dcc[idx].u.chat->away);
466     dcc[idx].u.chat->away = nmalloc(strlen(s) + 1);
467     strcpy(dcc[idx].u.chat->away, s);
468     if (dcc[idx].u.chat->channel >= 0) {
469     chanout_but(-1, dcc[idx].u.chat->channel,
470     "*** %s is now away: %s\n", dcc[idx].nick, s);
471     if (dcc[idx].u.chat->channel < GLOBAL_CHANS) {
472     botnet_send_away(-1, botnetnick, dcc[idx].sock, s, idx);
473     }
474     }
475     dprintf(idx, "You are now away.\n");
476     check_tcl_away(botnetnick, dcc[idx].sock, s);
477     }
478    
479     /* This helps the memory debugging
480     */
481     void *_get_data_ptr(int size, char *file, int line)
482     {
483     char *p;
484     #ifdef DEBUG_MEM
485     char x[1024];
486    
487     p = strrchr(file, '/');
488     egg_snprintf(x, sizeof x, "dccutil.c:%s", p ? p + 1 : file);
489     p = n_malloc(size, x, line);
490     #else
491     p = nmalloc(size);
492     #endif
493     egg_bzero(p, size);
494     return p;
495     }
496    
497     /* Make a password, 10-15 random letters and digits
498     */
499     void makepass(char *s)
500     {
501     int i;
502    
503     i = 10 + randint(6);
504     make_rand_str(s, i);
505     }
506    
507     void flush_lines(int idx, struct chat_info *ci)
508     {
509     int c = ci->line_count;
510     struct msgq *p = ci->buffer, *o;
511    
512     while (p && c < (ci->max_line)) {
513     ci->current_lines--;
514     tputs(dcc[idx].sock, p->msg, p->len);
515     nfree(p->msg);
516     o = p->next;
517     nfree(p);
518     p = o;
519     c++;
520     }
521     if (p != NULL) {
522     if (dcc[idx].status & STAT_TELNET)
523     tputs(dcc[idx].sock, "[More]: ", 8);
524     else
525     tputs(dcc[idx].sock, "[More]\n", 7);
526     }
527     ci->buffer = p;
528     ci->line_count = 0;
529     }
530    
531     int new_dcc(struct dcc_table *type, int xtra_size)
532     {
533     int i = dcc_total;
534    
535     if (dcc_total == max_dcc && increase_socks_max())
536     return -1;
537     dcc_total++;
538     egg_bzero((char *) &dcc[i], sizeof(struct dcc_t));
539    
540     dcc[i].type = type;
541     if (xtra_size) {
542     dcc[i].u.other = nmalloc(xtra_size);
543     egg_bzero(dcc[i].u.other, xtra_size);
544     }
545     return i;
546     }
547    
548     /* Changes the given dcc entry to another type.
549     */
550     void changeover_dcc(int i, struct dcc_table *type, int xtra_size)
551     {
552     /* Free old structure. */
553     if (dcc[i].type && dcc[i].type->kill)
554     dcc[i].type->kill(i, dcc[i].u.other);
555     else if (dcc[i].u.other) {
556     nfree(dcc[i].u.other);
557     dcc[i].u.other = NULL;
558     }
559    
560     dcc[i].type = type;
561     if (xtra_size) {
562     dcc[i].u.other = nmalloc(xtra_size);
563     egg_bzero(dcc[i].u.other, xtra_size);
564     }
565     }
566    
567     int detect_dcc_flood(time_t *timer, struct chat_info *chat, int idx)
568     {
569     time_t t;
570    
571     if (!dcc_flood_thr)
572     return 0;
573     t = now;
574     if (*timer != t) {
575     *timer = t;
576     chat->msgs_per_sec = 0;
577     } else {
578     chat->msgs_per_sec++;
579     if (chat->msgs_per_sec > dcc_flood_thr) {
580     /* FLOOD */
581     dprintf(idx, "*** FLOOD: %s.\n", IRC_GOODBYE);
582     /* Evil assumption here that flags&DCT_CHAT implies chat type */
583     if ((dcc[idx].type->flags & DCT_CHAT) && chat && (chat->channel >= 0)) {
584     char x[1024];
585    
586     egg_snprintf(x, sizeof x, DCC_FLOODBOOT, dcc[idx].nick);
587     chanout_but(idx, chat->channel, "*** %s", x);
588     if (chat->channel < GLOBAL_CHANS)
589     botnet_send_part_idx(idx, x);
590     }
591     check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
592     if ((dcc[idx].sock != STDOUT) || backgrd) {
593     killsock(dcc[idx].sock);
594     lostdcc(idx);
595     } else {
596     dprintf(DP_STDOUT, "\n### SIMULATION RESET ###\n\n");
597     dcc_chatter(idx);
598     }
599     return 1; /* <- flood */
600     }
601     }
602     return 0;
603     }
604    
605     /* Handle someone being booted from dcc chat.
606     */
607     void do_boot(int idx, char *by, char *reason)
608     {
609     int files = (dcc[idx].type != &DCC_CHAT);
610    
611     dprintf(idx, DCC_BOOTED1);
612     dprintf(idx, DCC_BOOTED2, files ? "file section" : "bot",
613     by, reason[0] ? ": " : ".", reason);
614     /* If it's a partyliner (chatterer :) */
615     /* Horrible assumption that DCT_CHAT using structure uses same format
616     * as DCC_CHAT */
617     if ((dcc[idx].type->flags & DCT_CHAT) && (dcc[idx].u.chat->channel >= 0)) {
618     char x[1024];
619    
620     egg_snprintf(x, sizeof x, DCC_BOOTED3, by, dcc[idx].nick,
621     reason[0] ? ": " : "", reason);
622     chanout_but(idx, dcc[idx].u.chat->channel, "*** %s.\n", x);
623     if (dcc[idx].u.chat->channel < GLOBAL_CHANS)
624     botnet_send_part_idx(idx, x);
625     }
626     check_tcl_chof(dcc[idx].nick, dcc[idx].sock);
627     if ((dcc[idx].sock != STDOUT) || backgrd) {
628     killsock(dcc[idx].sock);
629     lostdcc(idx);
630     /* Entry must remain in the table so it can be logged by the caller */
631     } else {
632     dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n");
633     dcc_chatter(idx);
634     }
635     return;
636     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23