/* bandb/bandb.c * * Copyright (C) 2006 Lee Hardy * 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 #include #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]); } }