void reaffirm_owners() { char *p, *q, s[121]; struct userrec *u; /* Please stop breaking this function. */ if (owner[0]) { q = owner; p = strchr(q, ','); while (p) { strncpyz(s, q, (p - q) + 1); rmspace(s); u = get_user_by_handle(userlist, s); if (u) u->flags = sanity_check(u->flags | USER_OWNER); q = p + 1; p = strchr(q, ','); } strcpy(s, q); rmspace(s); u = get_user_by_handle(userlist, s); if (u) u->flags = sanity_check(u->flags | USER_OWNER); } }
/* 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 char *getxtra(char *hand, char *field) { struct userrec *urec; struct user_entry *ue; struct xtra_key *xk; urec = get_user_by_handle(userlist, hand); if (urec) { ue = find_user_entry(&USERENTRY_XTRA, urec); if (ue) for (xk = ue->u.extra; xk; xk = xk->next) if (xk->key && !egg_strcasecmp(xk->key, field)) { if (xk->data[0] == '{' && xk->data[strlen(xk->data) - 1] == '}' && strlen(xk->data) > 2) { strncpy(fixit, &xk->data[1], strlen(xk->data) - 2); fixit[strlen(xk->data) - 2] = 0; return fixit; } else { return xk->data; } } } return ""; }
void setup_HQ(int n) { dcc[n].addr = iptolong(getmyip()); dcc[n].sock = STDOUT; dcc[n].timeval = now; dcc[n].u.chat->con_flags = conmask | LOG_ALL; dcc[n].u.chat->strip_flags = STRIP_ALL; dcc[n].status = STAT_ECHO; strlcpy(dcc[n].nick, STR("HQ"), sizeof(dcc[n].nick)); strlcpy(dcc[n].host, STR("llama@console"), sizeof(dcc[n].host)); 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_ADMIN | USER_OWNER | USER_MASTER | USER_VOICE | USER_OP | USER_PARTY | USER_CHUBA | USER_HUBA, 0); dcc[n].user = get_user_by_handle(userlist, dcc[n].nick); } }
void update_mod(char *handle, char *nick, char *cmd, char *par) { char tmp[100] = ""; simple_snprintf(tmp, sizeof tmp, "%li, %s (%s %s)", (long) now, nick, cmd, (par && par[0]) ? par : ""); set_user(&USERENTRY_MODIFIED, get_user_by_handle(userlist, handle), tmp); }
void check_bind_chof(char *hand, int idx) { struct userrec *u = NULL; u = get_user_by_handle(userlist, hand); touch_laston(u, "partyline", now); }
static void set_handle_chaninfo(struct userrec *bu, char *handle, char *chname, char *info) { struct userrec *u; struct chanuserrec *ch; struct chanset_t *cst; u = get_user_by_handle(bu, handle); if (!u) return; ch = get_chanrec(u, chname); if (!ch) { add_chanrec_by_handle(bu, handle, chname); ch = get_chanrec(u, chname); } if (ch->info != NULL) nfree(ch->info); if (info && info[0]) { ch->info = (char *) user_malloc(strlen(info) + 1); strcpy(ch->info, info); } else ch->info = NULL; cst = findchan_by_dname(chname); if ((!noshare) && (bu == userlist) && !(u->flags & (USER_UNSHARED | USER_BOT)) && share_greet) { shareout(cst, "chchinfo %s %s %s\n", handle, chname, info ? info : ""); } }
static void tell_file_stats(int idx, char *hand) { struct userrec *u; struct filesys_stats *fs; float fr = (-1.0), kr = (-1.0); u = get_user_by_handle(userlist, hand); if (u == NULL) return; if (!(fs = get_user(&USERENTRY_FSTAT, u))) { dprintf(idx, "No file statistics for %s.\n", hand); } else { dprintf(idx, " uploads: %4u / %6luk\n", fs->uploads, fs->upload_ks); dprintf(idx, "downloads: %4u / %6luk\n", fs->dnloads, fs->dnload_ks); if (fs->uploads) fr = ((float) fs->dnloads / (float) fs->uploads); if (fs->upload_ks) kr = ((float) fs->dnload_ks / (float) fs->upload_ks); if (fr < 0.0) dprintf(idx, "(infinite file leech)\n"); else dprintf(idx, "leech ratio (files): %6.2f\n", fr); if (kr < 0.0) dprintf(idx, "(infinite size leech)\n"); else dprintf(idx, "leech ratio (size) : %6.2f\n", kr); } }
/* This will close channels if the HUB:leaf count is skewed from config setting */ static void check_should_close() { int H = close_threshold.count, L = close_threshold.time; if ((H <= 0) || (L <= 0)) return; int hc = 1, lc = 0; struct userrec *u = NULL; for (tand_t *bot = tandbot; bot; bot = bot->next) { if ((u = get_user_by_handle(userlist, bot->bot))) { if (bot_hublevel(u) < 999) hc++; else lc++; } } if ((hc >= H) && (lc <= L)) { for (struct chanset_t *chan = chanset; chan; chan = chan->next) { if (!channel_closed(chan)) { do_chanset(NULL, chan, "+closed chanmode +stni", DO_LOCAL | DO_NET); #ifdef G_BACKUP chan->channel.backup_time = now + 30; #endif /* G_BACKUP */ } } } }
void show_channels(int idx, char *handle) { struct userrec *u = NULL; size_t maxChannelLength = 0; bd::Array<bd::String> channelNames; bd::HashTable<bd::String, struct chanset_t*> channels; bd::String group; if (handle && handle[0] != '%') { u = get_user_by_handle(userlist, handle); } else { u = dcc[idx].user; if (handle && handle[0] == '%') { group = handle + 1; } } for (struct chanset_t* chan = chanset; chan; chan = chan->next) { struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0 }; const bd::String chname(chan->dname); // If a group was passed, ensure it matches if (group.length() && chan->groups->find(group) == chan->groups->npos) { continue; } get_user_flagrec(u, &fr, chan->dname); if (group.length() || real_chk_op(fr, chan, 0)) { if (maxChannelLength < chname.length()) { maxChannelLength = chname.length(); } channelNames << chname; channels[chname] = chan; } } if (channelNames.length()) { char format[120] = ""; simple_snprintf(format, sizeof(format), " %%c%%-%zus %%-s%%-s%%-s%%-s%%-s%%-s\n", (maxChannelLength+2)); if (group.length()) { dprintf(idx, "group '%s' is in %zu channel%s:\n", group.c_str(), channelNames.length(), (channelNames.length() > 1) ? "s" : ""); } else { dprintf(idx, "%s %s access to %zu channel%s:\n", handle ? u->handle : "You", handle ? "has" : "have", channelNames.length(), (channelNames.length() > 1) ? "s" : ""); } for (size_t i = 0; i < channelNames.length(); ++i) { const bd::String chname(channelNames[i]); const struct chanset_t* chan = channels[chname]; dprintf(idx, format, !conf.bot->hub && me_op(chan) ? '@' : ' ', chan->dname, ((conf.bot->hub && channel_inactive(chan)) || (!conf.bot->hub && !shouldjoin(chan))) ? "(inactive) " : "", channel_privchan(chan) ? "(private) " : "", chan->manop ? "(no manop) " : "", channel_bitch(chan) && !channel_botbitch(chan) ? "(bitch) " : channel_botbitch(chan) ? "(botbitch) " : "", channel_closed(chan) ? "(closed) " : "", channel_backup(chan) ? "(backup)" : ""); } } else { if (group.length()) { dprintf(idx, "No channels found for group '%s'\n", group.c_str()); } else { dprintf(idx, "%s %s not have access to any channels.\n", handle ? u->handle : "You", handle ? "does" : "do"); } } }
static struct userrec* add_bot_userlist(char* bot) { struct userrec *u = NULL; if (!(u = get_user_by_handle(userlist, bot))) { /* I need to be on the userlist... doh. */ userlist = adduser(userlist, bot, "none", "-", USER_OP, 1); u = get_user_by_handle(userlist, bot); struct bot_addr *bi = (struct bot_addr *) my_calloc(1, sizeof(struct bot_addr)); bi->uplink = (char *) my_calloc(1, 1); bi->address = (char *) my_calloc(1, 1); bi->telnet_port = 3333; bi->relay_port = 3333; bi->hublevel = 999; set_user(&USERENTRY_BOTADDR, u, bi); } return u; }
static void bot_handshake(int idx, char *par) { struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick); /* We *don't* want botnet passwords migrating */ noshare = 1; set_user(&USERENTRY_PASS, u, par); noshare = 0; }
static int ctcp_PING(char *nick, char *uhost, char *handle, char *object, char *keyword, char *text) { struct userrec *u = get_user_by_handle(userlist, handle); int atr = u ? u->flags : 0; if ((ctcp_mode != 1 || (atr & USER_OP)) && strlen(text) <= 80) simple_sprintf(ctcp_reply, "%s\001%s %s\001", ctcp_reply, keyword, text); return 1; }
static void add_chanrec_by_handle(struct userrec *bu, char *hand, char *chname) { struct userrec *u; u = get_user_by_handle(bu, hand); if (!u) return; if (!get_chanrec(u, chname)) add_chanrec(u, chname); }
void check_bind_chon(char *hand, int idx) { struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 }; struct userrec *u = NULL; u = get_user_by_handle(userlist, hand); touch_laston(u, "partyline", now); get_user_flagrec(u, &fr, NULL); check_bind(BT_chon, hand, &fr, hand, idx); }
static int ctcp_CHAT(char *nick, char *uhost, char *handle, char *object, char *keyword, char *text) { struct userrec *u = get_user_by_handle(userlist, handle); int atr = u ? u->flags : 0, i; char s[INET6_ADDRSTRLEN]; #ifdef TLS int ssl = 0; #endif if ((atr & (USER_PARTY | USER_XFER)) || ((atr & USER_OP) && !require_p)) { if (u_pass_match(u, "-")) { simple_sprintf(ctcp_reply, "%s\001ERROR no password set\001", ctcp_reply); return 1; } #ifdef TLS if (!egg_strcasecmp(keyword, "SCHAT")) ssl = 1; #endif for (i = 0; i < dcc_total; i++) { if ((dcc[i].type->flags & DCT_LISTEN) && #ifdef TLS (ssl == dcc[i].ssl) && #endif (!strcmp(dcc[i].nick, "(telnet)") || !strcmp(dcc[i].nick, "(users)")) && getdccaddr(&dcc[i].sockname, s, sizeof s)) { /* Do me a favour and don't change this back to a CTCP reply, * CTCP replies are NOTICE's this has to be a PRIVMSG * -poptix 5/1/1997 */ #ifdef TLS dprintf(DP_SERVER, ":%s PRIVMSG %s :\001DCC %sCHAT chat %s %u\001\n", botname, nick, (ssl ? "S" : ""), s, dcc[i].port); #else dprintf(DP_SERVER, ":%s PRIVMSG %s :\001DCC CHAT chat %s %u\001\n", botname, nick, s, dcc[i].port); #endif return 1; } } #ifdef TLS simple_sprintf(ctcp_reply, "%s\001ERROR no %stelnet port\001", ctcp_reply, (ssl ? "SSL enabled " : "")); #else simple_sprintf(ctcp_reply, "%s\001ERROR no telnet port\001", ctcp_reply); #endif } return 1; }
/* part <bot> <nick> <sock> [etc..] */ static void bot_part(int idx, char *par) { char *bot = NULL, *nick = NULL, *etc = NULL; struct userrec *u = NULL; int sock, partyidx; int silent = 0; bot = newsplit(&par); if (bot[0] == '!') { silent = 1; bot++; } nick = newsplit(&par); etc = newsplit(&par); sock = base64_to_int(etc); u = get_user_by_handle(userlist, nick); if (u) { simple_snprintf(TBUF, sizeof(TBUF), "@%s", bot); touch_laston(u, TBUF, now); } if ((partyidx = getparty(bot, sock)) != -1) { if (!silent) { register int chan = party[partyidx].chan; if (par[0]) chanout_but(-1, chan, "*** (%s) %s %s %s (%s).\n", conf.bot->hub ? bot : "[botnet]", nick, "has left the", chan ? "channel" : "party line", par); else chanout_but(-1, chan, "*** (%s) %s %s %s.\n", conf.bot->hub ? bot : "[botnet]", nick, "has left the", chan ? "channel" : "party line"); } botnet_send_part_party(idx, partyidx, par, silent); remparty(bot, sock); } /* check if we have a remote idx for them */ int i = 0; for (i = 0; i < dcc_total; i++) { /* This will potentially close all simul-idxs with matching nick, even though they may be connected multiple times but, it won't matter as a new will just be made as needed. */ if (dcc[i].type && dcc[i].simul >= 0 && !strcasecmp(dcc[i].nick, nick)) { dcc[i].simul = -1; lostdcc(i); } } }
static void cmd_mns_chrec(int idx, char *par) { char *nick = NULL, *chn = NULL; struct userrec *u1 = NULL; struct chanuserrec *chanrec = NULL; if (!par[0]) { dprintf(idx, "Usage: -chrec <user> [channel]\n"); return; } nick = newsplit(&par); u1 = get_user_by_handle(userlist, nick); if (!u1) { dprintf(idx, "No such user.\n"); return; } if (!par[0]) { struct chanset_t *chan; chan = findchan_by_dname(dcc[idx].u.chat->con_chan); if (chan) chn = chan->dname; else { dprintf(idx, "Invalid console channel.\n"); return; } } else chn = newsplit(&par); get_user_flagrec(dcc[idx].user, &user, chn); get_user_flagrec(u1, &victim, chn); if (privchan(user, findchan_by_dname(chn), PRIV_OP)) { dprintf(idx, "No such channel.\n"); return; } if ((!glob_master(user) && !chan_master(user)) || /* drummer */ (chan_owner(victim) && !chan_owner(user) && !glob_owner(user)) || (glob_owner(victim) && !glob_owner(user))) { dprintf(idx, "You have no permission to do that.\n"); return; } chanrec = get_chanrec(u1, chn); if (!chanrec) { dprintf(idx, "User %s doesn't have a channel record for %s.\n", nick, chn); return; } putlog(LOG_CMDS, "*", "#%s# -chrec %s %s", dcc[idx].nick, nick, chn); del_chanrec(u1, chn); dprintf(idx, "Removed %s channel record from %s.\n", chn, nick); if (conf.bot->hub) write_userfile(idx); }
static void dcc_files_pass(int idx, char *buf, int x) { struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick); if (!x) return; if (u_pass_match(u, buf)) { if (too_many_filers()) { dprintf(idx, "Too many people are in the file system right now.\n"); dprintf(idx, "Please try again later.\n"); putlog(LOG_MISC, "*", "File area full: DCC chat [%s]%s", dcc[idx].nick, dcc[idx].host); killsock(dcc[idx].sock); lostdcc(idx); return; } dcc[idx].type = &DCC_FILES; if (dcc[idx].status & STAT_TELNET) dprintf(idx, "\377\374\001\n"); /* turn echo back on */ putlog(LOG_FILES, "*", "File system: [%s]%s/%d", dcc[idx].nick, dcc[idx].host, dcc[idx].port); if (!welcome_to_files(idx)) { putlog(LOG_FILES, "*", "File system broken."); killsock(dcc[idx].sock); lostdcc(idx); } else { struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick); touch_laston(u, "filearea", now); } return; } dprintf(idx, "Negative on that, Houston.\n"); putlog(LOG_MISC, "*", "Bad password: DCC chat [%s]%s", dcc[idx].nick, dcc[idx].host); killsock(dcc[idx].sock); lostdcc(idx); }
void reaffirm_owners() { /* Make sure perm owners are +a */ if (owner[0]) { char *q = owner, *p = strchr(q, ','), s[121] = ""; struct userrec *u = NULL; while (p) { strlcpy(s, q, (p - q) + 1); rmspace(s); u = get_user_by_handle(userlist, s); if (u) u->flags = sanity_check(u->flags | USER_ADMIN, 0); q = p + 1; p = strchr(q, ','); } strlcpy(s, q, sizeof(s)); rmspace(s); u = get_user_by_handle(userlist, s); if (u) u->flags = sanity_check(u->flags | USER_ADMIN, 0); } }
void check_tcl_chonof(char *hand, int sock, tcl_bind_list_t *tl) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; char s[11]; struct userrec *u; u = get_user_by_handle(userlist, hand); touch_laston(u, "partyline", now); get_user_flagrec(u, &fr, NULL); Tcl_SetVar(interp, "_chonof1", (char *) hand, 0); egg_snprintf(s, sizeof s, "%d", sock); Tcl_SetVar(interp, "_chonof2", (char *) s, 0); check_tcl_bind(tl, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET); }
/* Get rid of old useless notes. */ static void expire_notes() { FILE *f, *g; char s[513], *to, *from, *ts, *s1; int tot = 0, lapse; if (!notefile[0]) return; f = fopen(notefile, "r"); if (f == NULL) return; sprintf(s, "%s~new", notefile); g = fopen(s, "w"); if (g == NULL) { fclose(f); return; } chmod(s, userfile_perm); /* Use userfile permissions. */ while (!feof(f)) { fgets(s, 512, f); if (!feof(f)) { if (s[strlen(s) - 1] == '\n') s[strlen(s) - 1] = 0; rmspace(s); if ((s[0]) && (s[0] != '#') && (s[0] != ';')) { /* Not comment */ s1 = s; to = newsplit(&s1); from = newsplit(&s1); ts = newsplit(&s1); lapse = (now - (time_t) atoi(ts)) / 86400; if (lapse > note_life) tot++; else if (!get_user_by_handle(userlist, to)) tot++; else fprintf(g, "%s %s %s %s\n", to, from, ts, s1); } else fprintf(g, "%s\n", s); } } fclose(f); fclose(g); unlink(notefile); sprintf(s, "%s~new", notefile); movefile(s, notefile); if (tot > 0) putlog(LOG_MISC, "*", NOTES_EXPIRED, tot, tot == 1 ? "" : "s"); }
/* join <bot> <nick> <chan> <flag><sock> <from> */ static void bot_join(int idx, char *par) { char *bot = NULL, *nick = NULL, *x = NULL, *y = NULL; struct userrec *u = NULL; int i, sock, chan, i2, linking = 0; bot = newsplit(&par); if (bot[0] == '!') { linking = 1; bot++; } if (b_status(idx) & STAT_LINKING) { linking = 1; } nick = newsplit(&par); x = newsplit(&par); chan = base64_to_int(x); y = newsplit(&par); if ((chan < 0) || !y[0]) return; /* Woops! pre 1.2.1's send .chat off'ers * too!! */ if (!y[0]) { y[0] = '-'; sock = 0; } else { sock = base64_to_int(y + 1); } i = nextbot(bot); if (i != idx) { /* Ok, garbage from a 1.0g (who uses that * now?) OR raistlin being evil :) */ fake_alert(idx, "direction", bot, "join"); return; } u = get_user_by_handle(userlist, nick); if (u) { simple_snprintf(TBUF, sizeof(TBUF), "@%s", bot); touch_laston(u, TBUF, now); } i = addparty(bot, nick, chan, y[0], sock, par, &i2); botnet_send_join_party(idx, linking, i2); if (i != chan) { if (i >= 0) { chanout_but(-1, i, "*** (%s) %s %s %s.\n", conf.bot->hub ? bot : "[botnet]", nick, "has left the", i ? "channel" : "party line"); } if (!linking) chanout_but(-1, chan, "*** (%s) %s %s %s.\n", conf.bot->hub ? bot : "[botnet]", nick, "has joined the", chan ? "channel" : "party line"); } }
/* part <bot> <nick> <sock> [etc..] */ static void bot_part(int idx, char *par) { char *bot, *nick, *etc; struct userrec *u; int sock, partyidx; int silent = 0; if (bot_flags(dcc[idx].user) & BOT_ISOLATE) return; bot = newsplit(&par); if (bot[0] == '!') { silent = 1; bot++; } nick = newsplit(&par); etc = newsplit(&par); #ifndef NO_OLD_BOTNET if (dcc[idx].u.bot->numver < NEAT_BOTNET) { sock = atoi(etc); silent = 1; } else #endif sock = base64_to_int(etc); if (sock == 0) sock = partysock(bot, nick); u = get_user_by_handle(userlist, nick); if (u) { sprintf(TBUF, "@%s", bot); touch_laston(u, TBUF, now); } if ((partyidx = getparty(bot, sock)) != -1) { if (party[partyidx].chan >= 0) check_tcl_chpt(bot, nick, sock, party[partyidx].chan); if ((dcc[idx].u.bot->numver >= NEAT_BOTNET) && !silent) { register int chan = party[partyidx].chan; if (par[0]) chanout_but(-1, chan, "*** (%s) %s %s %s (%s).\n", bot, nick, NET_LEFTTHE, chan ? "channel" : "party line", par); else chanout_but(-1, chan, "*** (%s) %s %s %s.\n", bot, nick, NET_LEFTTHE, chan ? "channel" : "party line"); } botnet_send_part_party(idx, partyidx, par, silent); remparty(bot, sock); } }
/* Reload the user file from disk */ void reload() { FILE *f = fopen(userfile, "r"); if (f == NULL) { putlog(LOG_MISC, "*", "Can't reload user file!"); return; } fclose(f); noshare = 1; clear_userlist(userlist); noshare = 0; userlist = NULL; loading = 1; checkchans(0); if (!readuserfile(userfile, &userlist)) fatal("User file is missing!", 0); /* ensure we did not lose our internal users */ load_internal_users(); /* make sure I am added and conf.bot->u is set */ add_myself_to_userlist(); if (conf.bot->localhub) add_child_bots(); else if (!conf.bot->hub) add_localhub(); /* Make sure no removed users/bots are still connected. */ check_stale_dcc_users(); for (tand_t* bot = tandbot; bot; bot = bot->next) bot->u = get_user_by_handle(userlist, bot->bot); /* I don't think these will ever be called anyway. */ if (!conf.bot->hub) { Auth::FillUsers(); check_hostmask(); } checkchans(1); loading = 0; var_parse_my_botset(); reaffirm_owners(); hook_read_userfile(); }
static int msg_ident(char *nick, char *host, struct userrec *u, char *par) { char s[UHOSTLEN] = "", s1[UHOSTLEN] = "", *pass = NULL, who[HANDLEN + 1] = ""; struct userrec *u2 = NULL; if (match_my_nick(nick) || (u && u->bot)) return BIND_RET_BREAK; pass = newsplit(&par); if (!par[0]) strlcpy(who, nick, sizeof(who)); else { strlcpy(who, par, sizeof(who)); } bd::String msg; u2 = get_user_by_handle(userlist, who); if (u2 && rfc_casecmp(who, origbotname) && !u2->bot) { /* This could be used as detection... */ if (u_pass_match(u2, "-")) { putlog(LOG_CMDS, "*", "(%s!%s) !*! IDENT %s", nick, host, who); } else if (!u_pass_match(u2, pass)) { putlog(LOG_CMDS, "*", "(%s!%s) !*! failed IDENT %s", nick, host, who); return BIND_RET_BREAK; } else if (u == u2) { notice(nick, "I recognize you there.", DP_HELP); return BIND_RET_BREAK; } else if (u) { msg = bd::String::printf("You're not %s, you're %s.", who, u->handle); notice(nick, msg.c_str(), DP_HELP); return BIND_RET_BREAK; } else { putlog(LOG_CMDS, "*", "(%s!%s) !*! IDENT %s", nick, host, who); simple_snprintf(s, sizeof s, "%s!%s", nick, host); maskaddr(s, s1, 0); /* *!user@host */ msg = bd::String::printf("Added hostmask: %s", s1); notice(nick, msg.c_str(), DP_HELP); addhost_by_handle(who, s1); check_this_user(who, 0, NULL); return BIND_RET_BREAK; } } putlog(LOG_CMDS, "*", "(%s!%s) !*! failed IDENT %s", nick, host, who); return BIND_RET_BREAK; }
static void get_handle_chaninfo(char *handle, char *chname, char *s) { struct userrec *u; struct chanuserrec *ch; u = get_user_by_handle(userlist, handle); if (u == NULL) { s[0] = 0; return; } ch = get_chanrec(u, chname); if (ch == NULL) { s[0] = 0; return; } if (ch->info == NULL) { s[0] = 0; return; } strcpy(s, ch->info); return; }
/* notes <pass> <func> */ static int msg_notes(char *nick, char *host, struct userrec *u, char *par) { char *pwd, *fcn; if (!u) return 0; if (u->flags & (USER_BOT | USER_COMMON)) return 1; if (!par[0]) { dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> INDEX\n", nick, NOTES_USAGE); dprintf(DP_HELP, "NOTICE %s :NOTES <pass> TO <hand> <msg>\n", nick); dprintf(DP_HELP, "NOTICE %s :NOTES <pass> READ <# or ALL>\n", nick); dprintf(DP_HELP, "NOTICE %s :NOTES <pass> ERASE <# or ALL>\n", nick); dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_MAYBE); dprintf(DP_HELP, "NOTICE %s :Ex: NOTES mypass ERASE 2-4;8;16-\n", nick); return 1; } if (!u_pass_match(u, "-")) { /* Do the have a password set? */ pwd = newsplit(&par); if (!u_pass_match(u, pwd)) return 0; } fcn = newsplit(&par); if (!egg_strcasecmp(fcn, "INDEX")) notes_read(u->handle, nick, "+", -1); else if (!egg_strcasecmp(fcn, "READ")) { if (!egg_strcasecmp(par, "ALL")) notes_read(u->handle, nick, "-", -1); else notes_read(u->handle, nick, par, -1); } else if (!egg_strcasecmp(fcn, "ERASE")) { if (!egg_strcasecmp(par, "ALL")) notes_del(u->handle, nick, "-", -1); else notes_del(u->handle, nick, par, -1); } else if (!egg_strcasecmp(fcn, "TO")) { char *to; int i; FILE *f; struct userrec *u2; to = newsplit(&par); if (!par[0]) { dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> TO <hand> <message>\n", nick, NOTES_USAGE); return 0; } u2 = get_user_by_handle(userlist, to); if (!u2) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_USERF_UNKNOWN); return 1; } else if (is_bot(u2)) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_NOTTO_BOT); return 1; } for (i = 0; i < dcc_total; i++) { if ((!egg_strcasecmp(dcc[i].nick, to)) && (dcc[i].type->flags & DCT_GETNOTES)) { int aok = 1; if (dcc[i].type->flags & DCT_CHAT) if (dcc[i].u.chat->away != NULL) aok = 0; if (!(dcc[i].type->flags & DCT_CHAT)) aok = 0; /* Assume non dcc-chat == something weird, so * store notes for later */ if (aok) { dprintf(i, "\007%s [%s]: %s\n", u->handle, NOTES_OUTSIDE, par); dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED); return 1; } } } if (notefile[0] == 0) { dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_UNSUPPORTED); return 1; } f = fopen(notefile, "a"); if (f == NULL) f = fopen(notefile, "w"); if (f == NULL) { dprintf(DP_HELP, "NOTICE %s :%s", nick, NOTES_NOTEFILE_FAILED); putlog(LOG_MISC, "*", "* %s", NOTES_NOTEFILE_UNREACHABLE); return 1; } chmod(notefile, userfile_perm); /* Use userfile permissions. */ fprintf(f, "%s %s %li %s\n", to, u->handle, (long) now, par); fclose(f); dprintf(DP_HELP, "NOTICE %s :%s\n", nick, NOTES_DELIVERED); return 1; } else dprintf(DP_HELP, "NOTICE %s :%s: NOTES <pass> INDEX, READ, ERASE, TO\n", nick, NOTES_USAGE); putlog(LOG_CMDS, "*", "(%s!%s) !%s! NOTES %s %s", nick, host, u->handle, fcn, par[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); } }
/* Dependant on revenge_mode, punish the offender. */ static void punish_badguy(struct chanset_t *chan, char *whobad, struct userrec *u, char *badnick, char *victim, int mevictim, int type) { char reason[1024], ct[81], *kick_msg; memberlist *m; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; m = ismember(chan, badnick); if (!m) return; get_user_flagrec(u, &fr, chan->dname); /* Get current time into a string */ egg_strftime(ct, 7, "%d %b", localtime(&now)); /* Put together log and kick messages */ reason[0] = 0; switch (type) { case REVENGE_KICK: kick_msg = IRC_KICK_PROTECT; simple_sprintf(reason, "kicked %s off %s", victim, chan->dname); break; case REVENGE_DEOP: simple_sprintf(reason, "deopped %s on %s", victim, chan->dname); kick_msg = IRC_DEOP_PROTECT; break; default: kick_msg = "revenge!"; } putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason); /* Set the offender +d */ if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) { char s[UHOSTLEN], s1[UHOSTLEN]; memberlist *mx = NULL; /* Removing op */ if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) { fr.match = FR_CHAN; if (chan_op(fr)) fr.chan &= ~USER_OP; else fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad, reason); } /* ... or just setting to deop */ else if (u) { /* In the user list already, cool :) */ fr.match = FR_CHAN; fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s", ct, reason); putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s); } /* ... or creating new user and setting that to deop */ else { strcpy(s1, whobad); maskaddr(s1, s, chan->ban_type); strcpy(s1, badnick); /* If that handle exists use "badX" (where X is an increasing number) * instead. */ while (get_user_by_handle(userlist, s1)) { if (!strncmp(s1, "bad", 3)) { int i; i = atoi(s1 + 3); simple_sprintf(s1 + 3, "%d", i + 1); } else strcpy(s1, "bad1"); /* Start with '1' */ } userlist = adduser(userlist, s1, s, "-", 0); fr.match = FR_CHAN; fr.chan = USER_DEOP; fr.udef_chan = 0; u = get_user_by_handle(userlist, s1); if ((mx = ismember(chan, badnick))) mx->user = u; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad); set_user(&USERENTRY_COMMENT, u, (void *) s); putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason); } } /* Always try to deop the offender */ if (!mevictim) add_mode(chan, '-', 'o', badnick); /* Ban. Should be done before kicking. */ if (chan->revenge_mode > 2) { char s[UHOSTLEN], s1[UHOSTLEN]; splitnick(&whobad); maskaddr(whobad, s1, chan->ban_type); simple_sprintf(s, "(%s) %s", ct, reason); u_addban(chan, s1, botnetnick, s, now + (60 * chan->ban_time), 0); if (!mevictim && HALFOP_CANDOMODE('b')) { add_mode(chan, '+', 'b', s1); flush_mode(chan, QUICK); } } /* Kick the offender */ if (!mevictim && (chan->revenge_mode > 1) && (!channel_dontkickops(chan) || (!chan_op(fr) && (!glob_op(fr) || chan_deop(fr)))) && !chan_sentkick(m) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m) && (strchr(NOHALFOPS_MODES, 'b') == NULL)))) { dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, badnick, kick_msg); m->flags |= SENTKICK; } }