/[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.2 - (show annotations) (download) (as text)
Sat Oct 9 15:46:34 1999 UTC (20 years, 1 month ago) by fabian
Branch: MAIN
Changes since 1.1: +25 -18 lines
File MIME type: text/x-chdr
all changes to the 1.3 tree merged with 1.4

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23