]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Merge pull request #51 from retropc/chanserv-live
authorChris Porter <redacted>
Sun, 23 Oct 2016 17:20:42 +0000 (18:20 +0100)
committerGitHub <redacted>
Sun, 23 Oct 2016 17:20:42 +0000 (18:20 +0100)
Merge master into chanserv-live

MODULES
a4stats/a4stats_db.c
configure.ini
depmod.pl
helpmod2/hcommands.c
nickrate/nickrate.c
pqsql/pqsql-dbapi2.c
splitlist/splitlist.c
splitlist/splitlist.h
splitlist/splitlist_commands.c
trusts/trusts_management.c

diff --git a/MODULES b/MODULES
index a47506c0e636e2d22e98f080773faac4261470be..ab1fa6b4553d3fda3a9ad836a9fb83bcab2df30b 100644 (file)
--- 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
 ---
 
index af7ae917af4e1f89d9884abcf946d180f3f666f2..dbcbe715245005ed590007b1fd5319dd9307fbbb 100644 (file)
@@ -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);
 }
 
index 6d3ded79bdcf6b363ab8a9781ff527cd6cf4609b..7bb1f2fc23aae59888493aa70b37dfed47233448 100644 (file)
@@ -78,7 +78,7 @@ fakeusers=
 raw=
 nickwatch=
 patrol=
-regexgline=pcre mysql
+regexgline=pcre dbapi
 facepalm=
 a4stats=lua
 rbl=
index 9c53672b17b0a5e081b4ad8ffdbbf3a45f8024fc..1004001321edb96bfa583c1c9a2c303d93f27234 100755 (executable)
--- 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;
index d7544074d2796cb84858458a4e6047d57a7c3d0c..57b9e9a3106d29df6180b13a632aae8abb85b654 100644 (file)
@@ -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;
index 6da2f43cca9eebb314ebe5d0ae329bcd576c8e6f..01cfb38ac652e95e0bd803a16067c7f29dc42782 100644 (file)
@@ -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;
   }
   
index fd6c1bd6c48125cca7810666fffc44ad8b9446e8..97cb0dc8adf36ddf51c81d695dec0b8f30a6cb86 100644 (file)
@@ -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, '\'');
 
index 29859c31181e60568383f58f8563da78f150f375..4789a0ea7374fe946cf9e0f3a812c653d6c07826 100644 (file)
@@ -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;
 
index eaa2e0eed0ac1a138fe3794647dde71a3d130a7b..21e079923249ec9396f23a3c0288539b89c793d1 100644 (file)
@@ -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 */
index fc8a4753250cd685319da39b8f02f98bdc8a292f..6cdce56d5c070b87b29bcfbd2455f54eb7141f72 100644 (file)
@@ -1,25 +1,44 @@
 /* oper commands for the splitlist */
 
+#include <errno.h>
+#include <string.h>
+
 #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 <servername> [+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 <servername> [+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;
+}
index 8f72f4d6d501e339cc1e083b33e3af31fc1641fc..6fc0685d495b573e80b80f28158f0270d31d2687 100644 (file)
@@ -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;
 }