From: Chris Porter Date: Sun, 23 Oct 2016 17:20:42 +0000 (+0100) Subject: Merge pull request #51 from retropc/chanserv-live X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/commitdiff_plain/9684145a15443492690d9faf4687e4dc721fe8e3?hp=1c3fa815d7a695533dd728a27ea08110ad01c0b3 Merge pull request #51 from retropc/chanserv-live Merge master into chanserv-live --- diff --git a/MODULES b/MODULES index a47506c0..ab1fa6b4 100644 --- a/MODULES +++ b/MODULES @@ -60,7 +60,9 @@ module lets opers use arbitrary account names and IDs. chanfix ------- -Keeps track of channel ops and can be used to re-op opless channels. +Keeps track of channel ops and can be used to re-op opless channels. However, +since its chanfixing commands require oper, it should be paired with the request +module, which provides REQUESTOP for users and uses chanfix internally. chanserv -------- @@ -68,6 +70,28 @@ chanserv This is QuakeNet's channel service (Q). In order to load this module you will need also need to load the pqsql module. +Configuration: + +[chanserv] +nick=Q +user=TheQBot +host=some.host +realname=ChannelService +account=Q +secret= +ticketsecret= +createaccountsecret= + +secret can be an arbitrary string, at most 128 characters long. If not set, Q +will generate a random one and not write it to the configuration. + +ticketsecret can be an arbitrary string, at most 256 characters long and must +be set for ticket auth to work. Note that you must implement ticket auth +yourself if you wish to use it. + +createaccountsecret must be a hex string of exact 128 characters (i.e. 64 bytes +of hex-encoded data). + pqsql ----- @@ -80,6 +104,7 @@ host=127.0.0.1 port=5432 username=gunnar password=changeme +#database=newserv dbapi2 ------ @@ -134,6 +159,8 @@ have a look at the labspace repository at http://hg.quakenet.org/lua-labspace/ Configuration: [lua] +#botnick=U +#scriptsuffix=.lua scriptdir=./luascripts script=labspace @@ -152,6 +179,24 @@ nickwatch Implements event-based nicksearch queries. +nterfacer +--------- + +Implements a protocol that allows external services to communicate with this +newserv instance. + +You will need to implement your own client if you wish to use this. + +Configuration: + +[nterfacer] +#debug=0 +# listening port +#port=2438 +# Each individual permit/allowed client must have a hostname and password +hostname=127.0.0.1 +password=changeme + miscreply --------- @@ -184,6 +229,20 @@ proxyscan Does on-connect proxy scans and glines open proxies. +Configuration: + +[proxyscan] +# listen port +port=9999 +# bind IP +ip=127.0.0.1 +maxscans=200 +rescaninterval=3600 +nick=P +user=proxyscan +host=some.host +realname=Proxyscan + request ------- @@ -200,6 +259,11 @@ Configuration: #sserver=spamscan.quakenet.org #qnick=Q #qserver=cserve.quakenet.org +#auth=R +#authid=1780711 +# Auth to S +#user=R +#password=bla serverlist ---------- @@ -207,6 +271,15 @@ serverlist Implements the serverlist command which shows various information about connected servers (including their network latency). +Configuration: + +[serverlist] +q_server=CServe.quakenet.org +s_server=services2.uk.quakenet.org +service_re=^services\d*\..*$ +hub_re=^hub\d*\..*$ +not_client_re=^(testserv\d*\.).*$ + settime ------- @@ -218,11 +291,52 @@ splitlist Keeps track of servers that were lost during a netsplit. This module is used by chanfix to determine when it shouldn't re-op users. +ticketauth +---------- + +Provides ticketauth, a way to authenticate to noperserv using a one-time +ticket. It works similar to the ticket auth in chanserv. + +If you want to use ticketauth, you'll need to implement a method to issue +tickets using the shared secret yourself. + +Configuration: + +[ticketauth] +sharedsecret= + +sharedsecret is an arbitrary string of at most 512 characters. + trojanscan ---------- Used to find and gline drones on the network. +Note that this module uses MySQL exclusively and in a blocking manner, so that +a hanging connection to the MySQL database can and will block all network I/O. +For this reason, you will probably want a newserv instance dedicated to running +trojanscan if you wish to run it. + +Configuration: + +[trojanscan] +nick=T +ident=trojanscan +hostname=trojanscan.quakenet.org +realname=Trojanscan v2.73 +authname=T +# MySQL credentials +dbhost=localhost +dbport=3306 +dbuser=moo +dbpass=changeme +db=moo +maxchans=750 +cycletime=16000 +parttime=2600 +maxusers=20 +minchansize=150 + trusts ------ @@ -253,7 +367,7 @@ server=gnb.netsplit.net,changeme server=test.gnb.netsplit.net,changeme You can use the QuakeNet IAuth daemon available at -http://hg.quakenet.org/iauthd/ to enforce connection limits using IAuth rather +https://hg.quakenet.org/iauthd/ to enforce connection limits using IAuth rather than g:lines. whowas, whowas_channels @@ -265,6 +379,11 @@ nicks and by newsearch. The whowas_channels module optionally keeps track of which channels users were on. +Configuration: + +[whowas] +maxentries=1000 + xsb --- diff --git a/a4stats/a4stats_db.c b/a4stats/a4stats_db.c index af7ae917..dbcbe715 100644 --- a/a4stats/a4stats_db.c +++ b/a4stats/a4stats_db.c @@ -14,6 +14,9 @@ #define CLEANUP_INACTIVE_DAYS 30 /* disable channels where nothing happened for this many days */ #define CLEANUP_DELETE_DAYS 5 /* delete data for channels that have been disabled for this many days */ +#define A4STATS_DB_TOLOWER(x) "translate(lower(" x "), E'[]\\\\~', '{}|^')" +#define A4STATS_DB_EQ_NOCASE(x, y) A4STATS_DB_TOLOWER(x) " = " A4STATS_DB_TOLOWER(y) + MODULE_VERSION(""); DBAPIConn *a4statsdb; @@ -316,7 +319,7 @@ static int a4stats_lua_add_line(lua_State *ps) { channel = lua_tostring(ps, 1); hour = lua_tonumber(ps, 2); - snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE name = ?", hour, hour); + snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), hour, hour); a4statsdb->squery(a4statsdb, query, "Ts", "channels", channel); @@ -466,7 +469,7 @@ static int a4stats_lua_enable_channel(lua_State *ps) { LUA_RETURN(ps, LUA_FAIL); a4statsdb->squery(a4statsdb, "INSERT INTO ? (name, timestamp) VALUES (?, ?)", "Tst", "channels", lua_tostring(ps, 1), time(NULL)); - a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE name = ?", "Ts", "channels", lua_tostring(ps, 1)); + a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Ts", "channels", lua_tostring(ps, 1)); LUA_RETURN(ps, LUA_OK); } @@ -475,7 +478,7 @@ static int a4stats_lua_disable_channel(lua_State *ps) { if (!lua_isstring(ps, 1)) LUA_RETURN(ps, LUA_FAIL); - a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE name = ?", "Tts", "channels", time(NULL), lua_tostring(ps, 1)); + a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Tts", "channels", time(NULL), lua_tostring(ps, 1)); LUA_RETURN(ps, LUA_OK); } @@ -490,7 +493,7 @@ static int a4stats_lua_set_privacy(lua_State *ps) { channel = lua_tostring(ps, 1); privacy = lua_tonumber(ps, 2); - a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE name = ?", "TUs", "channels", privacy, channel); + a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "TUs", "channels", privacy, channel); LUA_RETURN(ps, LUA_OK); } diff --git a/configure.ini b/configure.ini index 6d3ded79..7bb1f2fc 100644 --- a/configure.ini +++ b/configure.ini @@ -78,7 +78,7 @@ fakeusers= raw= nickwatch= patrol= -regexgline=pcre mysql +regexgline=pcre dbapi facepalm= a4stats=lua rbl= diff --git a/depmod.pl b/depmod.pl index 9c53672b..10040013 100755 --- a/depmod.pl +++ b/depmod.pl @@ -41,6 +41,8 @@ for (@arglist) { next if ($sym eq "_init"); next if ($sym eq "_fini"); next if ($sym eq "_version"); + next if ($sym eq "__bss_start"); + next if ($sym eq "_end"); if ($type eq "U") { push @{$reqsyms{$modname}}, $sym; diff --git a/helpmod2/hcommands.c b/helpmod2/hcommands.c index d7544074..57b9e9a3 100644 --- a/helpmod2/hcommands.c +++ b/helpmod2/hcommands.c @@ -2386,7 +2386,7 @@ static void helpmod_cmd_ticket (huser *sender, channel* returntype, char* ostr, helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s is considered improper and not worthy of a ticket", argv[1]); return; } - if (huser_get_level(husr) > H_PEON) + if (huser_get_level(husr) > H_FRIEND) { helpmod_reply(sender, returntype, "Cannot issue a ticket: User %s does not require a ticket", argv[1]); return; diff --git a/nickrate/nickrate.c b/nickrate/nickrate.c index 6da2f43c..01cfb38a 100644 --- a/nickrate/nickrate.c +++ b/nickrate/nickrate.c @@ -63,13 +63,13 @@ int nr_openlistensocket(int portnum) { unsigned int opt=1; if ((fd=socket(AF_INET,SOCK_STREAM,0))==-1) { - Error("proxyscan",ERR_ERROR,"Unable to open listening socket (%d).",errno); + Error("nickrate",ERR_ERROR,"Unable to open listening socket (%d).",errno); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof(opt))!=0) { close(fd); - Error("proxyscan",ERR_ERROR,"Unable to set SO_REUSEADDR on listen socket."); + Error("nickrate",ERR_ERROR,"Unable to set SO_REUSEADDR on listen socket."); return -1; } @@ -80,7 +80,7 @@ int nr_openlistensocket(int portnum) { if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) { close(fd); - Error("proxyscan",ERR_ERROR,"Unable to bind listen socket (%d).",errno); + Error("nickrate",ERR_ERROR,"Unable to bind listen socket (%d).",errno); return -1; } @@ -88,7 +88,7 @@ int nr_openlistensocket(int portnum) { if (ioctl(fd, FIONBIO, &opt)!=0) { close(fd); - Error("proxyscan",ERR_ERROR,"Unable to set listen socket non-blocking."); + Error("nickrate",ERR_ERROR,"Unable to set listen socket non-blocking."); return -1; } diff --git a/pqsql/pqsql-dbapi2.c b/pqsql/pqsql-dbapi2.c index fd6c1bd6..97cb0dc8 100644 --- a/pqsql/pqsql-dbapi2.c +++ b/pqsql/pqsql-dbapi2.c @@ -22,7 +22,7 @@ static int dbapi2_adapter_quotestring(const DBAPIConn *db, char *buf, size_t buf size_t esclen; esclen = dbescapestring(xbuf, (char *)data, len); - sbaddstr(&b, "E'"); + sbaddchar(&b, '\''); sbaddstrlen(&b, xbuf, esclen); sbaddchar(&b, '\''); diff --git a/splitlist/splitlist.c b/splitlist/splitlist.c index 29859c31..4789a0ea 100644 --- a/splitlist/splitlist.c +++ b/splitlist/splitlist.c @@ -12,7 +12,6 @@ array splitlist; static void sphook_newserver(int hook, void *arg); static void sphook_lostserver(int hook, void *arg); -static void sp_addsplit(const char *name, time_t ts, flag_t flags); void _init(void) { registerhook(HOOK_SERVER_NEWSERVER, &sphook_newserver); @@ -72,7 +71,7 @@ void sp_deletesplit(const char *name) { } } -static void sp_addsplit(const char *name, time_t ts, flag_t type) { +void sp_addsplit(const char *name, time_t ts, flag_t type) { int slot; splitserver *srv; diff --git a/splitlist/splitlist.h b/splitlist/splitlist.h index eaa2e0ee..21e07992 100644 --- a/splitlist/splitlist.h +++ b/splitlist/splitlist.h @@ -17,10 +17,10 @@ extern array splitlist; void sp_deletesplit(const char *name); int sp_countsplitservers(flag_t orflags); -/* I don't see why these are exported... */ +/* I don't see why this is exported... */ /* int sp_issplitserver(const char *name); -void sp_addsplit(const char *name, time_t ts); */ +void sp_addsplit(const char *name, time_t ts, flag_t type); #endif /* __SPLITLIST_H */ diff --git a/splitlist/splitlist_commands.c b/splitlist/splitlist_commands.c index fc8a4753..6cdce56d 100644 --- a/splitlist/splitlist_commands.c +++ b/splitlist/splitlist_commands.c @@ -1,25 +1,44 @@ /* oper commands for the splitlist */ +#include +#include + #include "../lib/irc_string.h" #include "../irc/irc.h" +#include "../irc/irc_config.h" #include "../splitlist/splitlist.h" #include "../serverlist/serverlist.h" #include "../control/control.h" #include "../lib/version.h" +#include "../lib/flags.h" MODULE_VERSION(""); int spcmd_splitlist(void *source, int cargc, char **cargv); int spcmd_splitdel(void *source, int cargc, char **cargv); +int spcmd_splitadd(void *source, int cargc, char **cargv); void _init(void) { registercontrolhelpcmd("splitlist", NO_STAFF, 0, &spcmd_splitlist, "Usage: splitlist\nLists servers currently split from the network."); registercontrolcmd("splitdel", 10, 1, &spcmd_splitdel); + registercontrolhelpcmd("splitadd", 10, 3, &spcmd_splitadd, + "Usage: splitadd [+flags] [split time as unix timestamp]\n" + " Adds a server as split from the network.\n" + " Flags:\n" + " +c: Client server\n" + " +h: Hub server\n" + " +s: Service\n" + " +Q: Q/CServe\n" + " +S: S/spamscan\n" + " +X: Other critical service\n" + " If no flags are given, an attempt to figure them out based on name\n" + " will be made, but it's likely not a good one."); } void _fini(void) { deregistercontrolcmd("splitlist", &spcmd_splitlist); deregistercontrolcmd("splitdel", &spcmd_splitdel); + deregistercontrolcmd("splitadd", &spcmd_splitadd); } /* todo: add RELINK status */ @@ -73,3 +92,100 @@ int spcmd_splitdel(void *source, int cargc, char **cargv) { return CMD_OK; } + +static int doessplitalreadyexist(const char *servername) { + splitserver srv; + unsigned int i; + + for (i = 0; i < splitlist.cursi; i++) { + srv = ((splitserver*)splitlist.content)[i]; + + if (!strcasecmp(srv.name->content, servername)) + return 1; + } + + return 0; +} + +int spcmd_splitadd(void *source, int cargc, char **cargv) { + nick *np = (nick*)source; + unsigned long long num; + char *end; + flag_t servertype = 0; + char *servername; + size_t servernamelen; + time_t splittime; + server fake; + + if (cargc < 1) { + controlreply(np, "Usage: splitadd [+flags] [split time as unix timestamp]"); + return CMD_ERROR; + } + + servername = cargv[0]; + servernamelen = strlen(servername); + + if (findserver(servername) != -1) { + controlreply(np, "Server %s is linked right now, refusing to add split.", + servername); + return CMD_ERROR; + } + + if (doessplitalreadyexist(servername)) { + controlreply(np, "There is a split for %s already.", servername); + return CMD_ERROR; + } + + if (servernamelen > SERVERLEN) { + controlreply(np, "Server name %s is too long (max: %d characters)", + servername, SERVERLEN); + return CMD_ERROR; + } + + /* Handle flags */ + if (cargc > 1) { + if (setflags(&servertype, (flag_t)-1, cargv[1], servertypeflags, + REJECT_UNKNOWN) != REJECT_NONE) { + controlreply(np, "Flag string %s contained invalid flags.", cargv[1]); + return CMD_ERROR; + } + } else { + /* Set up a fake server for getservertype. */ + memset(&fake, 0, sizeof(fake)); + + fake.name = getsstring(servername, servernamelen); + servertype = getservertype(&fake); + freesstring(fake.name); + } + + /* Handle timestamp */ + if (cargc < 3) { + splittime = getnettime(); + } else { + errno = 0; + num = strtoull(cargv[2], &end, 10); + if (errno == ERANGE) { + controlreply(np, "%s is out of range for a timestamp.", cargv[2]); + return CMD_ERROR; + } + + /* Truncation may happen here. + * However, there's no way to get the max time_t value, so we'll just try to + * find out after the fact. + */ + splittime = (time_t)num; + + if ((unsigned long long)splittime < num) { + controlreply(np, "Tried to use %llu as split time value, but it's too " + "large for the system to handle", num); + return CMD_ERROR; + } + } + + sp_addsplit(servername, splittime, servertype); + controlreply(np, "Added split for %s (%s ago) with flags %s.", + servername, longtoduration(getnettime() - splittime, 1), + printflags(servertype, servertypeflags)); + + return CMD_OK; +} diff --git a/trusts/trusts_management.c b/trusts/trusts_management.c index 8f72f4d6..6fc0685d 100644 --- a/trusts/trusts_management.c +++ b/trusts/trusts_management.c @@ -207,7 +207,7 @@ static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) { controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content); trustlog(tg, sender->authname, "Created trust group '%s' (ID #%d): howmany=%d, enforceident=%d, maxperident=%d, " "createdby=%s, contact=%s, comment=%s", - tg->name->content, howmany, tg->id, enforceident, maxperident, createdby, contact, comment); + tg->name->content, tg->id, howmany, enforceident, maxperident, createdby, contact, comment); return CMD_OK; }