X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/ce9266cf05e4f05cf133db1075095fbb7fcc741d..ffb204b696ed373e9e367d45079c3b725c98efe4:/src/opserv.c diff --git a/src/opserv.c b/src/opserv.c index 63f3787..cd0617f 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -25,12 +25,13 @@ #include "nickserv.h" #include "modcmd.h" #include "modules.h" +#include "proto.h" #include "opserv.h" #include "timeq.h" #include "saxdb.h" #include "shun.h" -#include +#include #ifdef HAVE_SYS_TIMES_H #include @@ -93,6 +94,20 @@ #define KEY_OFFLINE "offline" #define KEY_ROUTINGPLAN "routingplan" #define KEY_ROUTINGPLAN_OPTIONS "routingplan_options" +#define KEY_DEFCON1 "DefCon1" +#define KEY_DEFCON2 "DefCon2" +#define KEY_DEFCON3 "DefCon3" +#define KEY_DEFCON4 "DefCon4" +#define KEY_DEFCON_LEVEL "DefConLevel" +#define KEY_DEFCON_CHANMODES "DefConChanModes" +#define KEY_DEFCON_SESSION_LIMIT "DefConSessionLimit" +#define KEY_DEFCON_TIMEOUT "DefConTimeOut" +#define KEY_DEFCON_GLOBAL "GlobalOnDefcon" +#define KEY_DEFCON_GLOBAL_MORE "GlobalOnDefconMore" +#define KEY_DEFCON_MESSAGE "DefconMessage" +#define KEY_DEFCON_OFF_MESSAGE "DefConOffMessage" +#define KEY_DEFCON_GLINE_DURATION "DefConGlineExpire" +#define KEY_DEFCON_GLINE_REASON "DefConGlineReason" /* Routing karma values: */ /* What value we start out with when new servers are added: */ @@ -159,19 +174,30 @@ static const struct message_entry msgtab[] = { { "OSMSG_HOP_DONE", "Halfopped the requested lusers." }, { "OSMSG_HOPALL_DONE", "Halfopped everyone on $b%s$b." }, { "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" }, - { "OSMSG_WHOIS_NICK", "Nick : %s" }, - { "OSMSG_WHOIS_HOST", "Host : %s@%s" }, - { "OSMSG_WHOIS_FAKEHOST", "Fakehost : %s" }, - { "OSMSG_WHOIS_CRYPT_HOST", "Crypt Host : %s" }, - { "OSMSG_WHOIS_CRYPT_IP", "Crypt IP : %s" }, - { "OSMSG_WHOIS_IP", "Real IP : %s" }, - { "OSMSG_WHOIS_MODES", "Modes : +%s " }, - { "OSMSG_WHOIS_INFO", "Info : %s" }, - { "OSMSG_WHOIS_NUMERIC", "Numnick : %s" }, - { "OSMSG_WHOIS_SERVER", "Server : %s" }, - { "OSMSG_WHOIS_NICK_AGE", "Nick Age : %s" }, - { "OSMSG_WHOIS_ACCOUNT", "Account : %s" }, - { "OSMSG_WHOIS_CHANNELS", "Channels : %s" }, + { "OSMSG_WHOIS_NICK", "Nick : %s" }, + { "OSMSG_WHOIS_HOST", "Host : %s@%s" }, + { "OSMSG_WHOIS_FAKEHOST", "Fakehost : %s" }, + { "OSMSG_WHOIS_CRYPT_HOST", "Crypt Host : %s" }, + { "OSMSG_WHOIS_CRYPT_IP", "Crypt IP : %s" }, + { "OSMSG_WHOIS_IP", "Real IP : %s" }, + { "OSMSG_WHOIS_COUNTRY", "Country : %s" }, + { "OSMSG_WHOIS_COUNTRY_CODE","Country Code : %s" }, + { "OSMSG_WHOIS_CITY", "City : %s" }, + { "OSMSG_WHOIS_REGION", "Region/State : %s" }, + { "OSMSG_WHOIS_POSTAL_CODE","Postal Code : %s" }, + { "OSMSG_WHOIS_LATITUDE", "Latitude : %f" }, + { "OSMSG_WHOIS_LONGITUDE", "Longitude : %f" }, + { "OSMSG_WHOIS_MAP", "Map : %s" }, + { "OSMSG_WHOIS_DMA_CODE", "DMA Code : %d" }, + { "OSMSG_WHOIS_AREA_CODE", "Area Code : %d" }, + { "OSMSG_WHOIS_MODES", "Modes : +%s " }, + { "OSMSG_WHOIS_INFO", "Info : %s" }, + { "OSMSG_WHOIS_NUMERIC", "Numnick : %s" }, + { "OSMSG_WHOIS_SERVER", "Server : %s" }, + { "OSMSG_WHOIS_NICK_AGE", "Nick Age : %s" }, + { "OSMSG_WHOIS_ACCOUNT", "Account : %s" }, + { "OSMSG_WHOIS_PRIVS", "IRCd Privs : %s" }, + { "OSMSG_WHOIS_CHANNELS", "Channels : %s" }, { "OSMSG_WHOIS_HIDECHANS", "Channel list omitted for your sanity." }, { "OSMSG_UNBAN_DONE", "Ban(s) removed from channel %s." }, { "OSMSG_CHANNEL_VOICED", "All users on %s voiced." }, @@ -362,11 +388,43 @@ static const struct message_entry msgtab[] = { { "OSMSG_INVALID_REGEX", "Invalid regex: %s: %s (%d)" }, { "OSMSG_TRACK_DISABLED", "Tracking is not currently compiled into X3" }, { "OSMSG_MAXUSERS_RESET", "Max clients has been reset to $b%d$b" }, + + { "OSMSG_DEFCON_INVALID", "DefCon level %d is invalid, please choose a value between 1 and 5" }, + { "OSMSG_DEFCON_ALLOWING_ALL", "DefCon is at level 5 and allowing everything" }, + { "OSMSG_DEFCON_DISALLOWING", "DefCon is at level %d and enforcing:" }, + { "OSMSG_DEFCON_NO_NEW_CHANNELS", "No Channel Registrations" }, + { "OSMSG_DEFCON_NO_NEW_NICKS", "No Nickname/Account Registrations" }, + { "OSMSG_DEFCON_NO_MODE_CHANGE", "No Channel Mode Changes" }, + { "OSMSG_DEFCON_NO_NEW_CLIENTS", "No New Clients" }, + { "OSMSG_DEFCON_FORCE_CHANMODES", "Forcing Channel Mode(s): %s" }, + { "OSMSG_DEFCON_REDUCE_SESSION", "Forcing Reduced Session: %d" }, + { "OSMSG_DEFCON_OPER_ONLY", "Allowing Services Communication With Opers Only" }, + { "OSMSG_DEFCON_SILENT_OPER_ONLY", "Allowing Services Communication With Opers Only AND Silently Ignoring Regular Users" }, + { "OSMSG_DEFCON_GLINE_NEW_CLIENTS", "Glining New Clients" }, + { "OSMSG_DEFCON_SHUN_NEW_CLIENTS", "Shunning New Clients" }, + { "OSMSG_DEFCON_NO_NEW_MEMOS", "Disallowing New Memos" }, + + { "OSMSG_PRIV_UNKNOWN", "Unknown privilege flag %s, see /msg $O HELP PRIVFLAGS for a flag list" }, + { "OSMSG_PRIV_SET", "Privilege flag %s has been %sset" }, + { NULL, NULL } }; #define OPSERV_SYNTAX() svccmd_send_help_brief(user, opserv, cmd) +int DefConLevel = 5; +int DefCon[6]; +int DefConTimeOut; +int GlobalOnDefcon = 0; +int GlobalOnDefconMore = 0; +int DefConGlineExpire; +int DefConModesSet = 0; +unsigned int DefConSessionLimit; +char *DefConChanModes; +char *DefConGlineReason; +char *DefConMessage; +char *DefConOffMessage; + extern void add_track_user(struct userNode *user); typedef int (*discrim_search_func)(struct userNode *match, void *extra); @@ -524,6 +582,212 @@ opserv_free_user_alert(void *data) #define opserv_alert(format...) do { if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel , opserv , ## format); } while (0) +char *defconReverseModes(const char *modes) +{ + char *newmodes = NULL; + unsigned int i = 0; + if (!modes) { + return NULL; + } + if (!(newmodes = malloc(sizeof(char) * strlen(modes) + 1))) { + return NULL; + } + for (i = 0; i < strlen(modes); i++) { + if (modes[i] == '+') + newmodes[i] = '-'; + else if (modes[i] == '-') + newmodes[i] = '+'; + else + newmodes[i] = modes[i]; + } + newmodes[i] = '\0'; + return newmodes; +} + +int checkDefCon(int level) +{ + return DefCon[DefConLevel] & level; +} + +void showDefConSettings(struct userNode *user, struct svccmd *cmd) +{ + if (DefConLevel == 5) { + reply("OSMSG_DEFCON_ALLOWING_ALL"); + return; + } else + reply("OSMSG_DEFCON_DISALLOWING", DefConLevel); + + if (checkDefCon(DEFCON_NO_NEW_CHANNELS)) + reply("OSMSG_DEFCON_NO_NEW_CHANNELS"); + + if (checkDefCon(DEFCON_NO_NEW_NICKS)) + reply("OSMSG_DEFCON_NO_NEW_NICKS"); + + if (checkDefCon(DEFCON_NO_MODE_CHANGE)) + reply("OSMSG_DEFCON_NO_MODE_CHANGE"); + + if (checkDefCon(DEFCON_FORCE_CHAN_MODES) && (DefConChanModes)) + reply("OSMSG_DEFCON_FORCE_CHANMODES", DefConChanModes); + + if (checkDefCon(DEFCON_REDUCE_SESSION)) + reply("OSMSG_DEFCON_REDUCE_SESSION", DefConSessionLimit); + + if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) + reply("OSMSG_DEFCON_NO_NEW_CLIENTS"); + + if (checkDefCon(DEFCON_OPER_ONLY)) + reply("OSMSG_DEFCON_OPER_ONLY"); + + if (checkDefCon(DEFCON_SILENT_OPER_ONLY)) + reply("OSMSG_DEFCON_SILENT_OPER_ONLY"); + + if (checkDefCon(DEFCON_GLINE_NEW_CLIENTS)) + reply("OSMSG_DEFCON_GLINE_NEW_CLIENTS"); + + if (checkDefCon(DEFCON_SHUN_NEW_CLIENTS)) + reply("OSMSG_DEFCON_SHUN_NEW_CLIENTS"); + + if (checkDefCon(DEFCON_NO_NEW_MEMOS)) + reply("OSMSG_DEFCON_NO_NEW_MEMOS"); + + return; +} + +void do_mass_mode(char *modes) +{ + dict_iterator_t it; + + if (!modes) + return; + + for (it = dict_first(channels); it; it = iter_next(it)) { + struct chanNode *chan = iter_data(it); + + irc_mode(opserv, chan, modes); + } + +} + +void DefConProcess(struct userNode *user) +{ + char *newmodes; + + if (GlobalOnDefcon) + global_message_args(MESSAGE_RECIPIENT_LUSERS, "DEFCON_NETWORK_CHANGED", DefConLevel); + + if (GlobalOnDefconMore && GlobalOnDefcon) + global_message(MESSAGE_RECIPIENT_LUSERS, DefConMessage); + + if ((DefConLevel == 5) && !GlobalOnDefconMore && !GlobalOnDefcon) + global_message(MESSAGE_RECIPIENT_LUSERS, DefConOffMessage); + + if (user) + global_message_args(MESSAGE_RECIPIENT_OPERS, "DEFCON_OPER_LEVEL_CHANGE", user->nick, DefConLevel); + else + global_message_args(MESSAGE_RECIPIENT_OPERS, "DEFCON_TIMEOUT_LEVEL_CHANGE", DefConLevel); + + if (checkDefCon(DEFCON_FORCE_CHAN_MODES)) { + if (DefConChanModes && !DefConModesSet) { + if (DefConChanModes[0] == '+' || DefConChanModes[0] == '-') { + do_mass_mode(DefConChanModes); + DefConModesSet = 1; + } + } + } else { + if (DefConChanModes && (DefConModesSet != 0)) { + if (DefConChanModes[0] == '+' || DefConChanModes[0] == '-') { + if ((newmodes = defconReverseModes(DefConChanModes))) { + do_mass_mode(newmodes); + free(newmodes); + } + DefConModesSet = 0; + } + } + } + + return; +} + +void +defcon_timeout(UNUSED_ARG(void *data)) +{ + DefConLevel = 5; + DefConProcess(NULL); +} + +static MODCMD_FUNC(cmd_defcon) +{ + if ((argc < 2) || (atoi(argv[1]) == DefConLevel)) { + showDefConSettings(user, cmd); + return 1; + } + + if ((atoi(argv[1]) < 1) || (atoi(argv[1]) > 5)) { + reply("OSMSG_DEFCON_INVALID", atoi(argv[1])); + return 0; + } + + DefConLevel = atoi(argv[1]); + showDefConSettings(user, cmd); + + if (DefConTimeOut > 0) { + timeq_del(0, defcon_timeout, NULL, TIMEQ_IGNORE_DATA & TIMEQ_IGNORE_WHEN); + timeq_add(now + DefConTimeOut, defcon_timeout, NULL); + } + + DefConProcess(user); + return 1; +} + +/* TODO +static MODCMD_FUNC(cmd_privallow) +{ +//privallow servername/username +/-flag (global is set in conf) +} + +static MODCMD_FUNC(cmd_privdissallow) +{ +//privdisallow servername/username +/-flag (global is set in conf) +} + +static MODCMD_FUNC(cmd_privlist) +{ +//privlist servername/user (global with none) +} +*/ + +static MODCMD_FUNC(cmd_privset) +{ + struct userNode *target; + char *flag; + int add = PRIV_ADD; + + flag = argv[2]; + if (*flag == '-') { + add = PRIV_DEL; + flag++; + } else if (*flag == '+') { + add = PRIV_ADD; + flag++; + } + + target = GetUserH(argv[1]); + if (!target) { + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; + } + + if (check_priv(flag)) { + irc_privs(target, flag, add); + reply("OSMSG_PRIV_SET", argv[2], (add == 1) ? "" : "un"); + } else { + reply("OSMSG_PRIV_UNKNOWN", argv[2]); + return 0; + } + + return 1; +} + /* A lot of these commands are very similar to what ChanServ can do, * but OpServ can do them even on channels that aren't registered. */ @@ -667,9 +931,7 @@ static MODCMD_FUNC(cmd_warn) dict_insert(opserv_chan_warn, strdup(argv[1]), reason); reply("OSMSG_WARN_ADDED", argv[1], reason); if (dict_find(channels, argv[1], NULL)) { - message = alloca(strlen(reason) + strlen(argv[1]) + 55); - sprintf(message, "Channel activity warning for channel %s: %s", argv[1], reason); - global_message(MESSAGE_RECIPIENT_OPERS, message); + global_message_args(MESSAGE_RECIPIENT_OPERS, "OSMSG_CHANNEL_ACTIVITY_WARN" argv[1], reason); } return 1; } @@ -1558,6 +1820,32 @@ static MODCMD_FUNC(cmd_whois) reply("OSMSG_WHOIS_CRYPT_HOST", target->crypthost); reply("OSMSG_WHOIS_CRYPT_IP", target->cryptip); reply("OSMSG_WHOIS_IP", irc_ntoa(&target->ip)); + + if (target->city) { + reply("OSMSG_WHOIS_COUNTRY", target->country_name); + reply("OSMSG_WHOIS_COUNTRY_CODE", target->country_code); + reply("OSMSG_WHOIS_CITY", target->city); + reply("OSMSG_WHOIS_REGION", target->region); + + reply("OSMSG_WHOIS_POSTAL_CODE", target->postal_code); + reply("OSMSG_WHOIS_LATITUDE", target->latitude); + reply("OSMSG_WHOIS_LONGITUDE", target->longitude); + /* Only show a map url if we have a city, latitude and longitude. + * Theres not much point of latitude and longitude coordinates are + * returned but no city, the coordinates are useless. + */ + if (target->latitude && target->longitude && target->city) { + char map_url[MAXLEN]; + snprintf(map_url, sizeof(map_url), "http://www.mapquest.com/maps/map.adp?searchtype=address&formtype=address&latlongtype=decimal&latitude=%f&longitude=%f", + target->latitude, target->longitude); + reply("OSMSG_WHOIS_MAP", map_url); + } + reply("OSMSG_WHOIS_DMA_CODE", target->dma_code); + reply("OSMSG_WHOIS_AREA_CODE", target->area_code); + } else if (target->country_name) { + reply("OSMSG_WHOIS_COUNTRY", target->country_name); + } + if (target->modes) { bpos = 0; #define buffer_cat(str) (herelen = strlen(str), memcpy(buffer+bpos, str, herelen), bpos += herelen) @@ -1587,6 +1875,9 @@ static MODCMD_FUNC(cmd_whois) #endif reply("OSMSG_WHOIS_SERVER", target->uplink->name); reply("OSMSG_WHOIS_ACCOUNT", (target->handle_info ? target->handle_info->handle : "Not authenticated")); + + reply("OSMSG_WHOIS_PRIVS", client_report_privs(target)); + intervalString(buffer, now - target->timestamp, user->handle_info); reply("OSMSG_WHOIS_NICK_AGE", buffer); if (target->channels.used <= MAX_CHANNELS_WHOIS) @@ -2172,12 +2463,33 @@ opserv_new_user_check(struct userNode *user) } } + if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) { + irc_kill(opserv, user, DefConGlineReason); + return 0; + } + + if ( (checkDefCon(DEFCON_GLINE_NEW_CLIENTS) || checkDefCon(DEFCON_SHUN_NEW_CLIENTS)) && !IsOper(user)) { + char target[IRC_NTOP_MAX_SIZE + 3] = { '*', '@', '\0' }; + + strcpy(target + 2, user->hostname); + if (checkDefCon(DEFCON_GLINE_NEW_CLIENTS)) + gline_add(opserv->nick, target, DefConGlineExpire, DefConGlineReason, now, 1, 0); + else if (checkDefCon(DEFCON_SHUN_NEW_CLIENTS)) + shun_add(opserv->nick, target, DefConGlineExpire, DefConGlineReason, now, 1); + + return 0; + } + /* Only warn or G-line if there's an untrusted max and their IP is sane. */ if (opserv_conf.untrusted_max && irc_in_addr_is_valid(user->ip) && !irc_in_addr_is_loopback(user->ip)) { struct trusted_host *th = dict_find(opserv_trusted_hosts, addr, NULL); unsigned int limit = th ? th->limit : opserv_conf.untrusted_max; + + if (checkDefCon(DEFCON_REDUCE_SESSION) && !th) + limit = DefConSessionLimit; + if (!limit) { /* 0 means unlimited hosts */ } else if (ohi->clients.used == limit) { @@ -2269,9 +2581,7 @@ opserv_channel_check(struct chanNode *newchan) } /* if ((warning = dict_find(opserv_chan_warn, newchan->name, NULL))) { - char message[MAXLEN]; - snprintf(message, sizeof(message), "Channel activity warning for channel %s: %s", newchan->name, warning); - global_message(MESSAGE_RECIPIENT_OPERS, message); + global_message_args(MESSAGE_RECIPIENT_OPERS, "OSMSG_CHANNEL_ACTIVITY_WARN", newchan->name, warning); } */ @@ -2755,6 +3065,10 @@ routing_connect_server(char *server, int port, struct server *to) wc->server = strdup(server); wc->target = strdup(to->name); + /* Just to make sure there isn't one left hanging + * if 2 connections are attempted at once.. + * */ + routing_delete_connect_timer(server); dict_insert(opserv_waiting_connections, strdup(server), wc); timeq_add(now + ROUTING_CONNECT_TIMEOUT, routing_connect_timeout, wc); @@ -5989,6 +6303,48 @@ opserv_conf_read(void) policer_params_set(pp, "drain-rate", "3"); if ((child = database_get_data(conf_node, KEY_NEW_USER_POLICER, RECDB_OBJECT))) dict_foreach(child, set_policer_param, pp); + + /* Defcon configuration */ + DefCon[0] = 0; + str = database_get_data(conf_node, KEY_DEFCON1, RECDB_QSTRING); + DefCon[1] = str ? atoi(str) : 415; + str = database_get_data(conf_node, KEY_DEFCON2, RECDB_QSTRING); + DefCon[2] = str ? atoi(str) : 159; + str = database_get_data(conf_node, KEY_DEFCON3, RECDB_QSTRING); + DefCon[3] = str ? atoi(str) : 31; + str = database_get_data(conf_node, KEY_DEFCON4, RECDB_QSTRING); + DefCon[4] = str? atoi(str) : 23; + DefCon[5] = 0; + + str = database_get_data(conf_node, KEY_DEFCON_LEVEL, RECDB_QSTRING); + DefConLevel = str ? atoi(str) : 5; + + str = database_get_data(conf_node, KEY_DEFCON_CHANMODES, RECDB_QSTRING); + DefConChanModes = str ? strdup(str) : "+r"; + + str = database_get_data(conf_node, KEY_DEFCON_SESSION_LIMIT, RECDB_QSTRING); + DefConSessionLimit = str ? atoi(str) : 2; + + str = database_get_data(conf_node, KEY_DEFCON_TIMEOUT, RECDB_QSTRING); + DefConTimeOut = str ? ParseInterval(str) : 900; + + str = database_get_data(conf_node, KEY_DEFCON_GLINE_DURATION, RECDB_QSTRING); + DefConGlineExpire = str ? ParseInterval(str) : 300; + + str = database_get_data(conf_node, KEY_DEFCON_GLOBAL, RECDB_QSTRING); + GlobalOnDefcon = str ? atoi(str) : 0; + + str = database_get_data(conf_node, KEY_DEFCON_GLOBAL_MORE, RECDB_QSTRING); + GlobalOnDefconMore = str ? atoi(str) : 0; + + str = database_get_data(conf_node, KEY_DEFCON_MESSAGE, RECDB_QSTRING); + DefConMessage = str ? strdup(str) : "Put your message to send your users here. Dont forget to uncomment GlobalOnDefconMore"; + + str = database_get_data(conf_node, KEY_DEFCON_OFF_MESSAGE, RECDB_QSTRING); + DefConOffMessage = str? strdup(str) : "Services are now back to normal, sorry for any inconvenience"; + + str = database_get_data(conf_node, KEY_DEFCON_GLINE_REASON, RECDB_QSTRING); + DefConGlineReason = str ? strdup(str) : "This network is currently not accepting connections, please try again later"; } /* lame way to export opserv_conf value to nickserv.c ... */ @@ -6097,6 +6453,7 @@ init_opserv(const char *nick) opserv_define_func("DELTRUST", cmd_deltrust, 800, 0, 2); opserv_define_func("DEOP", cmd_deop, 100, 2, 2); opserv_define_func("DEOPALL", cmd_deopall, 400, 2, 0); + opserv_define_func("DEFCON", cmd_defcon, 900, 0, 0); opserv_define_func("DEHOP", cmd_dehop, 100, 2, 2); opserv_define_func("DEHOPALL", cmd_dehopall, 400, 2, 0); opserv_define_func("DEVOICEALL", cmd_devoiceall, 300, 2, 0); @@ -6131,6 +6488,7 @@ init_opserv(const char *nick) opserv_define_func("HOP", cmd_hop, 100, 2, 2); opserv_define_func("HOPALL", cmd_hopall, 400, 2, 0); opserv_define_func("MAP", cmd_stats_links, 0, 0, 0); + opserv_define_func("PRIVSET", cmd_privset, 900, 0, 3); opserv_define_func("PART", cmd_part, 601, 0, 2); opserv_define_func("QUERY", cmd_query, 0, 0, 0); opserv_define_func("RAW", cmd_raw, 999, 0, 2);