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

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

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


Revision 1.3 - (hide annotations) (download) (as text)
Sun Oct 10 21:24:43 2010 UTC (8 years, 9 months ago) by pseudo
Branch: MAIN
Changes since 1.2: +2 -1 lines
File MIME type: text/x-chdr
Removed the unrecognized options warning when configuring modules.
Modified -v output and .status display configure options.

1 simple 1.1 /*
2     * chanprog.c -- handles:
3     * rmspace()
4     * maintaining the server list
5     * revenge punishment
6     * timers, utimers
7     * telling the current programmed settings
8     * initializing a lot of stuff and loading the tcl scripts
9     *
10 pseudo 1.3 * $Id: chanprog.c,v 1.2 2010/10/10 18:22:47 pseudo Exp $
11 simple 1.1 */
12     /*
13     * Copyright (C) 1997 Robey Pointer
14     * Copyright (C) 1999 - 2010 Eggheads Development Team
15     *
16     * This program is free software; you can redistribute it and/or
17     * modify it under the terms of the GNU General Public License
18     * as published by the Free Software Foundation; either version 2
19     * of the License, or (at your option) any later version.
20     *
21     * This program is distributed in the hope that it will be useful,
22     * but WITHOUT ANY WARRANTY; without even the implied warranty of
23     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24     * GNU General Public License for more details.
25     *
26     * You should have received a copy of the GNU General Public License
27     * along with this program; if not, write to the Free Software
28     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29     */
30    
31     #include "main.h"
32    
33     #ifdef HAVE_GETRUSAGE
34     # include <sys/resource.h>
35     # ifdef HAVE_SYS_RUSAGE_H
36     # include <sys/rusage.h>
37     # endif
38     #endif
39    
40     #ifdef HAVE_UNAME
41     # include <sys/utsname.h>
42     #endif
43    
44     #include "modules.h"
45    
46     extern struct userrec *userlist;
47     extern log_t *logs;
48     extern Tcl_Interp *interp;
49     extern char ver[], botnetnick[], firewall[], motdfile[], userfile[], helpdir[],
50     tempdir[], moddir[], notify_new[], owner[], configfile[];
51     extern time_t now, online_since;
52     extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport,
53     default_flags, max_logs, conmask, protect_readonly, make_userfile,
54     noshare, ignore_time, max_socks;
55    
56     tcl_timer_t *timer = NULL; /* Minutely timer */
57     tcl_timer_t *utimer = NULL; /* Secondly timer */
58     unsigned long timer_id = 1; /* Next timer of any sort will
59     * have this number */
60     struct chanset_t *chanset = NULL; /* Channel list */
61     char admin[121] = ""; /* Admin info */
62     char origbotname[NICKLEN + 1];
63     char botname[NICKLEN + 1]; /* Primary botname */
64    
65    
66     /* Remove leading and trailing whitespaces.
67     */
68     void rmspace(char *s)
69     {
70     register char *p = NULL, *q = NULL;
71    
72     if (!s || !*s)
73     return;
74    
75     /* Remove trailing whitespaces. */
76     for (q = s + strlen(s) - 1; q >= s && egg_isspace(*q); q--);
77     *(q + 1) = 0;
78    
79     /* Remove leading whitespaces. */
80     for (p = s; egg_isspace(*p); p++);
81    
82     if (p != s)
83     memmove(s, p, q - p + 2);
84     }
85    
86    
87     /* Returns memberfields if the nick is in the member list.
88     */
89     memberlist *ismember(struct chanset_t *chan, char *nick)
90     {
91     register memberlist *x;
92    
93     for (x = chan->channel.member; x && x->nick[0]; x = x->next)
94     if (!rfc_casecmp(x->nick, nick))
95     return x;
96     return NULL;
97     }
98    
99     /* Find a chanset by channel name as the server knows it (ie !ABCDEchannel)
100     */
101     struct chanset_t *findchan(const char *name)
102     {
103     register struct chanset_t *chan;
104    
105     for (chan = chanset; chan; chan = chan->next)
106     if (!rfc_casecmp(chan->name, name))
107     return chan;
108     return NULL;
109     }
110    
111     /* Find a chanset by display name (ie !channel)
112     */
113     struct chanset_t *findchan_by_dname(const char *name)
114     {
115     register struct chanset_t *chan;
116    
117     for (chan = chanset; chan; chan = chan->next)
118     if (!rfc_casecmp(chan->dname, name))
119     return chan;
120     return NULL;
121     }
122    
123    
124     /*
125     * "caching" functions
126     */
127    
128     /* Shortcut for get_user_by_host -- might have user record in one
129     * of the channel caches.
130     */
131     struct userrec *check_chanlist(const char *host)
132     {
133     char *nick, *uhost, buf[UHOSTLEN];
134     register memberlist *m;
135     register struct chanset_t *chan;
136    
137     strncpyz(buf, host, sizeof buf);
138     uhost = buf;
139     nick = splitnick(&uhost);
140     for (chan = chanset; chan; chan = chan->next)
141     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
142     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
143     return m->user;
144     return NULL;
145     }
146    
147     /* Shortcut for get_user_by_handle -- might have user record in channels
148     */
149     struct userrec *check_chanlist_hand(const char *hand)
150     {
151     register struct chanset_t *chan;
152     register memberlist *m;
153    
154     for (chan = chanset; chan; chan = chan->next)
155     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
156     if (m->user && !egg_strcasecmp(m->user->handle, hand))
157     return m->user;
158     return NULL;
159     }
160    
161     /* Clear the user pointers in the chanlists.
162     *
163     * Necessary when a hostmask is added/removed, a user is added or a new
164     * userfile is loaded.
165     */
166     void clear_chanlist(void)
167     {
168     register memberlist *m;
169     register struct chanset_t *chan;
170    
171     for (chan = chanset; chan; chan = chan->next)
172     for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
173     m->user = NULL;
174     m->tried_getuser = 0;
175     }
176     }
177    
178     /* Clear the user pointer of a specific nick in the chanlists.
179     *
180     * Necessary when a hostmask is added/removed, a nick changes, etc.
181     * Does not completely invalidate the channel cache like clear_chanlist().
182     */
183     void clear_chanlist_member(const char *nick)
184     {
185     register memberlist *m;
186     register struct chanset_t *chan;
187    
188     for (chan = chanset; chan; chan = chan->next)
189     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
190     if (!rfc_casecmp(m->nick, nick)) {
191     m->user = NULL;
192     m->tried_getuser = 0;
193     break;
194     }
195     }
196    
197     /* If this user@host is in a channel, set it (it was null)
198     */
199     void set_chanlist(const char *host, struct userrec *rec)
200     {
201     char *nick, *uhost, buf[UHOSTLEN];
202     register memberlist *m;
203     register struct chanset_t *chan;
204    
205     strncpyz(buf, host, sizeof buf);
206     uhost = buf;
207     nick = splitnick(&uhost);
208     for (chan = chanset; chan; chan = chan->next)
209     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
210     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
211     m->user = rec;
212     }
213    
214     /* Calculate the memory we should be using
215     */
216     int expmem_chanprog()
217     {
218     register int tot = 0;
219     register tcl_timer_t *t;
220    
221     for (t = timer; t; t = t->next)
222     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
223     for (t = utimer; t; t = t->next)
224     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
225     return tot;
226     }
227    
228 pseudo 1.2 float getcputime()
229     {
230     #ifdef HAVE_GETRUSAGE
231     float stime, utime;
232     struct rusage ru;
233    
234     getrusage(RUSAGE_SELF, &ru);
235     utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 1000000.00);
236     stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 1000000.00);
237     return (utime + stime);
238     #else
239     # ifdef HAVE_CLOCK
240     return (clock() / (CLOCKS_PER_SEC * 1.00));
241     # else
242     return -1.00;
243     # endif
244     #endif
245     }
246    
247 simple 1.1 /* Dump uptime info out to dcc (guppy 9Jan99)
248     */
249     void tell_verbose_uptime(int idx)
250     {
251     char s[256], s1[121];
252     time_t now2, hr, min;
253    
254     now2 = now - online_since;
255     s[0] = 0;
256     if (now2 > 86400) {
257     /* days */
258     sprintf(s, "%d day", (int) (now2 / 86400));
259     if ((int) (now2 / 86400) >= 2)
260     strcat(s, "s");
261     strcat(s, ", ");
262     now2 -= (((int) (now2 / 86400)) * 86400);
263     }
264     hr = (time_t) ((int) now2 / 3600);
265     now2 -= (hr * 3600);
266     min = (time_t) ((int) now2 / 60);
267     sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
268     s1[0] = 0;
269     if (backgrd)
270     strcpy(s1, MISC_BACKGROUND);
271     else {
272     if (term_z)
273     strcpy(s1, MISC_TERMMODE);
274     else if (con_chan)
275     strcpy(s1, MISC_STATMODE);
276     else
277     strcpy(s1, MISC_LOGMODE);
278     }
279     dprintf(idx, "%s %s (%s)\n", MISC_ONLINEFOR, s, s1);
280     }
281    
282     /* Dump status info out to dcc
283     */
284     void tell_verbose_status(int idx)
285     {
286     char s[256], s1[121], s2[81];
287     char *vers_t, *uni_t;
288     int i;
289     time_t now2 = now - online_since, hr, min;
290 pseudo 1.2 float cputime;
291 simple 1.1 #ifdef HAVE_UNAME
292     struct utsname un;
293    
294     if (!uname(&un) < 0) {
295     #endif
296     vers_t = " ";
297     uni_t = "*unknown*";
298     #ifdef HAVE_UNAME
299     } else {
300     vers_t = un.release;
301     uni_t = un.sysname;
302     }
303     #endif
304    
305     i = count_users(userlist);
306     dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk).\n",
307     botnetnick, ver, i, i == 1 ? "" : "s",
308     (int) (expected_memory() / 1024));
309    
310     s[0] = 0;
311     if (now2 > 86400) {
312     /* days */
313     sprintf(s, "%d day", (int) (now2 / 86400));
314     if ((int) (now2 / 86400) >= 2)
315     strcat(s, "s");
316     strcat(s, ", ");
317     now2 -= (((int) (now2 / 86400)) * 86400);
318     }
319     hr = (time_t) ((int) now2 / 3600);
320     now2 -= (hr * 3600);
321     min = (time_t) ((int) now2 / 60);
322     sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
323     s1[0] = 0;
324     if (backgrd)
325     strcpy(s1, MISC_BACKGROUND);
326     else {
327     if (term_z)
328     strcpy(s1, MISC_TERMMODE);
329     else if (con_chan)
330     strcpy(s1, MISC_STATMODE);
331     else
332     strcpy(s1, MISC_LOGMODE);
333     }
334 pseudo 1.2 cputime = getcputime();
335     if (cputime < 0)
336     sprintf(s2, "CPU: unknown");
337     else {
338     hr = cputime / 60;
339     cputime -= hr * 60;
340     sprintf(s2, "CPU: %02d:%05.2f", (int) hr, cputime); /* Actally min/sec */
341     }
342 simple 1.1 dprintf(idx, "%s %s (%s) - %s - %s: %4.1f%%\n", MISC_ONLINEFOR,
343     s, s1, s2, MISC_CACHEHIT,
344     100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
345    
346 pseudo 1.3 dprintf(idx, "Configured with: " EGG_AC_ARGS "\n");
347 simple 1.1 if (admin[0])
348     dprintf(idx, "Admin: %s\n", admin);
349    
350     dprintf(idx, "Config file: %s\n", configfile);
351     dprintf(idx, "OS: %s %s\n", uni_t, vers_t);
352 pseudo 1.2 dprintf(idx, "Process ID: %d (parent %d)\n", getpid(), getppid());
353 simple 1.1
354     /* info library */
355     dprintf(idx, "%s %s\n", MISC_TCLLIBRARY,
356     ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
357     tcl_resultstring() : "*unknown*");
358    
359     /* info tclversion/patchlevel */
360     dprintf(idx, "%s %s (%s %s)\n", MISC_TCLVERSION,
361     ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
362     tcl_resultstring() : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
363     tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
364     TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
365    
366     if (tcl_threaded())
367     dprintf(idx, "Tcl is threaded.\n");
368     dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
369     }
370    
371     /* Show all internal state variables
372     */
373     void tell_settings(int idx)
374     {
375     char s[1024];
376     int i;
377     struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
378    
379     dprintf(idx, "Botnet nickname: %s\n", botnetnick);
380     if (firewall[0])
381     dprintf(idx, "Firewall: %s:%d\n", firewall, firewallport);
382     dprintf(idx, "Userfile: %s\n", userfile);
383     dprintf(idx, "Motd: %s\n", motdfile);
384     dprintf(idx, "Directories:\n");
385     #ifndef STATIC
386     dprintf(idx, " Help : %s\n", helpdir);
387     dprintf(idx, " Temp : %s\n", tempdir);
388     dprintf(idx, " Modules: %s\n", moddir);
389     #else
390     dprintf(idx, " Help: %s\n", helpdir);
391     dprintf(idx, " Temp: %s\n", tempdir);
392     #endif
393     fr.global = default_flags;
394    
395     build_flags(s, &fr, NULL);
396     dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
397     MISC_NOTIFY, notify_new);
398     if (owner[0])
399     dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
400     for (i = 0; i < max_logs; i++)
401     if (logs[i].filename != NULL) {
402     dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
403     logs[i].filename, logs[i].chname,
404     masktype(logs[i].mask), maskname(logs[i].mask));
405     }
406     dprintf(idx, "Ignores last %d minute%s.\n", ignore_time,
407     (ignore_time != 1) ? "s" : "");
408     }
409    
410     void reaffirm_owners()
411     {
412     char *p, *q, s[121];
413     struct userrec *u;
414    
415     /* Please stop breaking this function. */
416     if (owner[0]) {
417     q = owner;
418     p = strchr(q, ',');
419     while (p) {
420     strncpyz(s, q, (p - q) + 1);
421     rmspace(s);
422     u = get_user_by_handle(userlist, s);
423     if (u)
424     u->flags = sanity_check(u->flags | USER_OWNER);
425     q = p + 1;
426     p = strchr(q, ',');
427     }
428     strcpy(s, q);
429     rmspace(s);
430     u = get_user_by_handle(userlist, s);
431     if (u)
432     u->flags = sanity_check(u->flags | USER_OWNER);
433     }
434     }
435    
436     void chanprog()
437     {
438     int i;
439     FILE *f;
440     char s[161], rands[8];
441    
442     admin[0] = 0;
443     helpdir[0] = 0;
444     tempdir[0] = 0;
445     conmask = 0;
446    
447     for (i = 0; i < max_logs; i++)
448     logs[i].flags |= LF_EXPIRING;
449    
450     /* Turn off read-only variables (make them write-able) for rehash */
451     protect_readonly = 0;
452    
453     /* Now read it */
454     if (!readtclprog(configfile))
455     fatal(MISC_NOCONFIGFILE, 0);
456    
457     for (i = 0; i < max_logs; i++) {
458     if (logs[i].flags & LF_EXPIRING) {
459     if (logs[i].filename != NULL) {
460     nfree(logs[i].filename);
461     logs[i].filename = NULL;
462     }
463     if (logs[i].chname != NULL) {
464     nfree(logs[i].chname);
465     logs[i].chname = NULL;
466     }
467     if (logs[i].f != NULL) {
468     fclose(logs[i].f);
469     logs[i].f = NULL;
470     }
471     logs[i].mask = 0;
472     logs[i].flags = 0;
473     }
474     }
475    
476     /* We should be safe now */
477     call_hook(HOOK_REHASH);
478     protect_readonly = 1;
479    
480     if (!botnetnick[0])
481     strncpyz(botnetnick, origbotname, HANDLEN + 1);
482    
483     if (!botnetnick[0])
484     fatal("I don't have a botnet nick!!\n", 0);
485    
486     if (!userfile[0])
487     fatal(MISC_NOUSERFILE2, 0);
488    
489     if (!readuserfile(userfile, &userlist)) {
490     if (!make_userfile) {
491     char tmp[178];
492    
493     egg_snprintf(tmp, sizeof tmp, MISC_NOUSERFILE, configfile);
494     fatal(tmp, 0);
495     }
496     printf("\n\n%s\n", MISC_NOUSERFILE2);
497     if (module_find("server", 0, 0))
498     printf(MISC_USERFCREATE1, origbotname);
499     printf("%s\n\n", MISC_USERFCREATE2);
500     } else if (make_userfile) {
501     make_userfile = 0;
502     printf("%s\n", MISC_USERFEXISTS);
503     }
504    
505     if (helpdir[0])
506     if (helpdir[strlen(helpdir) - 1] != '/')
507     strcat(helpdir, "/");
508    
509     if (tempdir[0])
510     if (tempdir[strlen(tempdir) - 1] != '/')
511     strcat(tempdir, "/");
512    
513     /* Test tempdir: it's vital. */
514    
515     /* Possible file race condition solved by using a random string
516     * and the process id in the filename.
517     * FIXME: This race is only partitially fixed. We could still be
518     * overwriting an existing file / following a malicious
519     * link.
520     */
521     make_rand_str(rands, 7); /* create random string */
522     sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
523     f = fopen(s, "w");
524     if (f == NULL)
525     fatal(MISC_CANTWRITETEMP, 0);
526     fclose(f);
527     unlink(s);
528     reaffirm_owners();
529     check_tcl_event("userfile-loaded");
530     }
531    
532     /* Reload the user file from disk
533     */
534     void reload()
535     {
536     if (!file_readable(userfile)) {
537     putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
538     return;
539     }
540    
541     noshare = 1;
542     clear_userlist(userlist);
543     noshare = 0;
544     userlist = NULL;
545     if (!readuserfile(userfile, &userlist))
546     fatal(MISC_MISSINGUSERF, 0);
547     reaffirm_owners();
548     check_tcl_event("userfile-loaded");
549     call_hook(HOOK_READ_USERFILE);
550     }
551    
552     void rehash()
553     {
554     call_hook(HOOK_PRE_REHASH);
555     noshare = 1;
556     clear_userlist(userlist);
557     noshare = 0;
558     userlist = NULL;
559     chanprog();
560     }
561    
562     /*
563     * Brief venture into timers
564     */
565    
566     /* Add a timer
567     */
568     unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
569     unsigned long prev_id)
570     {
571     tcl_timer_t *old = (*stack);
572    
573     *stack = nmalloc(sizeof **stack);
574     (*stack)->next = old;
575     (*stack)->mins = elapse;
576     (*stack)->cmd = nmalloc(strlen(cmd) + 1);
577     strcpy((*stack)->cmd, cmd);
578     /* If it's just being added back and already had an id,
579     * don't create a new one.
580     */
581     if (prev_id > 0)
582     (*stack)->id = prev_id;
583     else
584     (*stack)->id = timer_id++;
585     return (*stack)->id;
586     }
587    
588     /* Remove a timer, by id
589     */
590     int remove_timer(tcl_timer_t ** stack, unsigned long id)
591     {
592     tcl_timer_t *old;
593     int ok = 0;
594    
595     while (*stack) {
596     if ((*stack)->id == id) {
597     ok++;
598     old = *stack;
599     *stack = ((*stack)->next);
600     nfree(old->cmd);
601     nfree(old);
602     } else
603     stack = &((*stack)->next);
604     }
605     return ok;
606     }
607    
608     /* Check timers, execute the ones that have expired.
609     */
610     void do_check_timers(tcl_timer_t ** stack)
611     {
612     tcl_timer_t *mark = *stack, *old = NULL;
613     char x[16];
614    
615     /* New timers could be added by a Tcl script inside a current timer
616     * so i'll just clear out the timer list completely, and add any
617     * unexpired timers back on.
618     */
619     *stack = NULL;
620     while (mark) {
621     if (mark->mins > 0)
622     mark->mins--;
623     old = mark;
624     mark = mark->next;
625     if (!old->mins) {
626     egg_snprintf(x, sizeof x, "timer%lu", old->id);
627     do_tcl(x, old->cmd);
628     nfree(old->cmd);
629     nfree(old);
630     } else {
631     old->next = *stack;
632     *stack = old;
633     }
634     }
635     }
636    
637     /* Wipe all timers.
638     */
639     void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
640     {
641     tcl_timer_t *mark = *stack, *old;
642    
643     while (mark) {
644     old = mark;
645     mark = mark->next;
646     nfree(old->cmd);
647     nfree(old);
648     }
649     *stack = NULL;
650     }
651    
652     /* Return list of timers
653     */
654     void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
655     {
656     char mins[10], id[16], *x;
657     EGG_CONST char *argv[3];
658     tcl_timer_t *mark;
659    
660     for (mark = stack; mark; mark = mark->next) {
661     egg_snprintf(mins, sizeof mins, "%u", mark->mins);
662     egg_snprintf(id, sizeof id, "timer%lu", mark->id);
663     argv[0] = mins;
664     argv[1] = mark->cmd;
665     argv[2] = id;
666     x = Tcl_Merge(3, argv);
667     Tcl_AppendElement(irp, x);
668     Tcl_Free((char *) x);
669     }
670     }
671    
672     /* Oddly enough, written by Sup (former(?) Eggdrop coder)
673     */
674     int isowner(char *name)
675     {
676     register char *ptr = NULL, *s = NULL, *n = NULL;
677    
678     if (!name)
679     return 0;
680    
681     ptr = owner - 1;
682    
683     do {
684     ptr++;
685     if (*ptr && !egg_isspace(*ptr) && *ptr != ',') {
686     if (!s)
687     s = ptr;
688     } else if (s) {
689     for (n = name; *n && *s && s < ptr &&
690     tolower((unsigned) *n) == tolower((unsigned) *s); n++, s++);
691    
692     if (s == ptr && !*n)
693     return 1;
694    
695     s = NULL;
696     }
697     } while (*ptr);
698    
699     return 0;
700     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23