/* * Copyright (c) 2010 JD Horelick * Rights to this code are as defined in doc/LICENSE. * * DEFCON implementation. * * By default, any setting except 5 will expire after 15 minutes, * to change this, add a defcon_timeout = X; option to the operserv{} * block in your atheme.con. X = amount of time in minutes for a defcon * setting to time out/expire. * */ #include "atheme-compat.h" #define DEFCON_CMODE "R" DECLARE_MODULE_V1 ( "contrib/os_defcon", false, _modinit, _moddeinit, PACKAGE_STRING, "Atheme Development Group " ); static void os_cmd_defcon(sourceinfo_t *si, int parc, char *parv[]); static void defcon_nouserreg(hook_user_register_check_t *hdata); static void defcon_nochanreg(hook_channel_register_check_t *hdatac); static void defcon_useradd(hook_user_nick_t *data); static void defcon_timeoutfunc(void *dummy); static int level = 5; static unsigned int defcon_timeout = 900; static mowgli_eventloop_timer_t *defcon_timer = NULL; command_t os_defcon = { "DEFCON", N_("Implements Defense Condition lockdowns."), PRIV_ADMIN, 1, os_cmd_defcon, { .path = "contrib/defcon" } }; void _modinit(module_t *m) { service_named_bind_command("operserv", &os_defcon); TAINT_ON("Using os_defcon", "Use of os_defcon is unsupported and not recommend. Use only at your own risk."); /* Hooks for all the stuff defcon disables */ hook_add_event("user_can_register"); hook_add_user_can_register(defcon_nouserreg); hook_add_event("channel_can_register"); hook_add_channel_can_register(defcon_nochanreg); hook_add_event("user_add"); hook_add_user_add(defcon_useradd); service_t *svs; svs = service_find("operserv"); add_duration_conf_item("DEFCON_TIMEOUT", &svs->conf_table, 0, &defcon_timeout, "m", 900); } void _moddeinit(module_unload_intent_t intent) { service_named_unbind_command("operserv", &os_defcon); hook_del_user_can_register(defcon_nouserreg); hook_del_channel_can_register(defcon_nochanreg); hook_del_user_add(defcon_useradd); service_t *svs; svs = service_find("operserv"); del_conf_item("DEFCON_TIMEOUT", &svs->conf_table); if (defcon_timer != NULL) mowgli_timer_destroy(base_eventloop, defcon_timer); } static void defcon_nouserreg(hook_user_register_check_t *hdata) { return_if_fail(hdata != NULL); return_if_fail(hdata->si != NULL); if (level < 5) { command_fail(hdata->si, fault_badparams, _("Registrations are currently disabled on this network, please try again later.")); hdata->approved++; } } static void defcon_nochanreg(hook_channel_register_check_t *hdatac) { return_if_fail(hdatac != NULL); return_if_fail(hdatac->si != NULL); if (level < 5) { command_fail(hdatac->si, fault_badparams, _("Registrations are currently disabled on this network, please try again later.")); hdatac->approved++; } } static void defcon_useradd(hook_user_nick_t *data) { user_t *u = data->u; if (!u) return; if (is_internal_client(u)) return; if (level == 1) { slog(LG_INFO, "DEFCON:KLINE: %s!%s@%s", u->nick, u->user, u->host); kline_sts("*", u->user, u->host, 900, "This network is currently not accepting connections, please try again later."); } } static void defcon_svsignore(void) { svsignore_t *svsignore; mowgli_node_t *n, *tn; if (level <= 2) { MOWGLI_ITER_FOREACH(n, svs_ignore_list.head) { svsignore = (svsignore_t *)n->data; if (!strcasecmp(svsignore->mask, "*@*")) return; } slog(LG_INFO, "DEFCON:IGNORE:ADD"); svsignore = svsignore_add("*@*", "DEFCON Level 1 or 2 activated"); svsignore->setby = "DEFCON"; svsignore->settime = CURRTIME; } else if (level >= 3) { MOWGLI_ITER_FOREACH_SAFE(n, tn, svs_ignore_list.head) { svsignore = (svsignore_t *)n->data; if (!strcasecmp(svsignore->mask,"*@*")) { slog(LG_INFO, "DEFCON:IGNORE:REMOVE"); svsignore_delete(svsignore); } } } } static void defcon_forcechanmodes(void) { channel_t *chptr; mowgli_patricia_iteration_state_t state; service_t *svs; char modesetbuf[256]; char modeunsetbuf[256]; svs = service_find("operserv"); if (level <= 3) { snprintf(modesetbuf, sizeof modesetbuf, "+%s", DEFCON_CMODE); slog(LG_INFO, "DEFCON:MODE: %s", modesetbuf); MOWGLI_PATRICIA_FOREACH(chptr, &state, chanlist) { channel_mode_va(svs->me, chptr, 1, modesetbuf); } } else if (level >= 4) { snprintf(modeunsetbuf, sizeof modeunsetbuf, "-%s", DEFCON_CMODE); slog(LG_INFO, "DEFCON:MODE: %s", modeunsetbuf); MOWGLI_PATRICIA_FOREACH(chptr, &state, chanlist) { channel_mode_va(svs->me, chptr, 1, modeunsetbuf); } } } static void defcon_timeoutfunc(void *dummy) { service_t *svs; char buf[BUFSIZE]; svs = service_find("operserv"); level = 5; defcon_svsignore(); defcon_forcechanmodes(); slog(LG_INFO, "DEFCON:TIMEOUT"); snprintf(buf, sizeof buf, "The DEFCON level is now back to normal (\2%d\2). Sorry for any inconvenience this caused.", level); notice_global_sts(svs->me, "*", buf); } static void os_cmd_defcon(sourceinfo_t *si, int parc, char *parv[]) { char *defcon = parv[0]; char buf[BUFSIZE]; if (!defcon) { command_success_nodata(si, _("Defense condition is currently level \2%d\2."), level); return; } level = atoi(defcon); if ((level <= 0) || (level > 5)) { command_fail(si, fault_badparams, _("Defcon level must be between 1 and 5")); level = 5; return; } /* Call the 2 functions that don't use hooks */ defcon_svsignore(); defcon_forcechanmodes(); if (level < 5) { snprintf(buf, sizeof buf, "The DEFCON level has been changed to \2%d\2. We apologize for any inconvenience.", level); if (defcon_timer == NULL) defcon_timer = mowgli_timer_add_once(base_eventloop, "defcon_timeout", defcon_timeoutfunc, NULL, defcon_timeout); } else { snprintf(buf, sizeof buf, "The DEFCON level is now back to normal (\2%d\2). Sorry for any inconvenience this caused.", level); mowgli_timer_destroy(base_eventloop, defcon_timer); defcon_timer = NULL; } notice_global_sts(si->service->me, "*", buf); command_success_nodata(si, _("Defense condition set to level \2%d\2."), level); wallops(_("\2%s\2 set Defense condition to level \2%d\2."), get_oper_name(si), level); logcommand(si, CMDLOG_ADMIN, "DEFCON: \2%d\2", level); } /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs * vim:ts=8 * vim:sw=8 * vim:noexpandtab */