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

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.67 2010/06/29 15:52:24 thommey 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 /* Dump uptime info out to dcc (guppy 9Jan99)
229 */
230 void tell_verbose_uptime(int idx)
231 {
232 char s[256], s1[121];
233 time_t now2, hr, min;
234
235 now2 = now - online_since;
236 s[0] = 0;
237 if (now2 > 86400) {
238 /* days */
239 sprintf(s, "%d day", (int) (now2 / 86400));
240 if ((int) (now2 / 86400) >= 2)
241 strcat(s, "s");
242 strcat(s, ", ");
243 now2 -= (((int) (now2 / 86400)) * 86400);
244 }
245 hr = (time_t) ((int) now2 / 3600);
246 now2 -= (hr * 3600);
247 min = (time_t) ((int) now2 / 60);
248 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
249 s1[0] = 0;
250 if (backgrd)
251 strcpy(s1, MISC_BACKGROUND);
252 else {
253 if (term_z)
254 strcpy(s1, MISC_TERMMODE);
255 else if (con_chan)
256 strcpy(s1, MISC_STATMODE);
257 else
258 strcpy(s1, MISC_LOGMODE);
259 }
260 dprintf(idx, "%s %s (%s)\n", MISC_ONLINEFOR, s, s1);
261 }
262
263 /* Dump status info out to dcc
264 */
265 void tell_verbose_status(int idx)
266 {
267 char s[256], s1[121], s2[81];
268 char *vers_t, *uni_t;
269 int i;
270 time_t now2 = now - online_since, hr, min;
271 #ifdef HAVE_GETRUSAGE
272 struct rusage ru;
273 #else
274 # ifdef HAVE_CLOCK
275 clock_t cl;
276 # endif
277 #endif
278 #ifdef HAVE_UNAME
279 struct utsname un;
280
281 if (!uname(&un) < 0) {
282 #endif
283 vers_t = " ";
284 uni_t = "*unknown*";
285 #ifdef HAVE_UNAME
286 } else {
287 vers_t = un.release;
288 uni_t = un.sysname;
289 }
290 #endif
291
292 i = count_users(userlist);
293 dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk).\n",
294 botnetnick, ver, i, i == 1 ? "" : "s",
295 (int) (expected_memory() / 1024));
296
297 s[0] = 0;
298 if (now2 > 86400) {
299 /* days */
300 sprintf(s, "%d day", (int) (now2 / 86400));
301 if ((int) (now2 / 86400) >= 2)
302 strcat(s, "s");
303 strcat(s, ", ");
304 now2 -= (((int) (now2 / 86400)) * 86400);
305 }
306 hr = (time_t) ((int) now2 / 3600);
307 now2 -= (hr * 3600);
308 min = (time_t) ((int) now2 / 60);
309 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
310 s1[0] = 0;
311 if (backgrd)
312 strcpy(s1, MISC_BACKGROUND);
313 else {
314 if (term_z)
315 strcpy(s1, MISC_TERMMODE);
316 else if (con_chan)
317 strcpy(s1, MISC_STATMODE);
318 else
319 strcpy(s1, MISC_LOGMODE);
320 }
321 #ifdef HAVE_GETRUSAGE
322 getrusage(RUSAGE_SELF, &ru);
323 hr = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) / 60);
324 min = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) - (hr * 60));
325 sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min); /* Actally min/sec */
326 #else
327 # ifdef HAVE_CLOCK
328 cl = (clock() / CLOCKS_PER_SEC);
329 hr = (int) (cl / 60);
330 min = (int) (cl - (hr * 60));
331 sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min); /* Actually min/sec */
332 # else
333 sprintf(s2, "CPU: unknown");
334 # endif
335 #endif
336 dprintf(idx, "%s %s (%s) - %s - %s: %4.1f%%\n", MISC_ONLINEFOR,
337 s, s1, s2, MISC_CACHEHIT,
338 100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
339
340 if (admin[0])
341 dprintf(idx, "Admin: %s\n", admin);
342
343 dprintf(idx, "Config file: %s\n", configfile);
344 dprintf(idx, "OS: %s %s\n", uni_t, vers_t);
345
346 /* info library */
347 dprintf(idx, "%s %s\n", MISC_TCLLIBRARY,
348 ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
349 tcl_resultstring() : "*unknown*");
350
351 /* info tclversion/patchlevel */
352 dprintf(idx, "%s %s (%s %s)\n", MISC_TCLVERSION,
353 ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
354 tcl_resultstring() : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
355 tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
356 TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
357
358 if (tcl_threaded())
359 dprintf(idx, "Tcl is threaded.\n");
360 dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
361 }
362
363 /* Show all internal state variables
364 */
365 void tell_settings(int idx)
366 {
367 char s[1024];
368 int i;
369 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
370
371 dprintf(idx, "Botnet nickname: %s\n", botnetnick);
372 if (firewall[0])
373 dprintf(idx, "Firewall: %s:%d\n", firewall, firewallport);
374 dprintf(idx, "Userfile: %s\n", userfile);
375 dprintf(idx, "Motd: %s\n", motdfile);
376 dprintf(idx, "Directories:\n");
377 #ifndef STATIC
378 dprintf(idx, " Help : %s\n", helpdir);
379 dprintf(idx, " Temp : %s\n", tempdir);
380 dprintf(idx, " Modules: %s\n", moddir);
381 #else
382 dprintf(idx, " Help: %s\n", helpdir);
383 dprintf(idx, " Temp: %s\n", tempdir);
384 #endif
385 fr.global = default_flags;
386
387 build_flags(s, &fr, NULL);
388 dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
389 MISC_NOTIFY, notify_new);
390 if (owner[0])
391 dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
392 for (i = 0; i < max_logs; i++)
393 if (logs[i].filename != NULL) {
394 dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
395 logs[i].filename, logs[i].chname,
396 masktype(logs[i].mask), maskname(logs[i].mask));
397 }
398 dprintf(idx, "Ignores last %d minute%s.\n", ignore_time,
399 (ignore_time != 1) ? "s" : "");
400 }
401
402 void reaffirm_owners()
403 {
404 char *p, *q, s[121];
405 struct userrec *u;
406
407 /* Please stop breaking this function. */
408 if (owner[0]) {
409 q = owner;
410 p = strchr(q, ',');
411 while (p) {
412 strncpyz(s, q, (p - q) + 1);
413 rmspace(s);
414 u = get_user_by_handle(userlist, s);
415 if (u)
416 u->flags = sanity_check(u->flags | USER_OWNER);
417 q = p + 1;
418 p = strchr(q, ',');
419 }
420 strcpy(s, q);
421 rmspace(s);
422 u = get_user_by_handle(userlist, s);
423 if (u)
424 u->flags = sanity_check(u->flags | USER_OWNER);
425 }
426 }
427
428 void chanprog()
429 {
430 int i;
431 FILE *f;
432 char s[161], rands[8];
433
434 admin[0] = 0;
435 helpdir[0] = 0;
436 tempdir[0] = 0;
437 conmask = 0;
438
439 for (i = 0; i < max_logs; i++)
440 logs[i].flags |= LF_EXPIRING;
441
442 /* Turn off read-only variables (make them write-able) for rehash */
443 protect_readonly = 0;
444
445 /* Now read it */
446 if (!readtclprog(configfile))
447 fatal(MISC_NOCONFIGFILE, 0);
448
449 for (i = 0; i < max_logs; i++) {
450 if (logs[i].flags & LF_EXPIRING) {
451 if (logs[i].filename != NULL) {
452 nfree(logs[i].filename);
453 logs[i].filename = NULL;
454 }
455 if (logs[i].chname != NULL) {
456 nfree(logs[i].chname);
457 logs[i].chname = NULL;
458 }
459 if (logs[i].f != NULL) {
460 fclose(logs[i].f);
461 logs[i].f = NULL;
462 }
463 logs[i].mask = 0;
464 logs[i].flags = 0;
465 }
466 }
467
468 /* We should be safe now */
469 call_hook(HOOK_REHASH);
470 protect_readonly = 1;
471
472 if (!botnetnick[0])
473 strncpyz(botnetnick, origbotname, HANDLEN + 1);
474
475 if (!botnetnick[0])
476 fatal("I don't have a botnet nick!!\n", 0);
477
478 if (!userfile[0])
479 fatal(MISC_NOUSERFILE2, 0);
480
481 if (!readuserfile(userfile, &userlist)) {
482 if (!make_userfile) {
483 char tmp[178];
484
485 egg_snprintf(tmp, sizeof tmp, MISC_NOUSERFILE, configfile);
486 fatal(tmp, 0);
487 }
488 printf("\n\n%s\n", MISC_NOUSERFILE2);
489 if (module_find("server", 0, 0))
490 printf(MISC_USERFCREATE1, origbotname);
491 printf("%s\n\n", MISC_USERFCREATE2);
492 } else if (make_userfile) {
493 make_userfile = 0;
494 printf("%s\n", MISC_USERFEXISTS);
495 }
496
497 if (helpdir[0])
498 if (helpdir[strlen(helpdir) - 1] != '/')
499 strcat(helpdir, "/");
500
501 if (tempdir[0])
502 if (tempdir[strlen(tempdir) - 1] != '/')
503 strcat(tempdir, "/");
504
505 /* Test tempdir: it's vital. */
506
507 /* Possible file race condition solved by using a random string
508 * and the process id in the filename.
509 * FIXME: This race is only partitially fixed. We could still be
510 * overwriting an existing file / following a malicious
511 * link.
512 */
513 make_rand_str(rands, 7); /* create random string */
514 sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
515 f = fopen(s, "w");
516 if (f == NULL)
517 fatal(MISC_CANTWRITETEMP, 0);
518 fclose(f);
519 unlink(s);
520 reaffirm_owners();
521 check_tcl_event("userfile-loaded");
522 }
523
524 /* Reload the user file from disk
525 */
526 void reload()
527 {
528 if (!file_readable(userfile)) {
529 putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
530 return;
531 }
532
533 noshare = 1;
534 clear_userlist(userlist);
535 noshare = 0;
536 userlist = NULL;
537 if (!readuserfile(userfile, &userlist))
538 fatal(MISC_MISSINGUSERF, 0);
539 reaffirm_owners();
540 check_tcl_event("userfile-loaded");
541 call_hook(HOOK_READ_USERFILE);
542 }
543
544 void rehash()
545 {
546 call_hook(HOOK_PRE_REHASH);
547 noshare = 1;
548 clear_userlist(userlist);
549 noshare = 0;
550 userlist = NULL;
551 chanprog();
552 }
553
554 /*
555 * Brief venture into timers
556 */
557
558 /* Add a timer
559 */
560 unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
561 unsigned long prev_id)
562 {
563 tcl_timer_t *old = (*stack);
564
565 *stack = nmalloc(sizeof **stack);
566 (*stack)->next = old;
567 (*stack)->mins = elapse;
568 (*stack)->cmd = nmalloc(strlen(cmd) + 1);
569 strcpy((*stack)->cmd, cmd);
570 /* If it's just being added back and already had an id,
571 * don't create a new one.
572 */
573 if (prev_id > 0)
574 (*stack)->id = prev_id;
575 else
576 (*stack)->id = timer_id++;
577 return (*stack)->id;
578 }
579
580 /* Remove a timer, by id
581 */
582 int remove_timer(tcl_timer_t ** stack, unsigned long id)
583 {
584 tcl_timer_t *old;
585 int ok = 0;
586
587 while (*stack) {
588 if ((*stack)->id == id) {
589 ok++;
590 old = *stack;
591 *stack = ((*stack)->next);
592 nfree(old->cmd);
593 nfree(old);
594 } else
595 stack = &((*stack)->next);
596 }
597 return ok;
598 }
599
600 /* Check timers, execute the ones that have expired.
601 */
602 void do_check_timers(tcl_timer_t ** stack)
603 {
604 tcl_timer_t *mark = *stack, *old = NULL;
605 char x[16];
606
607 /* New timers could be added by a Tcl script inside a current timer
608 * so i'll just clear out the timer list completely, and add any
609 * unexpired timers back on.
610 */
611 *stack = NULL;
612 while (mark) {
613 if (mark->mins > 0)
614 mark->mins--;
615 old = mark;
616 mark = mark->next;
617 if (!old->mins) {
618 egg_snprintf(x, sizeof x, "timer%lu", old->id);
619 do_tcl(x, old->cmd);
620 nfree(old->cmd);
621 nfree(old);
622 } else {
623 old->next = *stack;
624 *stack = old;
625 }
626 }
627 }
628
629 /* Wipe all timers.
630 */
631 void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
632 {
633 tcl_timer_t *mark = *stack, *old;
634
635 while (mark) {
636 old = mark;
637 mark = mark->next;
638 nfree(old->cmd);
639 nfree(old);
640 }
641 *stack = NULL;
642 }
643
644 /* Return list of timers
645 */
646 void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
647 {
648 char mins[10], id[16], *x;
649 EGG_CONST char *argv[3];
650 tcl_timer_t *mark;
651
652 for (mark = stack; mark; mark = mark->next) {
653 egg_snprintf(mins, sizeof mins, "%u", mark->mins);
654 egg_snprintf(id, sizeof id, "timer%lu", mark->id);
655 argv[0] = mins;
656 argv[1] = mark->cmd;
657 argv[2] = id;
658 x = Tcl_Merge(3, argv);
659 Tcl_AppendElement(irp, x);
660 Tcl_Free((char *) x);
661 }
662 }
663
664 /* Oddly enough, written by Sup (former(?) Eggdrop coder)
665 */
666 int isowner(char *name)
667 {
668 register char *ptr = NULL, *s = NULL, *n = NULL;
669
670 if (!name)
671 return 0;
672
673 ptr = owner - 1;
674
675 do {
676 ptr++;
677 if (*ptr && !egg_isspace(*ptr) && *ptr != ',') {
678 if (!s)
679 s = ptr;
680 } else if (s) {
681 for (n = name; *n && *s && s < ptr &&
682 tolower((unsigned) *n) == tolower((unsigned) *s); n++, s++);
683
684 if (s == ptr && !*n)
685 return 1;
686
687 s = NULL;
688 }
689 } while (*ptr);
690
691 return 0;
692 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23