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

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

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


Revision 1.14 - (show annotations) (download) (as text)
Thu Mar 23 23:10:26 2000 UTC (19 years, 3 months ago) by fabian
Branch: MAIN
Changes since 1.13: +1 -5 lines
File MIME type: text/x-chdr
resync with 1.4, Mar24

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23