solanum/bandb/bandb.c
2021-07-30 14:17:47 -04:00

336 lines
7 KiB
C

/* bandb/bandb.c
*
* Copyright (C) 2006 Lee Hardy <lee -at- leeh.co.uk>
* Copyright (C) 2006-2008 ircd-ratbox development team
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1.Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2.Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3.The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "setup.h"
#include <rb_lib.h>
#include <stdio.h>
#include "rsdb.h"
#include "ircd_defs.h"
#define MAXPARA 10
#define COMMIT_INTERVAL 3 /* seconds */
typedef enum
{
BANDB_KLINE,
BANDB_DLINE,
BANDB_XLINE,
BANDB_RESV,
LAST_BANDB_TYPE
} bandb_type;
static char bandb_letter[LAST_BANDB_TYPE] = {
'K', 'D', 'X', 'R'
};
static const char *bandb_table[LAST_BANDB_TYPE] = {
"kline", "dline", "xline", "resv"
};
static rb_helper *bandb_helper;
static int in_transaction;
static void check_schema(void);
static void
bandb_commit(void *unused)
{
rsdb_transaction(RSDB_TRANS_END);
in_transaction = 0;
}
static void
parse_ban(bandb_type type, char *parv[], int parc)
{
const char *mask1 = NULL;
const char *mask2 = NULL;
const char *oper = NULL;
const char *curtime = NULL;
const char *reason = NULL;
const char *perm = NULL;
int para = 1;
if(type == BANDB_KLINE)
{
if(parc != 7)
return;
}
else if(parc != 6)
return;
mask1 = parv[para++];
if(type == BANDB_KLINE)
mask2 = parv[para++];
oper = parv[para++];
curtime = parv[para++];
perm = parv[para++];
reason = parv[para++];
if(!in_transaction)
{
rsdb_transaction(RSDB_TRANS_START);
in_transaction = 1;
rb_event_addonce("bandb_commit", bandb_commit, NULL,
COMMIT_INTERVAL);
}
rsdb_exec(NULL,
"INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q', '%Q', '%Q', %s, %s, '%Q')",
bandb_table[type], mask1, mask2 ? mask2 : "", oper, curtime, perm, reason);
}
static void
parse_unban(bandb_type type, char *parv[], int parc)
{
const char *mask1 = NULL;
const char *mask2 = NULL;
if(type == BANDB_KLINE)
{
if(parc != 3)
return;
}
else if(parc != 2)
return;
mask1 = parv[1];
if(type == BANDB_KLINE)
mask2 = parv[2];
if(!in_transaction)
{
rsdb_transaction(RSDB_TRANS_START);
in_transaction = 1;
rb_event_addonce("bandb_commit", bandb_commit, NULL,
COMMIT_INTERVAL);
}
rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'",
bandb_table[type], mask1, mask2 ? mask2 : "");
}
static void
list_bans(void)
{
static char buf[512];
struct rsdb_table table;
int i, j;
/* schedule a clear of anything already pending */
rb_helper_write_queue(bandb_helper, "C");
for(i = 0; i < LAST_BANDB_TYPE; i++)
{
rsdb_exec_fetch(&table, "SELECT mask1,mask2,oper,reason FROM %s WHERE 1",
bandb_table[i]);
for(j = 0; j < table.row_count; j++)
{
if(i == BANDB_KLINE)
snprintf(buf, sizeof(buf), "%c %s %s %s :%s",
bandb_letter[i], table.row[j][0],
table.row[j][1], table.row[j][2], table.row[j][3]);
else
snprintf(buf, sizeof(buf), "%c %s %s :%s",
bandb_letter[i], table.row[j][0],
table.row[j][2], table.row[j][3]);
rb_helper_write_queue(bandb_helper, "%s", buf);
}
rsdb_exec_fetch_end(&table);
}
rb_helper_write(bandb_helper, "F");
}
static void
parse_request(rb_helper *helper)
{
static char *parv[MAXPARA + 1];
static char readbuf[READBUF_SIZE];
int parc;
int len;
while((len = rb_helper_read(helper, readbuf, sizeof(readbuf))) > 0)
{
parc = rb_string_to_array(readbuf, parv, MAXPARA);
if(parc < 1)
continue;
switch (parv[0][0])
{
case 'K':
parse_ban(BANDB_KLINE, parv, parc);
break;
case 'D':
parse_ban(BANDB_DLINE, parv, parc);
break;
case 'X':
parse_ban(BANDB_XLINE, parv, parc);
break;
case 'R':
parse_ban(BANDB_RESV, parv, parc);
break;
case 'k':
parse_unban(BANDB_KLINE, parv, parc);
break;
case 'd':
parse_unban(BANDB_DLINE, parv, parc);
break;
case 'x':
parse_unban(BANDB_XLINE, parv, parc);
break;
case 'r':
parse_unban(BANDB_RESV, parv, parc);
break;
case 'L':
list_bans();
break;
default:
break;
}
}
}
static void
error_cb(rb_helper *helper) __attribute__((noreturn));
static void
error_cb(rb_helper *helper)
{
if(in_transaction)
rsdb_transaction(RSDB_TRANS_END);
exit(1);
}
static void
dummy_handler(int sig)
{
return;
}
static void
setup_signals(void)
{
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGPIPE);
sigaddset(&act.sa_mask, SIGALRM);
#ifdef SIGTRAP
sigaddset(&act.sa_mask, SIGTRAP);
#endif
#ifdef SIGWINCH
sigaddset(&act.sa_mask, SIGWINCH);
sigaction(SIGWINCH, &act, 0);
#endif
sigaction(SIGPIPE, &act, 0);
#ifdef SIGTRAP
sigaction(SIGTRAP, &act, 0);
#endif
act.sa_handler = dummy_handler;
sigaction(SIGALRM, &act, 0);
}
static void
db_error_cb(const char *errstr) __attribute__((noreturn));
static void
db_error_cb(const char *errstr)
{
char buf[256];
snprintf(buf, sizeof(buf), "! :%s", errstr);
rb_helper_write(bandb_helper, "%s", buf);
rb_sleep(1 << 30, 0);
exit(1);
}
int
main(int argc, char *argv[])
{
setup_signals();
bandb_helper = rb_helper_child(parse_request, error_cb, NULL, NULL, NULL, 256, 256, 256); /* XXX fix me */
if(bandb_helper == NULL)
{
fprintf(stderr,
"This is the solanum bandb for internal ircd use.\n");
fprintf(stderr,
"You aren't supposed to run me directly (did you want solanum-bantool?). Exiting.\n");
exit(1);
}
rsdb_init(db_error_cb);
check_schema();
rb_helper_loop(bandb_helper, 0);
return 0;
}
static void
check_schema(void)
{
struct rsdb_table table;
int i;
for(i = 0; i < LAST_BANDB_TYPE; i++)
{
rsdb_exec_fetch(&table,
"SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
bandb_table[i]);
rsdb_exec_fetch_end(&table);
if(!table.row_count)
rsdb_exec(NULL,
"CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
bandb_table[i]);
}
}