00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "main.h"
00032
00033 #ifdef HAVE_GETRUSAGE
00034 # include <sys/resource.h>
00035 # ifdef HAVE_SYS_RUSAGE_H
00036 # include <sys/rusage.h>
00037 # endif
00038 #endif
00039
00040 #ifdef HAVE_UNAME
00041 # include <sys/utsname.h>
00042 #endif
00043
00044 #include "modules.h"
00045
00046 extern struct userrec *userlist;
00047 extern log_t *logs;
00048 extern Tcl_Interp *interp;
00049 extern char ver[], botnetnick[], firewall[], motdfile[], userfile[], helpdir[],
00050 tempdir[], moddir[], notify_new[], owner[], configfile[];
00051 extern time_t now, online_since;
00052 extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport,
00053 default_flags, max_logs, conmask, protect_readonly, make_userfile,
00054 noshare, ignore_time, max_socks;
00055
00056 tcl_timer_t *timer = NULL;
00057 tcl_timer_t *utimer = NULL;
00058 unsigned long timer_id = 1;
00059
00060 struct chanset_t *chanset = NULL;
00061 char admin[121] = "";
00062 char origbotname[NICKLEN + 1];
00063 char botname[NICKLEN + 1];
00064
00065
00066
00067
00068 void rmspace(char *s)
00069 {
00070 register char *p = NULL, *q = NULL;
00071
00072 if (!s || !*s)
00073 return;
00074
00075
00076 for (q = s + strlen(s) - 1; q >= s && egg_isspace(*q); q--);
00077 *(q + 1) = 0;
00078
00079
00080 for (p = s; egg_isspace(*p); p++);
00081
00082 if (p != s)
00083 memmove(s, p, q - p + 2);
00084 }
00085
00086
00087
00088
00089 memberlist *ismember(struct chanset_t *chan, char *nick)
00090 {
00091 register memberlist *x;
00092
00093 for (x = chan->channel.member; x && x->nick[0]; x = x->next)
00094 if (!rfc_casecmp(x->nick, nick))
00095 return x;
00096 return NULL;
00097 }
00098
00099
00100
00101 struct chanset_t *findchan(const char *name)
00102 {
00103 register struct chanset_t *chan;
00104
00105 for (chan = chanset; chan; chan = chan->next)
00106 if (!rfc_casecmp(chan->name, name))
00107 return chan;
00108 return NULL;
00109 }
00110
00111
00112
00113 struct chanset_t *findchan_by_dname(const char *name)
00114 {
00115 register struct chanset_t *chan;
00116
00117 for (chan = chanset; chan; chan = chan->next)
00118 if (!rfc_casecmp(chan->dname, name))
00119 return chan;
00120 return NULL;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 struct userrec *check_chanlist(const char *host)
00132 {
00133 char *nick, *uhost, buf[UHOSTLEN];
00134 register memberlist *m;
00135 register struct chanset_t *chan;
00136
00137 strncpyz(buf, host, sizeof buf);
00138 uhost = buf;
00139 nick = splitnick(&uhost);
00140 for (chan = chanset; chan; chan = chan->next)
00141 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00142 if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
00143 return m->user;
00144 return NULL;
00145 }
00146
00147
00148
00149 struct userrec *check_chanlist_hand(const char *hand)
00150 {
00151 register struct chanset_t *chan;
00152 register memberlist *m;
00153
00154 for (chan = chanset; chan; chan = chan->next)
00155 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00156 if (m->user && !egg_strcasecmp(m->user->handle, hand))
00157 return m->user;
00158 return NULL;
00159 }
00160
00161
00162
00163
00164
00165
00166 void clear_chanlist(void)
00167 {
00168 register memberlist *m;
00169 register struct chanset_t *chan;
00170
00171 for (chan = chanset; chan; chan = chan->next)
00172 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00173 m->user = NULL;
00174 m->tried_getuser = 0;
00175 }
00176 }
00177
00178
00179
00180
00181
00182
00183 void clear_chanlist_member(const char *nick)
00184 {
00185 register memberlist *m;
00186 register struct chanset_t *chan;
00187
00188 for (chan = chanset; chan; chan = chan->next)
00189 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00190 if (!rfc_casecmp(m->nick, nick)) {
00191 m->user = NULL;
00192 m->tried_getuser = 0;
00193 break;
00194 }
00195 }
00196
00197
00198
00199 void set_chanlist(const char *host, struct userrec *rec)
00200 {
00201 char *nick, *uhost, buf[UHOSTLEN];
00202 register memberlist *m;
00203 register struct chanset_t *chan;
00204
00205 strncpyz(buf, host, sizeof buf);
00206 uhost = buf;
00207 nick = splitnick(&uhost);
00208 for (chan = chanset; chan; chan = chan->next)
00209 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00210 if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
00211 m->user = rec;
00212 }
00213
00214
00215
00216 int expmem_chanprog()
00217 {
00218 register int tot = 0;
00219 register tcl_timer_t *t;
00220
00221 for (t = timer; t; t = t->next)
00222 tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
00223 for (t = utimer; t; t = t->next)
00224 tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
00225 return tot;
00226 }
00227
00228
00229
00230 void tell_verbose_uptime(int idx)
00231 {
00232 char s[256], s1[121];
00233 time_t now2, hr, min;
00234
00235 now2 = now - online_since;
00236 s[0] = 0;
00237 if (now2 > 86400) {
00238
00239 sprintf(s, "%d day", (int) (now2 / 86400));
00240 if ((int) (now2 / 86400) >= 2)
00241 strcat(s, "s");
00242 strcat(s, ", ");
00243 now2 -= (((int) (now2 / 86400)) * 86400);
00244 }
00245 hr = (time_t) ((int) now2 / 3600);
00246 now2 -= (hr * 3600);
00247 min = (time_t) ((int) now2 / 60);
00248 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
00249 s1[0] = 0;
00250 if (backgrd)
00251 strcpy(s1, MISC_BACKGROUND);
00252 else {
00253 if (term_z)
00254 strcpy(s1, MISC_TERMMODE);
00255 else if (con_chan)
00256 strcpy(s1, MISC_STATMODE);
00257 else
00258 strcpy(s1, MISC_LOGMODE);
00259 }
00260 dprintf(idx, "%s %s (%s)\n", MISC_ONLINEFOR, s, s1);
00261 }
00262
00263
00264
00265 void tell_verbose_status(int idx)
00266 {
00267 char s[256], s1[121], s2[81];
00268 char *vers_t, *uni_t;
00269 int i;
00270 time_t now2 = now - online_since, hr, min;
00271 #ifdef HAVE_GETRUSAGE
00272 struct rusage ru;
00273 #else
00274 # ifdef HAVE_CLOCK
00275 clock_t cl;
00276 # endif
00277 #endif
00278 #ifdef HAVE_UNAME
00279 struct utsname un;
00280
00281 if (!uname(&un) < 0) {
00282 #endif
00283 vers_t = " ";
00284 uni_t = "*unknown*";
00285 #ifdef HAVE_UNAME
00286 } else {
00287 vers_t = un.release;
00288 uni_t = un.sysname;
00289 }
00290 #endif
00291
00292 i = count_users(userlist);
00293 dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk).\n",
00294 botnetnick, ver, i, i == 1 ? "" : "s",
00295 (int) (expected_memory() / 1024));
00296
00297 s[0] = 0;
00298 if (now2 > 86400) {
00299
00300 sprintf(s, "%d day", (int) (now2 / 86400));
00301 if ((int) (now2 / 86400) >= 2)
00302 strcat(s, "s");
00303 strcat(s, ", ");
00304 now2 -= (((int) (now2 / 86400)) * 86400);
00305 }
00306 hr = (time_t) ((int) now2 / 3600);
00307 now2 -= (hr * 3600);
00308 min = (time_t) ((int) now2 / 60);
00309 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
00310 s1[0] = 0;
00311 if (backgrd)
00312 strcpy(s1, MISC_BACKGROUND);
00313 else {
00314 if (term_z)
00315 strcpy(s1, MISC_TERMMODE);
00316 else if (con_chan)
00317 strcpy(s1, MISC_STATMODE);
00318 else
00319 strcpy(s1, MISC_LOGMODE);
00320 }
00321 #ifdef HAVE_GETRUSAGE
00322 getrusage(RUSAGE_SELF, &ru);
00323 hr = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) / 60);
00324 min = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) - (hr * 60));
00325 sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min);
00326 #else
00327 # ifdef HAVE_CLOCK
00328 cl = (clock() / CLOCKS_PER_SEC);
00329 hr = (int) (cl / 60);
00330 min = (int) (cl - (hr * 60));
00331 sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min);
00332 # else
00333 sprintf(s2, "CPU: unknown");
00334 # endif
00335 #endif
00336 dprintf(idx, "%s %s (%s) - %s - %s: %4.1f%%\n", MISC_ONLINEFOR,
00337 s, s1, s2, MISC_CACHEHIT,
00338 100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
00339
00340 dprintf(idx, "Configured with: " EGG_AC_ARGS "\n");
00341 if (admin[0])
00342 dprintf(idx, "Admin: %s\n", admin);
00343
00344 dprintf(idx, "Config file: %s\n", configfile);
00345 dprintf(idx, "OS: %s %s\n", uni_t, vers_t);
00346
00347
00348 dprintf(idx, "%s %s\n", MISC_TCLLIBRARY,
00349 ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
00350 tcl_resultstring() : "*unknown*");
00351
00352
00353 dprintf(idx, "%s %s (%s %s)\n", MISC_TCLVERSION,
00354 ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
00355 tcl_resultstring() : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
00356 tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
00357 TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
00358
00359 if (tcl_threaded())
00360 dprintf(idx, "Tcl is threaded.\n");
00361 dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
00362 }
00363
00364
00365
00366 void tell_settings(int idx)
00367 {
00368 char s[1024];
00369 int i;
00370 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
00371
00372 dprintf(idx, "Botnet nickname: %s\n", botnetnick);
00373 if (firewall[0])
00374 dprintf(idx, "Firewall: %s:%d\n", firewall, firewallport);
00375 dprintf(idx, "Userfile: %s\n", userfile);
00376 dprintf(idx, "Motd: %s\n", motdfile);
00377 dprintf(idx, "Directories:\n");
00378 #ifndef STATIC
00379 dprintf(idx, " Help : %s\n", helpdir);
00380 dprintf(idx, " Temp : %s\n", tempdir);
00381 dprintf(idx, " Modules: %s\n", moddir);
00382 #else
00383 dprintf(idx, " Help: %s\n", helpdir);
00384 dprintf(idx, " Temp: %s\n", tempdir);
00385 #endif
00386 fr.global = default_flags;
00387
00388 build_flags(s, &fr, NULL);
00389 dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
00390 MISC_NOTIFY, notify_new);
00391 if (owner[0])
00392 dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
00393 for (i = 0; i < max_logs; i++)
00394 if (logs[i].filename != NULL) {
00395 dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
00396 logs[i].filename, logs[i].chname,
00397 masktype(logs[i].mask), maskname(logs[i].mask));
00398 }
00399 dprintf(idx, "Ignores last %d minute%s.\n", ignore_time,
00400 (ignore_time != 1) ? "s" : "");
00401 }
00402
00403 void reaffirm_owners()
00404 {
00405 char *p, *q, s[121];
00406 struct userrec *u;
00407
00408
00409 if (owner[0]) {
00410 q = owner;
00411 p = strchr(q, ',');
00412 while (p) {
00413 strncpyz(s, q, (p - q) + 1);
00414 rmspace(s);
00415 u = get_user_by_handle(userlist, s);
00416 if (u)
00417 u->flags = sanity_check(u->flags | USER_OWNER);
00418 q = p + 1;
00419 p = strchr(q, ',');
00420 }
00421 strcpy(s, q);
00422 rmspace(s);
00423 u = get_user_by_handle(userlist, s);
00424 if (u)
00425 u->flags = sanity_check(u->flags | USER_OWNER);
00426 }
00427 }
00428
00429 void chanprog()
00430 {
00431 int i;
00432 FILE *f;
00433 char s[161], rands[8];
00434
00435 admin[0] = 0;
00436 helpdir[0] = 0;
00437 tempdir[0] = 0;
00438 conmask = 0;
00439
00440 for (i = 0; i < max_logs; i++)
00441 logs[i].flags |= LF_EXPIRING;
00442
00443
00444 protect_readonly = 0;
00445
00446
00447 if (!readtclprog(configfile))
00448 fatal(MISC_NOCONFIGFILE, 0);
00449
00450 for (i = 0; i < max_logs; i++) {
00451 if (logs[i].flags & LF_EXPIRING) {
00452 if (logs[i].filename != NULL) {
00453 nfree(logs[i].filename);
00454 logs[i].filename = NULL;
00455 }
00456 if (logs[i].chname != NULL) {
00457 nfree(logs[i].chname);
00458 logs[i].chname = NULL;
00459 }
00460 if (logs[i].f != NULL) {
00461 fclose(logs[i].f);
00462 logs[i].f = NULL;
00463 }
00464 logs[i].mask = 0;
00465 logs[i].flags = 0;
00466 }
00467 }
00468
00469
00470 call_hook(HOOK_REHASH);
00471 protect_readonly = 1;
00472
00473 if (!botnetnick[0])
00474 strncpyz(botnetnick, origbotname, HANDLEN + 1);
00475
00476 if (!botnetnick[0])
00477 fatal("I don't have a botnet nick!!\n", 0);
00478
00479 if (!userfile[0])
00480 fatal(MISC_NOUSERFILE2, 0);
00481
00482 if (!readuserfile(userfile, &userlist)) {
00483 if (!make_userfile) {
00484 char tmp[178];
00485
00486 egg_snprintf(tmp, sizeof tmp, MISC_NOUSERFILE, configfile);
00487 fatal(tmp, 0);
00488 }
00489 printf("\n\n%s\n", MISC_NOUSERFILE2);
00490 if (module_find("server", 0, 0))
00491 printf(MISC_USERFCREATE1, origbotname);
00492 printf("%s\n\n", MISC_USERFCREATE2);
00493 } else if (make_userfile) {
00494 make_userfile = 0;
00495 printf("%s\n", MISC_USERFEXISTS);
00496 }
00497
00498 if (helpdir[0])
00499 if (helpdir[strlen(helpdir) - 1] != '/')
00500 strcat(helpdir, "/");
00501
00502 if (tempdir[0])
00503 if (tempdir[strlen(tempdir) - 1] != '/')
00504 strcat(tempdir, "/");
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 make_rand_str(rands, 7);
00515 sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
00516 f = fopen(s, "w");
00517 if (f == NULL)
00518 fatal(MISC_CANTWRITETEMP, 0);
00519 fclose(f);
00520 unlink(s);
00521 reaffirm_owners();
00522 check_tcl_event("userfile-loaded");
00523 }
00524
00525
00526
00527 void reload()
00528 {
00529 if (!file_readable(userfile)) {
00530 putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
00531 return;
00532 }
00533
00534 noshare = 1;
00535 clear_userlist(userlist);
00536 noshare = 0;
00537 userlist = NULL;
00538 if (!readuserfile(userfile, &userlist))
00539 fatal(MISC_MISSINGUSERF, 0);
00540 reaffirm_owners();
00541 check_tcl_event("userfile-loaded");
00542 call_hook(HOOK_READ_USERFILE);
00543 }
00544
00545 void rehash()
00546 {
00547 call_hook(HOOK_PRE_REHASH);
00548 noshare = 1;
00549 clear_userlist(userlist);
00550 noshare = 0;
00551 userlist = NULL;
00552 chanprog();
00553 }
00554
00555
00556
00557
00558
00559
00560
00561 unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
00562 unsigned long prev_id)
00563 {
00564 tcl_timer_t *old = (*stack);
00565
00566 *stack = nmalloc(sizeof **stack);
00567 (*stack)->next = old;
00568 (*stack)->mins = elapse;
00569 (*stack)->cmd = nmalloc(strlen(cmd) + 1);
00570 strcpy((*stack)->cmd, cmd);
00571
00572
00573
00574 if (prev_id > 0)
00575 (*stack)->id = prev_id;
00576 else
00577 (*stack)->id = timer_id++;
00578 return (*stack)->id;
00579 }
00580
00581
00582
00583 int remove_timer(tcl_timer_t ** stack, unsigned long id)
00584 {
00585 tcl_timer_t *old;
00586 int ok = 0;
00587
00588 while (*stack) {
00589 if ((*stack)->id == id) {
00590 ok++;
00591 old = *stack;
00592 *stack = ((*stack)->next);
00593 nfree(old->cmd);
00594 nfree(old);
00595 } else
00596 stack = &((*stack)->next);
00597 }
00598 return ok;
00599 }
00600
00601
00602
00603 void do_check_timers(tcl_timer_t ** stack)
00604 {
00605 tcl_timer_t *mark = *stack, *old = NULL;
00606 char x[16];
00607
00608
00609
00610
00611
00612 *stack = NULL;
00613 while (mark) {
00614 if (mark->mins > 0)
00615 mark->mins--;
00616 old = mark;
00617 mark = mark->next;
00618 if (!old->mins) {
00619 egg_snprintf(x, sizeof x, "timer%lu", old->id);
00620 do_tcl(x, old->cmd);
00621 nfree(old->cmd);
00622 nfree(old);
00623 } else {
00624 old->next = *stack;
00625 *stack = old;
00626 }
00627 }
00628 }
00629
00630
00631
00632 void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
00633 {
00634 tcl_timer_t *mark = *stack, *old;
00635
00636 while (mark) {
00637 old = mark;
00638 mark = mark->next;
00639 nfree(old->cmd);
00640 nfree(old);
00641 }
00642 *stack = NULL;
00643 }
00644
00645
00646
00647 void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
00648 {
00649 char mins[10], id[16], *x;
00650 EGG_CONST char *argv[3];
00651 tcl_timer_t *mark;
00652
00653 for (mark = stack; mark; mark = mark->next) {
00654 egg_snprintf(mins, sizeof mins, "%u", mark->mins);
00655 egg_snprintf(id, sizeof id, "timer%lu", mark->id);
00656 argv[0] = mins;
00657 argv[1] = mark->cmd;
00658 argv[2] = id;
00659 x = Tcl_Merge(3, argv);
00660 Tcl_AppendElement(irp, x);
00661 Tcl_Free((char *) x);
00662 }
00663 }
00664
00665
00666
00667 int isowner(char *name)
00668 {
00669 register char *ptr = NULL, *s = NULL, *n = NULL;
00670
00671 if (!name)
00672 return 0;
00673
00674 ptr = owner - 1;
00675
00676 do {
00677 ptr++;
00678 if (*ptr && !egg_isspace(*ptr) && *ptr != ',') {
00679 if (!s)
00680 s = ptr;
00681 } else if (s) {
00682 for (n = name; *n && *s && s < ptr &&
00683 tolower((unsigned) *n) == tolower((unsigned) *s); n++, s++);
00684
00685 if (s == ptr && !*n)
00686 return 1;
00687
00688 s = NULL;
00689 }
00690 } while (*ptr);
00691
00692 return 0;
00693 }