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

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

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


Revision 1.3 - (show annotations) (download) (as text)
Sun Oct 10 21:24:43 2010 UTC (8 years, 7 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 /*
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 * $Id: chanprog.c,v 1.2 2010/10/10 18:22:47 pseudo Exp $
11 */
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 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 /* 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 float cputime;
291 #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 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 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 dprintf(idx, "Configured with: " EGG_AC_ARGS "\n");
347 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 dprintf(idx, "Process ID: %d (parent %d)\n", getpid(), getppid());
353
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