/[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.16 - (show annotations) (download) (as text)
Sun Oct 1 19:11:43 2000 UTC (18 years, 9 months ago) by fabian
Branch: MAIN
Changes since 1.15: +52 -89 lines
File MIME type: text/x-chdr
fabian: applied notes_lang_fix patch

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23