char *dns_start(Function *global_funcs) { int idx; global = global_funcs; module_register(MODULE_NAME, dns_table, 1, 0); if (!module_depend(MODULE_NAME, "eggdrop", 106, 0)) { module_undepend(MODULE_NAME); return "This module requires Eggdrop 1.6.0 or later."; } idx = new_dcc(&DCC_DNS, 0); if (idx < 0) return "NO MORE DCC CONNECTIONS -- Can't create DNS socket."; if (!init_dns_core()) { lostdcc(idx); return "DNS initialisation failed."; } dcc[idx].sock = resfd; dcc[idx].timeval = now; strcpy(dcc[idx].nick, "(dns)"); add_hook(HOOK_SECONDLY, (Function) dns_check_expires); add_hook(HOOK_DNS_HOSTBYIP, (Function) dns_lookup); add_hook(HOOK_DNS_IPBYHOST, (Function) dns_forward); return NULL; }
void rehash_ip() { /* cache our ip on load instead of every 30 seconds */ char *ip4 = NULL, *ip6 = NULL; if (cached_ip) { ip4 = strdup(myipstr(AF_INET)); ip6 = strdup(myipstr(AF_INET6)); } cache_my_ip(); sdprintf("ip4: %s", myipstr(AF_INET)); sdprintf("ip6: %s", myipstr(AF_INET6)); /* Check if our ip changed during a rehash */ if (ip4) { if (strcmp(ip4, myipstr(AF_INET)) || strcmp(ip6, myipstr(AF_INET6))) { if (tands > 0) { botnet_send_chat(-1, conf.bot->nick, "IP changed."); botnet_send_bye("IP changed."); } fatal("brb", 1); } free(ip4); free(ip6); } if (conf.bot->hub) { struct bot_addr *bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, conf.bot->u); listen_all(bi->telnet_port, 0, 1); my_port = bi->telnet_port; } else if (conf.bot->localhub) { // If not listening on the domain socket, open it up bool listening = 0; for (int i = 0; i < dcc_total; i++) { if (dcc[i].type && (dcc[i].type == &DCC_TELNET) && (!strcmp(dcc[i].host, conf.localhub_socket)) && (!strcmp(dcc[i].nick, "(unix_domain"))) { listening = 1; break; } } if (!listening) { // Listen on the unix domain socket port_t port; int i = open_listen_addr_by_af(conf.localhub_socket, &port, AF_UNIX); if (i < 0) { putlog(LOG_ERRORS, "*", "Can't listen on %s - %s", conf.localhub_socket, i == -1 ? "it's taken." : "couldn't assign file."); } else { /* now setup dcc entry */ int idx = new_dcc(&DCC_TELNET, 0); dcc[idx].addr = 0L; strlcpy(dcc[idx].host, conf.localhub_socket, sizeof(dcc[idx].host)); dcc[idx].port = 0; dcc[idx].sock = i; dcc[idx].timeval = now; strlcpy(dcc[idx].nick, "(unix_domain)", sizeof(dcc[idx].nick)); putlog(LOG_DEBUG, "*", "Listening on telnet %s", conf.localhub_socket); } } } }
/* idx nick conmask cmd par */ static void bot_rsim(char *botnick, char *code, char *msg) { int ridx = -1, idx = -1, i = 0, rconmask; unsigned long status = 0; char *nick = NULL, *cmd = NULL, *rconchan = NULL, buf[UHOSTMAX] = "", *par = NULL, *parp = NULL; struct userrec *u = get_user_by_handle(userlist, botnick); if (bot_hublevel(u) == 999) { putlog(LOG_WARN, "*", "BOTCMD received from a leaf. HIJACK."); return; } par = parp = strdup(msg); ridx = atoi(newsplit(&par)); nick = newsplit(&par); rconmask = atoi(newsplit(&par)); rconchan = newsplit(&par); if (egg_isdigit(par[0])) status = (unsigned long) atoi(newsplit(&par)); cmd = newsplit(&par); if (ridx < 0 || !nick || !cmd) { free(parp); return; } for (i = 0; i < dcc_total; i++) { /* See if we can find a simul-idx for the same ridx/nick */ if (dcc[i].type && dcc[i].simul == ridx && !strcasecmp(dcc[i].nick, nick)) { putlog(LOG_DEBUG, "*", "Simul found old idx for %s: %d (ridx: %d)", nick, i, ridx); dcc[i].simultime = now; idx = i; break; } } if (idx < 0) { idx = new_dcc(&DCC_CHAT, sizeof(struct chat_info)); putlog(LOG_DEBUG, "*", "Making new idx for %s@%s: %d ridx: %d", nick, botnick, idx, ridx); dcc[idx].sock = -1; dcc[idx].timeval = now; dcc[idx].simultime = now; dcc[idx].simul = ridx; dcc[idx].status = status; strlcpy(dcc[idx].simulbot, botnick, sizeof(dcc[idx].simulbot)); dcc[idx].u.chat->con_flags = rconmask; struct chat_info dummy; strlcpy(dcc[idx].u.chat->con_chan, rconchan, sizeof(dummy.con_chan)); dcc[idx].u.chat->strip_flags = STRIP_ALL; strlcpy(dcc[idx].nick, nick, sizeof(dcc[idx].nick)); simple_snprintf(buf, sizeof buf, "%s@%s", nick, botnick); strlcpy(dcc[idx].host, buf, sizeof(dcc[idx].host)); dcc[idx].addr = 0L; dcc[idx].user = get_user_by_handle(userlist, nick); } rmspace(par); check_bind_dcc(cmd, idx, par); free(parp); }
static int get_dns_idx() { int i, sock; sock = -1; for (i = 0; i < nservers; i++) { if (!dns_ip) dns_ip = dns_next_server(); sock = socket_create(dns_ip, DNS_PORT, NULL, 0, SOCKET_CLIENT | SOCKET_NONBLOCK | SOCKET_UDP); if (sock < 0) { /* Try the next server. */ dns_ip = NULL; } else break; } if (i == nservers) return 1; // dns_idx = sockbuf_new(); // sockbuf_set_handler(dns_idx, &dns_handler, NULL); // sockbuf_set_sock(dns_idx, sock, 0); // allocsock(sock, SOCK_CONNECT); if (sock >= 0 && dns_ip) { dns_idx = new_dcc(&dns_handler, 0); if (dns_idx < 0) { putlog(LOG_SERV, "*", "NO MORE DCC CONNECTIONS -- Can't create dns connection."); killsock(sock); return 1; } sdprintf("dns_idx: %d", dns_idx); dcc[dns_idx].sock = sock; dns_sock = sock; sdprintf("dns_sock: %d", dcc[dns_idx].sock); strlcpy(dcc[dns_idx].host, dns_ip, UHOSTLEN); strlcpy(dcc[dns_idx].nick, "(adns)", NICKLEN); sdprintf("dns_ip: %s", dns_ip); dcc[dns_idx].timeval = now; dns_handler.timeout_val = 0; return 0; } return 1; }
int main(int arg_c, char **arg_v) { int i, xx; char s[25]; FILE *f; struct sigaction sv; struct chanset_t *chan; #ifdef DEBUG struct rlimit cdlim; #endif #ifdef STOP_UAC int nvpair[2]; #endif /* Make sure it can write core, if you make debug. Else it's pretty * useless (dw) * * Only allow unlimited size core files when compiled with DEBUG defined. * This is not a good idea for normal builds -- in these cases, use the * default system resource limits instead. */ #ifdef DEBUG cdlim.rlim_cur = RLIM_INFINITY; cdlim.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &cdlim); #endif #ifdef DEBUG_CONTEXT /* Initialise context list */ for (i = 0; i < 16; i++) Context; #endif /* Include patch.h header for patch("...") */ #include "patch.h" argc = arg_c; argv = arg_v; /* Version info! */ egg_snprintf(ver, sizeof ver, "eggdrop v%s", egg_version); egg_snprintf(version, sizeof version, "Eggdrop v%s (C) 1997 Robey Pointer (C) 2010 Eggheads", egg_version); /* Now add on the patchlevel (for Tcl) */ sprintf(&egg_version[strlen(egg_version)], " %u", egg_numver); strcat(egg_version, egg_xtra); /* For OSF/1 */ #ifdef STOP_UAC /* Don't print "unaligned access fixup" warning to the user */ nvpair[0] = SSIN_UACPROC; nvpair[1] = UAC_NOPRINT; setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0); #endif /* Set up error traps: */ sv.sa_handler = got_bus; sigemptyset(&sv.sa_mask); #ifdef SA_RESETHAND sv.sa_flags = SA_RESETHAND; #else sv.sa_flags = 0; #endif sigaction(SIGBUS, &sv, NULL); sv.sa_handler = got_segv; sigaction(SIGSEGV, &sv, NULL); #ifdef SA_RESETHAND sv.sa_flags = 0; #endif sv.sa_handler = got_fpe; sigaction(SIGFPE, &sv, NULL); sv.sa_handler = got_term; sigaction(SIGTERM, &sv, NULL); sv.sa_handler = got_hup; sigaction(SIGHUP, &sv, NULL); sv.sa_handler = got_quit; sigaction(SIGQUIT, &sv, NULL); sv.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sv, NULL); sv.sa_handler = got_ill; sigaction(SIGILL, &sv, NULL); sv.sa_handler = got_alarm; sigaction(SIGALRM, &sv, NULL); /* Initialize variables and stuff */ now = time(NULL); chanset = NULL; egg_memcpy(&nowtm, localtime(&now), sizeof(struct tm)); lastmin = nowtm.tm_min; srandom((unsigned int) (now % (getpid() + getppid()))); init_mem(); init_language(1); if (argc > 1) for (i = 1; i < argc; i++) do_arg(argv[i]); printf("\n%s\n", version); #ifndef CYGWIN_HACKS /* Don't allow eggdrop to run as root * This check isn't useful under cygwin and has been * reported to cause trouble in some situations. */ if (((int) getuid() == 0) || ((int) geteuid() == 0)) fatal("ERROR: Eggdrop will not run as root!", 0); #endif #ifndef REPLACE_NOTIFIER init_threaddata(1); #endif init_userent(); init_misc(); init_bots(); init_modules(); if (backgrd) bg_prepare_split(); init_tcl(argc, argv); init_language(0); #ifdef STATIC link_statics(); #endif strncpyz(s, ctime(&now), sizeof s); strcpy(&s[11], &s[20]); putlog(LOG_ALL, "*", "--- Loading %s (%s)", ver, s); chanprog(); if (!encrypt_pass) { printf(MOD_NOCRYPT); bg_send_quit(BG_ABORT); exit(1); } i = 0; for (chan = chanset; chan; chan = chan->next) i++; putlog(LOG_MISC, "*", "=== %s: %d channels, %d users.", botnetnick, i, count_users(userlist)); #ifdef TLS ssl_init(); #endif cache_miss = 0; cache_hit = 0; if (!pid_file[0]) egg_snprintf(pid_file, sizeof pid_file, "pid.%s", botnetnick); /* Check for pre-existing eggdrop! */ f = fopen(pid_file, "r"); if (f != NULL) { fgets(s, 10, f); xx = atoi(s); i = kill(xx, SIGCHLD); /* Meaningless kill to determine if pid * is used */ if (i == 0 || errno != ESRCH) { printf(EGG_RUNNING1, botnetnick); printf(EGG_RUNNING2, pid_file); bg_send_quit(BG_ABORT); exit(1); } } /* Move into background? */ if (backgrd) { bg_do_split(); } else { /* !backgrd */ xx = getpid(); if (xx != 0) { FILE *fp; /* Write pid to file */ unlink(pid_file); fp = fopen(pid_file, "w"); if (fp != NULL) { fprintf(fp, "%u\n", xx); if (fflush(fp)) { /* Let the bot live since this doesn't appear to be a botchk */ printf(EGG_NOWRITE, pid_file); fclose(fp); unlink(pid_file); } else fclose(fp); } else printf(EGG_NOWRITE, pid_file); } } use_stderr = 0; /* Stop writing to stderr now */ if (backgrd) { /* Ok, try to disassociate from controlling terminal (finger cross) */ #ifdef HAVE_SETPGID setpgid(0, 0); #endif /* Tcl wants the stdin, stdout and stderr file handles kept open. */ freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); #ifdef CYGWIN_HACKS FreeConsole(); #endif } /* Terminal emulating dcc chat */ if (!backgrd && term_z) { int n = new_dcc(&DCC_CHAT, sizeof(struct chat_info)); getvhost(&dcc[n].sockname, AF_INET); dcc[n].sock = STDOUT; dcc[n].timeval = now; dcc[n].u.chat->con_flags = conmask; dcc[n].u.chat->strip_flags = STRIP_ALL; dcc[n].status = STAT_ECHO; strcpy(dcc[n].nick, "HQ"); strcpy(dcc[n].host, "llama@console"); /* HACK: Workaround not to pass literal "HQ" as a non-const arg */ dcc[n].user = get_user_by_handle(userlist, dcc[n].nick); /* Make sure there's an innocuous HQ user if needed */ if (!dcc[n].user) { userlist = adduser(userlist, dcc[n].nick, "none", "-", USER_PARTY); dcc[n].user = get_user_by_handle(userlist, dcc[n].nick); } setsock(STDOUT, 0); /* Entry in net table */ dprintf(n, "\n### ENTERING DCC CHAT SIMULATION ###\n\n"); dcc_chatter(n); } then = now; online_since = now; autolink_cycle(NULL); /* Hurry and connect to tandem bots */ add_help_reference("cmds1.help"); add_help_reference("cmds2.help"); add_help_reference("core.help"); add_hook(HOOK_SECONDLY, (Function) core_secondly); add_hook(HOOK_MINUTELY, (Function) core_minutely); add_hook(HOOK_HOURLY, (Function) core_hourly); add_hook(HOOK_REHASH, (Function) event_rehash); add_hook(HOOK_PRE_REHASH, (Function) event_prerehash); add_hook(HOOK_USERFILE, (Function) event_save); add_hook(HOOK_BACKUP, (Function) backup_userfile); add_hook(HOOK_DAILY, (Function) event_logfile); add_hook(HOOK_DAILY, (Function) event_resettraffic); add_hook(HOOK_LOADED, (Function) event_loaded); call_hook(HOOK_LOADED); debug0("main: entering loop"); while (1) { mainloop(1); } }
/* Hook up to a server */ static void connect_server(void) { char pass[121], botserver[UHOSTLEN]; int servidx; unsigned int botserverport = 0; lastpingcheck = 0; trying_server = now; empty_msgq(); if (newserverport) { /* Jump to specified server */ curserv = -1; /* Reset server list */ strcpy(botserver, newserver); botserverport = newserverport; strcpy(pass, newserverpass); newserver[0] = 0; newserverport = 0; newserverpass[0] = 0; } else { if (curserv == -1) curserv = 999; pass[0] = 0; } if (!cycle_time) { struct chanset_t *chan; struct server_list *x = serverlist; if (!x && !botserverport) { putlog(LOG_SERV, "*", "No servers in server list"); cycle_time = 300; return; } servidx = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info)); if (servidx < 0) { putlog(LOG_SERV, "*", "NO MORE DCC CONNECTIONS -- Can't create server connection."); return; } if (connectserver[0]) /* drummer */ do_tcl("connect-server", connectserver); check_tcl_event("connect-server"); next_server(&curserv, botserver, &botserverport, pass); #ifdef TLS putlog(LOG_SERV, "*", "%s [%s]:%s%d", IRC_SERVERTRY, botserver, use_ssl ? "+" : "", botserverport); dcc[servidx].ssl = use_ssl; #else putlog(LOG_SERV, "*", "%s [%s]:%d", IRC_SERVERTRY, botserver, botserverport); #endif dcc[servidx].port = botserverport; strcpy(dcc[servidx].nick, "(server)"); strncpyz(dcc[servidx].host, botserver, UHOSTLEN); botuserhost[0] = 0; nick_juped = 0; for (chan = chanset; chan; chan = chan->next) chan->status &= ~CHAN_JUPED; dcc[servidx].timeval = now; dcc[servidx].sock = -1; dcc[servidx].u.dns->host = get_data_ptr(strlen(dcc[servidx].host) + 1); strcpy(dcc[servidx].u.dns->host, dcc[servidx].host); dcc[servidx].u.dns->cbuf = get_data_ptr(strlen(pass) + 1); strcpy(dcc[servidx].u.dns->cbuf, pass); dcc[servidx].u.dns->dns_success = server_resolve_success; dcc[servidx].u.dns->dns_failure = server_resolve_failure; dcc[servidx].u.dns->dns_type = RES_IPBYHOST; dcc[servidx].u.dns->type = &SERVER_SOCKET; if (server_cycle_wait) /* Back to 1st server & set wait time. * Note: Put it here, just in case the server quits on us quickly */ cycle_time = server_cycle_wait; else cycle_time = 0; /* I'm resolving... don't start another server connect request */ resolvserv = 1; /* Resolve the hostname. */ dcc_dnsipbyhost(dcc[servidx].host); } }
/* this only handles CHAT requests, otherwise it's handled in filesys */ static int filesys_DCC_CHAT(char *nick, char *from, char *handle, char *object, char *keyword, char *text) { char *param, *ip, *prt, buf[512], *msg = buf; int i, sock; struct userrec *u = get_user_by_handle(userlist, handle); struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0}; Context; if (!strncasecmp(text, "SEND ", 5)) { filesys_dcc_send(nick, from, u, text + 5); return 1; } if (strncasecmp(text, "CHAT ", 5) || !u) return 0; strcpy(buf, text + 5); get_user_flagrec(u, &fr, 0); param = newsplit(&msg); if (dcc_total == max_dcc) { putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT(file)", param, nick, from); } else if (glob_party(fr) || (!require_p && chan_op(fr))) return 0; /* allow ctcp.so to pick up the chat */ else if (!glob_xfer(fr)) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :.\n", nick, DCC_REFUSED3); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from); } else if (u_pass_match(u, "-")) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, DCC_REFUSED3); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from); } else if (!dccdir[0]) { putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED5, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); sock = getsock(0); if (open_telnet_dcc(sock, ip, prt) < 0) { neterror(buf); if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", nick, DCC_CONNECTFAILED1, buf); putlog(LOG_MISC, "*", "%s: CHAT(file) (%s!%s)", DCC_CONNECTFAILED2, nick, from); putlog(LOG_MISC, "*", " (%s)", buf); killsock(sock); } else if ((atoi(prt) < min_dcc_port) || (atoi(prt) > max_dcc_port)) { /* invalid port range, do clients even use over 5000?? */ if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "%s: %s!%s", DCC_REFUSED7, nick, from); } else { i = new_dcc(&DCC_FILES_PASS, sizeof(struct file_info)); dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = sock; strcpy(dcc[i].nick, u->handle); strcpy(dcc[i].host, from); dcc[i].status = STAT_ECHO; dcc[i].timeval = now; dcc[i].u.file->chat = get_data_ptr(sizeof(struct chat_info)); bzero(dcc[i].u.file->chat, sizeof(struct chat_info)); strcpy(dcc[i].u.file->chat->con_chan, "*"); dcc[i].user = u; putlog(LOG_MISC, "*", "DCC connection: CHAT(file) (%s!%s)", nick, from); dprintf(i, "%s\n", DCC_ENTERPASS); } } return 1; }
/* received a ctcp-dcc */ static void filesys_dcc_send(char *nick, char *from, struct userrec *u, char *text) { char *param, *ip, *prt, buf[512], s1[512], *msg = buf; FILE *f; int atr = u ? u->flags : 0, i, j; Context; strcpy(buf, text); param = newsplit(&msg); if (!(atr & USER_XFER)) { putlog(LOG_FILES, "*", "Refused DCC SEND %s (no access): %s!%s", param, nick, from); } else if (!dccin[0] && !upload_to_cd) { dprintf(DP_HELP, "NOTICE %s :DCC file transfers not supported.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else if (strchr(param, '/')) { dprintf(DP_HELP, "NOTICE %s :Filename cannot have '/' in it...\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); if ((atoi(prt) < min_dcc_port) || (atoi(prt) > max_dcc_port)) { /* invalid port range, do clients even use over 5000?? */ dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): invalid port", param, nick); } else if (atoi(msg) == 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, file size info must be included.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): no file size", param, nick); } else if (atoi(msg) > (dcc_maxsize * 1024)) { dprintf(DP_HELP, "NOTICE %s :Sorry, file too large.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): file too large", param, nick); } else { /* This looks like a good place for a sanity check. */ if (!sanitycheck_dcc(nick, from, ip, prt)) return; i = new_dcc(&DCC_FORK_SEND, sizeof(struct xfer_info)); if (i < 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, too many DCC connections.\n", nick); putlog(LOG_MISC, "*", "DCC connections full: SEND %s (%s!%s)", param, nick, from); } dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = -1; strcpy(dcc[i].nick, nick); strcpy(dcc[i].host, from); if (param[0] == '.') param[0] = '_'; strncpy(dcc[i].u.xfer->filename, param, 120); dcc[i].u.xfer->filename[120] = 0; if (upload_to_cd) { char *p = get_user(&USERENTRY_DCCDIR, u); if (p) sprintf(dcc[i].u.xfer->dir, "%s%s/", dccdir, p); else sprintf(dcc[i].u.xfer->dir, "%s", dccdir); } else strcpy(dcc[i].u.xfer->dir, dccin); dcc[i].u.xfer->length = atoi(msg); sprintf(s1, "%s%s", dcc[i].u.xfer->dir, param); Context; f = fopen(s1, "r"); if (f) { fclose(f); dprintf(DP_HELP, "NOTICE %s :That file already exists.\n", nick); lostdcc(i); } else { /* check for dcc-sends in process with the same filename */ for (j = 0; j < dcc_total; j++) if (j != i) { if ((dcc[j].type->flags & (DCT_FILETRAN | DCT_FILESEND)) == (DCT_FILETRAN | DCT_FILESEND)) { if (!strcmp(param, dcc[j].u.xfer->filename)) { dprintf(DP_HELP, "NOTICE %s :That file is already being sent.\n", nick); lostdcc(i); return; } } } /* put uploads in /tmp first */ sprintf(s1, "%s%s", tempdir, param); dcc[i].u.xfer->f = fopen(s1, "w"); if (dcc[i].u.xfer->f == NULL) { dprintf(DP_HELP, "NOTICE %s :Can't create that file (temp dir error)\n", nick); lostdcc(i); } else { dcc[i].timeval = now; dcc[i].sock = getsock(SOCK_BINARY); if (open_telnet_dcc(dcc[i].sock, ip, prt) < 0) { dcc[i].type->eof(i); } } } } } }
int main(int argc, char **argv) { int xx, i; #ifdef STOP_UAC int nvpair[2]; #endif char buf[520], s[25]; FILE *f; #ifndef ENABLE_STRIP struct rlimit cdlim; #endif /* Don't allow Eggdrop to run as root. */ if (((int) getuid() == 0) || ((int) geteuid() == 0)) fatal("ERROR: Eggdrop will not run as root!", 0); #ifndef ENABLE_STRIP cdlim.rlim_cur = RLIM_INFINITY; cdlim.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &cdlim); #endif #include "patch.h" /* Version info! */ egg_snprintf(ver, sizeof ver, "eggdrop v%s", egg_version); egg_snprintf(version, sizeof version, "Eggdrop v%s (C) 1997 Robey Pointer (C) 2005 Eggheads", egg_version); /* Now add on the patchlevel (for Tcl) */ sprintf(&egg_version[strlen(egg_version)], " %u", egg_numver); strcat(egg_version, egg_xtra); #ifdef STOP_UAC nvpair[0] = SSIN_UACPROC; nvpair[1] = UAC_NOPRINT; setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0); #endif /* Set up error / signal traps. */ setup_signal_traps(); /* Initialize a few variables before main loop. */ cache_miss = 0; cache_hit = 0; chanset = NULL; now = time(NULL); egg_memcpy(&nowtm, localtime(&now), sizeof(struct tm)); lastmin = nowtm.tm_min; /* Initialize random number generator. */ srandom((unsigned int) (now % (getpid() + getppid()))); init_mem(); init_language(1); /* Process command line arguments. */ process_args(argc, argv); printf("\n%s\n", version); init_dcc_max(); init_userent(); logfile_init(0); init_bots(); init_net(); init_modules(); if (backgrd) bg_prepare_split(); init_tcl(argc, argv); init_language(0); help_init(); traffic_init(); logfile_init(1); #ifdef STATIC link_statics(); #endif strncpyz(s, ctime(&now), sizeof s); strcpy(&s[11], &s[20]); putlog(LOG_ALL, "*", "--- Loading %s (%s)", ver, s); /* Read configuration data. */ readconfig(); /* Check for encryption module. */ if (!encrypt_pass) { printf(MOD_NOCRYPT); bg_send_quit(BG_ABORT); exit(1); } putlog(LOG_MISC, "*", "=== %s: %d channels, %d users.", botnetnick, count_channels(), count_users(userlist)); if (!pid_file[0]) egg_snprintf(pid_file, sizeof pid_file, "pid.%s", botnetnick); /* Check for pre-existing eggdrop! */ f = fopen(pid_file, "r"); if (f != NULL) { fgets(s, 10, f); xx = atoi(s); kill(xx, SIGCHLD); /* Meaningless kill to determine if PID is used. */ if (errno != ESRCH) { printf(EGG_RUNNING1, botnetnick); printf(EGG_RUNNING2, pid_file); bg_send_quit(BG_ABORT); exit(1); } } /* Move into background? */ if (backgrd) { #ifndef CYGWIN_HACKS bg_do_split(); } else { #endif xx = getpid(); if (xx != 0) { FILE *fp; /* Write PID to file. */ unlink(pid_file); fp = fopen(pid_file, "w"); if (fp != NULL) { fprintf(fp, "%u\n", xx); if (fflush(fp)) { /* Let the bot live since this doesn't appear to be a botchk. */ printf("Cannot not write to '%s' (PID file).\n", pid_file); fclose(fp); unlink(pid_file); } else fclose(fp); } else printf("Cannot not write to '%s' (PID file).\n", pid_file); #ifdef CYGWIN_HACKS printf("Launched into the background (PID: %d)\n\n", xx); #endif } } use_stderr = 0; /* Stop writing to stderr now */ if (backgrd) { /* Ok, try to disassociate from controlling terminal (finger cross) */ #if defined(HAVE_SETPGID) && !defined(CYGWIN_HACKS) setpgid(0, 0); #endif /* Tcl wants the stdin, stdout and stderr file handles kept open. */ freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); #ifdef CYGWIN_HACKS FreeConsole(); #endif } /* Terminal emulating dcc chat */ if (!backgrd && term_z) { int n = new_dcc(&DCC_CHAT, sizeof(struct chat_info)); dcc[n].addr = iptolong(getmyip()); dcc[n].sock = STDOUT; dcc[n].timeval = now; dcc[n].u.chat->con_flags = conmask; dcc[n].u.chat->strip_flags = STRIP_ALL; dcc[n].status = STAT_ECHO; strcpy(dcc[n].nick, "HQ"); strcpy(dcc[n].host, "llama@console"); /* HACK: Workaround not to pass literal "HQ" as a non-const arg */ dcc[n].user = get_user_by_handle(userlist, dcc[n].nick); /* Make sure there's an innocuous HQ user if needed */ if (!dcc[n].user) { userlist = adduser(userlist, dcc[n].nick, "none", "-", USER_PARTY); dcc[n].user = get_user_by_handle(userlist, dcc[n].nick); } setsock(STDOUT, 0); /* Entry in net table */ dprintf(n, "\n### ENTERING DCC CHAT SIMULATION ###\n\n"); dcc_chatter(n); } then = now; online_since = now; autolink_cycle(NULL); /* Hurry and connect to tandem bots. */ add_help_reference("cmds1.help"); add_help_reference("cmds2.help"); add_help_reference("core.help"); /* Create hooks. */ add_hook(HOOK_SECONDLY, (Function) core_secondly); add_hook(HOOK_MINUTELY, (Function) core_minutely); add_hook(HOOK_HOURLY, (Function) core_hourly); add_hook(HOOK_REHASH, (Function) event_rehash); add_hook(HOOK_PRE_REHASH, (Function) event_prerehash); add_hook(HOOK_USERFILE, (Function) event_save); add_hook(HOOK_BACKUP, (Function) backupuserfile); add_hook(HOOK_DAILY, (Function) event_logfile); add_hook(HOOK_DAILY, (Function) traffic_reset); add_hook(HOOK_LOADED, (Function) event_loaded); call_hook(HOOK_LOADED); debug0("main: entering loop"); while (1) { int socket_cleanup = 0; #ifdef USE_TCL_EVENTS /* Process a single Tcl event. */ Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT); #endif now = time(NULL); random(); /* Every second... */ if (now != then) { call_hook(HOOK_SECONDLY); then = now; } /* Only do this every so often. */ if (!socket_cleanup) { socket_cleanup = 5; /* Remove dead dcc entries. */ dcc_remove_lost(); /* Check for server or dcc activity. */ dequeue_sockets(); } else { socket_cleanup--; } /* Free unused structures. */ garbage_collect(); xx = sockgets(buf, &i); if (xx >= 0) { /* Non-error */ int idx; for (idx = 0; idx < dcc_total; idx++) { if (dcc[idx].sock != xx) continue; if (dcc[idx].type && dcc[idx].type->activity) { traffic_update_in(dcc[idx].type, (strlen(buf) + 1)); /* Traffic stats. */ dcc[idx].type->activity(idx, buf, i); } else { putlog(LOG_MISC, "*", "!!! untrapped dcc activity: type %s, sock %d", dcc[idx].type->name, dcc[idx].sock); } break; } } else if (xx == -1) { /* EOF */ int idx; if (i == STDOUT && !backgrd) fatal("END OF FILE ON TERMINAL", 0); for (idx = 0; idx < dcc_total; idx++) { if (dcc[idx].sock != i) continue; if (dcc[idx].type && dcc[idx].type->eof) { dcc[idx].type->eof(idx); } else { putlog(LOG_MISC, "*", "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED", i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*"); killsock(i); lostdcc(idx); } idx = dcc_total + 1; } if (idx == dcc_total) { putlog(LOG_MISC, "*", "(@) EOF socket %d, not a dcc socket, not anything.", i); close(i); killsock(i); } } else if (xx == -2 && errno != EINTR) { /* select() error */ putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno); for (i = 0; i < dcc_total; i++) { if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) { putlog(LOG_MISC, "*", "DCC socket %d (type %d, name '%s') expired -- pfft", dcc[i].sock, dcc[i].type, dcc[i].nick); killsock(dcc[i].sock); lostdcc(i); i--; } } } else if (xx == -3) { call_hook(HOOK_IDLE); socket_cleanup = 0; /* If we've been idle, cleanup & flush */ } if (do_restart) { if (do_restart == -2) { rehash(); } else { int f = 1; module_entry *p; Function startfunc; char name[256]; check_tcl_event("prerestart"); /* Unload as many modules as possible */ while (f) { f = 0; for (p = module_list; p != NULL; p = p->next) { dependancy *d = dependancy_list; int ok = 1; while (ok && d) { if (d->needed == p) ok = 0; d = d->next; } if (ok) { strcpy(name, p->name); if (module_unload(name, botnetnick) == NULL) { f = 1; break; } } } } /* Make sure we don't have any modules left hanging around other than * "eggdrop" and the two that are supposed to be. */ for (f = 0, p = module_list; p; p = p->next) { if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") && strcmp(p->name, "uptime")) { f++; } } if (f != 0) { putlog(LOG_MISC, "*", MOD_STAGNANT); } /* Flush log files to disk. */ flushlogs(); /* Clean up Tcl stuff. */ kill_tcl(); /* Initialize stuff again. */ init_tcl(argc, argv); init_language(0); help_init(); traffic_init(); logfile_init(1); /* This resets our modules which we didn't unload (encryption and uptime). */ for (p = module_list; p; p = p->next) { if (p->funcs) { startfunc = p->funcs[MODCALL_START]; startfunc(NULL); } } rehash(); restart_chons(); call_hook(HOOK_LOADED); } do_restart = 0; } } }
/* Received a ctcp-dcc. */ static void filesys_dcc_send(char *nick, char *from, struct userrec *u, char *text) { char *param, *ip, *prt, *buf = NULL, *msg; int atr = u ? u->flags : 0, i, j = 0; if (text[j] == '"') { text[j] = ' '; for (j = 1; text[j] != '"' && text[j] != '\0'; j++) { if (text[j] == ' ') { text[j] = '_'; } } text[j] = ' '; } buf = nmalloc(strlen(text) + 1); msg = buf; strcpy(buf, text); param = newsplit(&msg); if (!(atr & USER_XFER)) { putlog(LOG_FILES, "*", "Refused DCC SEND %s (no access): %s!%s", param, nick, from); if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :No access\n", nick); } else if (!dccin[0] && !upload_to_cd) { dprintf(DP_HELP, "NOTICE %s :DCC file transfers not supported.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else if (strchr(param, '/')) { dprintf(DP_HELP, "NOTICE %s :Filename cannot have '/' in it...\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); if (atoi(prt) < 1024 || atoi(prt) > 65535) { /* Invalid port */ dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): invalid port", param, nick); } else if (atoi(msg) == 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, file size info must be included.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): no file size", param, nick); } else if (dcc_maxsize && (atoi(msg) > (dcc_maxsize * 1024))) { dprintf(DP_HELP, "NOTICE %s :Sorry, file too large.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): file too large", param, nick); } else { /* This looks like a good place for a sanity check. */ if (!sanitycheck_dcc(nick, from, ip, prt)) { my_free(buf); return; } i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info)); if (i < 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, too many DCC connections.\n", nick); putlog(LOG_MISC, "*", "DCC connections full: SEND %s (%s!%s)", param, nick, from); return; } dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = -1; dcc[i].user = u; strcpy(dcc[i].nick, nick); strcpy(dcc[i].host, from); dcc[i].u.dns->cbuf = get_data_ptr(strlen(param) + 1); strcpy(dcc[i].u.dns->cbuf, param); dcc[i].u.dns->ibuf = atoi(msg); dcc[i].u.dns->ip = dcc[i].addr; dcc[i].u.dns->dns_type = RES_HOSTBYIP; dcc[i].u.dns->dns_success = filesys_dcc_send_hostresolved; dcc[i].u.dns->dns_failure = filesys_dcc_send_hostresolved; dcc[i].u.dns->type = &DCC_FORK_SEND; dcc_dnshostbyip(dcc[i].addr); } } my_free(buf); }
/* link to another bot */ int botlink(char *linker, int idx, char *nick) { struct bot_addr *bi; struct userrec *u; register int i; Context; u = get_user_by_handle(userlist, nick); if (!u || !(u->flags & USER_BOT)) { if (idx >= 0) dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN); } else if (!strcasecmp(nick, botnetnick)) { if (idx >= 0) dprintf(idx, "%s\n", BOT_CANTLINKMYSELF); } else if (in_chain(nick) && (idx != -3)) { if (idx >= 0) dprintf(idx, "%s\n", BOT_ALREADYLINKED); } else { for (i = 0; i < dcc_total; i++) if ((dcc[i].user == u) && ((dcc[i].type == &DCC_FORK_BOT) || (dcc[i].type == &DCC_BOT_NEW))) { if (idx >= 0) dprintf(idx, "%s\n", BOT_ALREADYLINKING); return 0; } /* address to connect to is in 'info' */ bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u); if (!bi || !strlen(bi->address) || !bi->telnet_port) { if (idx >= 0) { dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick); dprintf(idx, "%s .chaddr %s %s\n", MISC_USEFORMAT, nick, MISC_CHADDRFORMAT); } } else if (dcc_total == max_dcc) { if (idx >= 0) dprintf(idx, "%s\n", DCC_TOOMANYDCCS1); } else { Context; correct_handle(nick); i = new_dcc(&DCC_FORK_BOT, sizeof(struct bot_info)); dcc[i].port = bi->telnet_port; strcpy(dcc[i].nick, nick); strcpy(dcc[i].host, bi->address); dcc[i].timeval = now; strcpy(dcc[i].u.bot->linker, linker); strcpy(dcc[i].u.bot->version, "(primitive bot)"); if (idx > -2) putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick, bi->address, bi->telnet_port); dcc[i].u.bot->numver = idx; dcc[i].timeval = now; dcc[i].u.bot->port = dcc[i].port; /* remember where i started */ dcc[i].sock = getsock(SOCK_STRONGCONN); dcc[i].user = u; if (open_telnet_raw(dcc[i].sock, bi->address, dcc[i].port) < 0) failed_link(i); return 1; } } return 0; }
/* relay to another tandembot */ void tandem_relay(int idx, char *nick, register int i) { struct chat_info *ci; struct userrec *u; struct bot_addr *bi; Context; u = get_user_by_handle(userlist, nick); if (!u || !(u->flags & USER_BOT)) { dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN); return; } if (!strcasecmp(nick, botnetnick)) { dprintf(idx, "%s\n", BOT_CANTRELAYMYSELF); return; } /* address to connect to is in 'info' */ bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u); if (!bi) { dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick); dprintf(idx, "%s .chaddr %s %s\n", MISC_USEFORMAT, nick, MISC_CHADDRFORMAT); return; } if (dcc_total == max_dcc) { dprintf(idx, "%s\n", DCC_TOOMANYDCCS1); return; } i = new_dcc(&DCC_FORK_RELAY, sizeof(struct relay_info)); dcc[i].u.relay->chat = get_data_ptr(sizeof(struct chat_info)); dcc[i].port = bi->relay_port; dcc[i].u.relay->port = dcc[i].port; dcc[i].addr = 0L; strcpy(dcc[i].nick, nick); dcc[i].user = u; strcpy(dcc[i].host, bi->address); dcc[i].u.relay->chat->away = NULL; dcc[i].status = 0; dcc[i].timeval = now; dcc[i].u.relay->chat->msgs_per_sec = 0; dcc[i].u.relay->chat->con_flags = 0; dcc[i].u.relay->chat->buffer = NULL; dcc[i].u.relay->chat->max_line = 0; dcc[i].u.relay->chat->line_count = 0; dcc[i].u.relay->chat->current_lines = 0; dprintf(idx, "%s %s @ %s:%d ...\n", BOT_CONNECTINGTO, nick, bi->address, bi->relay_port); dprintf(idx, "%s\n", BOT_BYEINFO1); ci = dcc[idx].u.chat; dcc[idx].u.relay = get_data_ptr(sizeof(struct relay_info)); dcc[idx].u.relay->chat = ci; dcc[idx].type = &DCC_PRE_RELAY; dcc[idx].u.relay->old_status = dcc[idx].status; dcc[i].sock = getsock(SOCK_STRONGCONN); dcc[idx].u.relay->sock = dcc[i].sock; dcc[i].u.relay->sock = dcc[idx].sock; dcc[i].timeval = now; if (open_telnet_raw(dcc[i].sock, dcc[i].host, dcc[i].port) < 0) failed_tandem_relay(i); }