diff options
| author | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
|---|---|---|
| committer | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
| commit | 55bf4dbcabf378e9472b7d31d6edf87f6ac853e9 (patch) | |
| tree | 7a9454ea6b8750256e242cf6d5fba3ca7a4b5044 /operserv.c | |
Initial Anope Import
git-svn-id: svn://svn.anope.org/anope/trunk@1 31f1291d-b8d6-0310-a050-a5561fc1590b
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'operserv.c')
| -rw-r--r-- | operserv.c | 5099 |
1 files changed, 5099 insertions, 0 deletions
diff --git a/operserv.c b/operserv.c new file mode 100644 index 000000000..c93a94368 --- /dev/null +++ b/operserv.c @@ -0,0 +1,5099 @@ +/* OperServ functions. + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * $Id: operserv.c,v 1.89 2004/03/14 22:44:47 dane Exp $ + * + */ + +#include "services.h" +#include "pseudo.h" + +/* + * Disable the modules on OpenBSD (for now) + * there is work in progress for this. + */ +#ifdef __OpenBSD__ +#ifdef USE_MODULES +#undef USE_MODULES +#endif /* USE_MODULES */ +#endif /* __OpenBSD__ */ + +extern Module *mod_current_module; +extern int mod_current_op; +extern User *mod_current_user; +extern ModuleHash *MODULE_HASH[MAX_CMD_HASH]; +/*************************************************************************/ + +struct clone { + char *host; + long time; +}; + +/* List of most recent users - statically initialized to zeros */ +static struct clone clonelist[CLONE_DETECT_SIZE]; + +/* Which hosts have we warned about, and when? This is used to keep us + * from sending out notices over and over for clones from the same host. */ +static struct clone warnings[CLONE_DETECT_SIZE]; + +/* List of Services administrators */ +SList servadmins; +/* List of Services operators */ +SList servopers; +/* AKILL, SGLINE, SQLINE and SZLINE lists */ +SList akills, sglines, sqlines, szlines; + +/*************************************************************************/ + +static void get_operserv_stats(long *nrec, long *memuse); + +static int compare_adminlist_entries(SList * slist, void *item1, + void *item2); +static int compare_operlist_entries(SList * slist, void *item1, + void *item2); +static void free_adminlist_entry(SList * slist, void *item); +static void free_operlist_entry(SList * slist, void *item); + +static int is_akill_entry_equal(SList * slist, void *item1, void *item2); +static void free_akill_entry(SList * slist, void *item); +#ifdef IRC_BAHAMUT +static int is_sgline_entry_equal(SList * slist, void *item1, void *item2); +static void free_sgline_entry(SList * slist, void *item); +#endif +static int is_sqline_entry_equal(SList * slist, void *item1, void *item2); +static void free_sqline_entry(SList * slist, void *item); +#ifdef IRC_BAHAMUT +static int is_szline_entry_equal(SList * slist, void *item1, void *item2); +static void free_szline_entry(SList * slist, void *item); +#endif + +static int do_help(User * u); +static int do_global(User * u); +static int do_stats(User * u); +static int do_admin(User * u); +static int do_oper(User * u); +static int do_os_mode(User * u); +static int do_clearmodes(User * u); +static int do_os_kick(User * u); +static int do_akill(User * u); +static int do_sgline(User * u); +static int do_sqline(User * u); +static int do_szline(User * u); +static int do_set(User * u); +static int do_noop(User * u); +static int do_jupe(User * u); +static int do_raw(User * u); +static int do_update(User * u); +static int do_reload(User * u); +static int do_os_quit(User * u); +static int do_shutdown(User * u); +static int do_restart(User * u); +static int do_ignorelist(User * u); +static int do_clearignore(User * u); +static int do_killclones(User * u); +static int do_chanlist(User * u); +static int do_userlist(User * u); +static int do_ignoreuser(User * u); +static int do_staff(User * u); +static int do_defcon(User * u); +static int do_chankill(User * u); +static void defcon_sendlvls(User * u); +char *defconReverseModes(const char *modes); +int DefConModesSet = 0; +time_t DefContimer; +void runDefCon(void); +void resetDefCon(int level); +void oper_global(char *nick, char *fmt, ...); + +#ifdef USE_MODULES +int do_modload(User * u); +int do_modunload(User * u); +int do_modlist(User * u); +int do_modinfo(User * u); +static int showModuleCmdLoaded(CommandHash * cmdList, char *mod_name, + User * u); +static int showModuleMsgLoaded(MessageHash * msgList, char *mod_name, + User * u); +#endif + + +#ifdef USE_OSSVS +#ifndef IRC_HYBRID +static int do_operumodes(User * u); +#endif +static int do_svsnick(User * u); +#endif + +#if defined(IRC_UNREAL) && defined(USE_OSSVS) +static int do_operoline(User * u); +#endif + +#ifdef DEBUG_COMMANDS +static void send_clone_lists(User * u); +static int do_matchwild(User * u); +#endif + +/* OperServ restart needs access to this if were gonna avoid sending ourself a signal */ +extern int do_restart_services(void); +void moduleAddOperServCmds(void); +/*************************************************************************/ + +/* Options for the lists */ +SListOpts akopts = { 0, NULL, &is_akill_entry_equal, &free_akill_entry }; +SListOpts saopts = { SLISTF_SORT, &compare_adminlist_entries, NULL, + &free_adminlist_entry +}; + +#ifdef IRC_BAHAMUT +SListOpts sgopts = { 0, NULL, &is_sgline_entry_equal, &free_sgline_entry }; +#endif +SListOpts soopts = + { SLISTF_SORT, &compare_operlist_entries, NULL, &free_operlist_entry }; +SListOpts sqopts = + { SLISTF_SORT, NULL, &is_sqline_entry_equal, &free_sqline_entry }; +#ifdef IRC_BAHAMUT +SListOpts szopts = { 0, NULL, &is_szline_entry_equal, &free_szline_entry }; +#endif + +/*************************************************************************/ +/* *INDENT-OFF* */ +void moduleAddOperServCmds(void) { + Command *c; + c = createCommand("HELP", do_help, NULL, -1, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("GLOBAL", do_global, NULL, OPER_HELP_GLOBAL, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("STATS", do_stats, NULL, OPER_HELP_STATS, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("UPTIME", do_stats, NULL, OPER_HELP_STATS, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + + /* Anyone can use the LIST option to the ADMIN and OPER commands; those + * routines check privileges to ensure that only authorized users + * modify the list. */ + c = createCommand("ADMIN", do_admin, NULL, OPER_HELP_ADMIN, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("OPER", do_oper, NULL, OPER_HELP_OPER, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("STAFF", do_staff, NULL, OPER_HELP_STAFF, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + /* Similarly, anyone can use *NEWS LIST, but *NEWS {ADD,DEL} are + * reserved for Services admins. */ + c = createCommand("LOGONNEWS", do_logonnews, NULL, NEWS_HELP_LOGON, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("OPERNEWS", do_opernews, NULL, NEWS_HELP_OPER, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("RANDOMNEWS", do_randomnews, NULL, NEWS_HELP_RANDOM, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + + /* Commands for Services opers: */ + c = createCommand("MODE", do_os_mode, is_services_oper,OPER_HELP_MODE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("CLEARMODES", do_clearmodes, is_services_oper,OPER_HELP_CLEARMODES, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("KICK", do_os_kick, is_services_oper,OPER_HELP_KICK, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("KILLCLONES", do_killclones, is_services_oper,OPER_HELP_KILLCLONES, -1,-1,-1, -1); addCoreCommand(OPERSERV,c); + c = createCommand("AKILL", do_akill, is_services_oper,OPER_HELP_AKILL, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SGLINE", do_sgline, is_services_oper,OPER_HELP_SGLINE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SQLINE", do_sqline, is_services_oper,OPER_HELP_SQLINE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SZLINE", do_szline, is_services_oper,OPER_HELP_SZLINE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + + /* Commands for Services admins: */ + c = createCommand("SET", do_set, is_services_admin,OPER_HELP_SET, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SET READONLY", NULL, NULL,OPER_HELP_SET_READONLY, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SET LOGCHAN",NULL, NULL,OPER_HELP_SET_LOGCHAN, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SET DEBUG", NULL, NULL,OPER_HELP_SET_DEBUG, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SET NOEXPIRE",NULL, NULL,OPER_HELP_SET_NOEXPIRE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SET SUPERADMIN",NULL, NULL,OPER_HELP_SET_SUPERADMIN, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#ifdef USE_OSSVS + c = createCommand("SVSNICK", do_svsnick, is_services_admin,OPER_HELP_SVSNICK, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#ifndef IRC_HYBRID + c = createCommand("UMODE", do_operumodes, is_services_admin,OPER_HELP_UMODE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#endif +#endif + c = createCommand("NOOP", do_noop, is_services_admin,OPER_HELP_NOOP, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("JUPE", do_jupe, is_services_admin,OPER_HELP_JUPE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("RAW", do_raw, is_services_admin,OPER_HELP_RAW, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("IGNORE", do_ignoreuser, is_services_admin,OPER_HELP_IGNORE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#if defined(IRC_UNREAL) && defined(USE_OSSVS) + c = createCommand("OLINE", do_operoline, is_services_admin,OPER_HELP_OLINE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#endif + c = createCommand("UPDATE", do_update, is_services_admin,OPER_HELP_UPDATE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("RELOAD", do_reload, is_services_admin,OPER_HELP_RELOAD, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("QUIT", do_os_quit, is_services_admin,OPER_HELP_QUIT, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("SHUTDOWN", do_shutdown, is_services_admin,OPER_HELP_SHUTDOWN, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("RESTART", do_restart, is_services_admin,OPER_HELP_RESTART, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#ifndef STREAMLINED + c = createCommand("SESSION", do_session, is_services_admin,OPER_HELP_SESSION, -1,-1,-1, -1); addCoreCommand(OPERSERV,c); + c = createCommand("EXCEPTION", do_exception, is_services_admin,OPER_HELP_EXCEPTION, -1,-1,-1, -1); addCoreCommand(OPERSERV,c); +#endif + c = createCommand("CHANLIST", do_chanlist, is_services_admin,OPER_HELP_CHANLIST, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("USERLIST", do_userlist, is_services_admin,OPER_HELP_USERLIST, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("CACHE", do_cache, is_services_admin,OPER_HELP_CACHE, -1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("DEFCON", do_defcon, is_services_admin, OPER_HELP_DEFCON,-1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("CHANKILL", do_chankill, is_services_admin, OPER_HELP_CHANKILL,-1,-1,-1,-1); addCoreCommand(OPERSERV,c); + /* Commands for Services root: */ +#ifdef USE_MODULES + c = createCommand("MODLOAD", do_modload, is_services_root, -1,-1,-1,-1,OPER_HELP_MODLOAD); addCoreCommand(OPERSERV,c); + c = createCommand("MODUNLOAD", do_modunload, is_services_root, -1,-1,-1,-1,OPER_HELP_MODUNLOAD); addCoreCommand(OPERSERV,c); + c = createCommand("MODLIST", do_modlist, is_services_root, -1,-1,-1,-1,OPER_HELP_MODLIST); addCoreCommand(OPERSERV,c); + c = createCommand("MODINFO", do_modinfo, is_services_root, -1,-1,-1,-1,OPER_HELP_MODINFO); addCoreCommand(OPERSERV,c); +#endif +#ifdef DEBUG_COMMANDS + c = createCommand("LISTTIMERS", send_timeout_list, is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("MATCHWILD", do_matchwild, is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c); + c = createCommand("LISTCLONES", send_clone_lists, is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c); +#endif +} + +/* *INDENT-ON* */ +/*************************************************************************/ +/*************************************************************************/ + +/* OperServ initialization. */ + +void os_init(void) +{ + Command *cmd; + moduleAddOperServCmds(); + cmd = findCommand(OPERSERV, "GLOBAL"); + if (cmd) + cmd->help_param1 = s_GlobalNoticer; + cmd = findCommand(OPERSERV, "ADMIN"); + if (cmd) + cmd->help_param1 = s_NickServ; + cmd = findCommand(OPERSERV, "OPER"); + if (cmd) + cmd->help_param1 = s_NickServ; + + /* Initialization of the lists */ + slist_init(&servadmins); + servadmins.opts = &saopts; + slist_init(&servopers); + servopers.opts = &soopts; + + slist_init(&akills); + akills.opts = &akopts; + slist_init(&sglines); +#ifdef IRC_BAHAMUT + sglines.opts = &sgopts; +#endif + slist_init(&sqlines); + sqlines.opts = &sqopts; + slist_init(&szlines); +#ifdef IRC_BAHAMUT + szlines.opts = &szopts; +#endif +} + +/*************************************************************************/ + +/* Main OperServ routine. */ + +void operserv(User * u, char *buf) +{ + char *cmd; + char *s; + + alog("%s: %s: %s", s_OperServ, u->nick, buf); + + cmd = strtok(buf, " "); + if (!cmd) { + return; + } else if (stricmp(cmd, "\1PING") == 0) { + if (!(s = strtok(NULL, ""))) + s = "\1"; + notice(s_OperServ, u->nick, "\1PING %s", s); + } else { + mod_run_cmd(s_OperServ, u, OPERSERV, cmd); + } +} + +static void get_operserv_stats(long *nrec, long *memuse) +{ + int i; + long mem = 0, count = 0, mem2 = 0, count2 = 0; + Akill *ak; + SXLine *sx; + + if (CheckClones) { + mem = sizeof(struct clone) * CLONE_DETECT_SIZE * 2; + for (i = 0; i < CLONE_DETECT_SIZE; i++) { + if (clonelist[i].host) { + count++; + mem += strlen(clonelist[i].host) + 1; + } + if (warnings[i].host) { + count++; + mem += strlen(warnings[i].host) + 1; + } + } + } + + count += akills.count; + mem += akills.capacity * sizeof(void); + mem += akills.count * sizeof(Akill); + + for (i = 0; i < akills.count; i++) { + ak = akills.list[i]; + mem += strlen(ak->user) + 1; + mem += strlen(ak->host) + 1; + mem += strlen(ak->by) + 1; + mem += strlen(ak->reason) + 1; + } + +#ifdef IRC_BAHAMUT + + count += sglines.count; + mem += sglines.capacity * sizeof(void); + mem += sglines.count * sizeof(SXLine); + + for (i = 0; i < sglines.count; i++) { + sx = sglines.list[i]; + mem += strlen(sx->mask) + 1; + mem += strlen(sx->by) + 1; + mem += strlen(sx->reason) + 1; + } + +#endif + + count += sqlines.count; + mem += sqlines.capacity * sizeof(void); + mem += sqlines.count * sizeof(SXLine); + + for (i = 0; i < sqlines.count; i++) { + sx = sqlines.list[i]; + mem += strlen(sx->mask) + 1; + mem += strlen(sx->by) + 1; + mem += strlen(sx->reason) + 1; + } + +#ifdef IRC_BAHAMUT + + count += szlines.count; + mem += szlines.capacity * sizeof(void); + mem += szlines.count * sizeof(SXLine); + + for (i = 0; i < szlines.count; i++) { + sx = szlines.list[i]; + mem += strlen(sx->mask) + 1; + mem += strlen(sx->by) + 1; + mem += strlen(sx->reason) + 1; + } + +#endif + + get_news_stats(&count2, &mem2); + count += count2; + mem += mem2; + get_exception_stats(&count2, &mem2); + count += count2; + mem += mem2; + + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ +/**************************** Privilege checks ***************************/ +/*************************************************************************/ + +/* Load old AKILL data. */ + +#define SAFE(x) do { \ + if ((x) < 0) { \ + if (!forceload) \ + fatal("Read error on %s", AutokillDBName); \ + break; \ + } \ +} while (0) + +static void load_old_akill(void) +{ + dbFILE *f; + int i, j; + int16 tmp16; + int32 tmp32; + char buf[NICKMAX], mask2[BUFSIZE], *mask, *s; + Akill *ak, *entry; + + if (! + (f = + open_db("AKILL", AutokillDBName ? AutokillDBName : "akill.db", + "r", 9))) + return; + + get_file_version(f); + + read_int16(&tmp16, f); + slist_setcapacity(&akills, tmp16); + + for (j = 0; j < akills.capacity; j++) { + ak = scalloc(sizeof(Akill), 1); + + SAFE(read_string(&mask, f)); + s = strchr(mask, '@'); + *s = 0; + s++; + ak->user = sstrdup(mask); + ak->host = sstrdup(s); + SAFE(read_string(&ak->reason, f)); + SAFE(read_buffer(buf, f)); + if (!*buf) + ak->by = sstrdup("<unknown>"); + else + ak->by = sstrdup(buf); + SAFE(read_int32(&tmp32, f)); + ak->seton = tmp32 ? tmp32 : time(NULL); + SAFE(read_int32(&tmp32, f)); + ak->expires = tmp32; + + /* Sanity checks *sigh* */ + + /* No nicknames allowed! */ + if (strchr(ak->user, '!')) { + s_rakill(ak->user, ak->host); + free(ak); + continue; + } + + snprintf(mask2, sizeof(mask2), "%s@%s", ak->user, ak->host); + + /* Is the mask already in the AKILL list? */ + if (slist_indexof(&akills, mask2) != -1) { + free(ak); + continue; + } + + /* Checks whether there is an AKILL that already covers + * the one we want to add, and whether there are AKILLs + * that would be covered by this one. Expiry time + * does *also* matter. + */ + + if (akills.count > 0) { + + for (i = akills.count - 1; i >= 0; i--) { + + char amask[BUFSIZE]; + + entry = akills.list[i]; + + if (!entry) + continue; + + snprintf(amask, sizeof(amask), "%s@%s", entry->user, + entry->host); + + if (match_wild_nocase(amask, mask2) + && (entry->expires >= ak->expires + || entry->expires == 0)) { + s_rakill(ak->user, ak->host); + free(ak); + ak = NULL; + break; + } + + if (match_wild_nocase(mask2, amask) + && (entry->expires <= ak->expires || ak->expires == 0)) + slist_delete(&akills, i); + } + + } + + if (ak) + slist_add(&akills, ak); + } + + close_db(f); +} + +#undef SAFE + +/* Load OperServ data. */ + +#define SAFE(x) do { \ + if ((x) < 0) { \ + if (!forceload) \ + fatal("Read error on %s", OperDBName); \ + failed = 1; \ + break; \ + } \ +} while (0) + +void load_os_dbase(void) +{ + dbFILE *f; + int16 i, n, ver, c; + HostCache *hc, **hclast, *hcprev; + int16 tmp16; + int32 tmp32; + char *s; + int failed = 0; + + if (!(f = open_db(s_OperServ, OperDBName, "r", OPER_VERSION))) + return; + + ver = get_file_version(f); + + if (ver <= 9) { + NickAlias *na; + + SAFE(read_int16(&n, f)); + for (i = 0; i < n && !failed; i++) { + SAFE(read_string(&s, f)); + if (s) { + na = findnick(s); + if (na) { + na->nc->flags |= NI_SERVICES_ADMIN; + if (slist_indexof(&servadmins, na) == -1) + slist_add(&servadmins, na); + } + free(s); + } + } + if (!failed) + SAFE(read_int16(&n, f)); + for (i = 0; i < n && !failed; i++) { + SAFE(read_string(&s, f)); + if (s) { + na = findnick(s); + if (na) { + na->nc->flags |= NI_SERVICES_OPER; + if (slist_indexof(&servopers, na) == -1) + slist_add(&servopers, na); + } + free(s); + } + } + } + + if (ver >= 7) { + int32 tmp32; + SAFE(read_int32(&maxusercnt, f)); + SAFE(read_int32(&tmp32, f)); + maxusertime = tmp32; + } + + if (ver <= 10) + load_old_akill(); + else { + Akill *ak; + + read_int16(&tmp16, f); + slist_setcapacity(&akills, tmp16); + + for (i = 0; i < akills.capacity; i++) { + ak = scalloc(sizeof(Akill), 1); + + SAFE(read_string(&ak->user, f)); + SAFE(read_string(&ak->host, f)); + SAFE(read_string(&ak->by, f)); + SAFE(read_string(&ak->reason, f)); + SAFE(read_int32(&tmp32, f)); + ak->seton = tmp32; + SAFE(read_int32(&tmp32, f)); + ak->expires = tmp32; + + slist_add(&akills, ak); + } + } + + if (ver >= 11) { + SXLine *sx; + + read_int16(&tmp16, f); + slist_setcapacity(&sglines, tmp16); + + for (i = 0; i < sglines.capacity; i++) { + sx = scalloc(sizeof(SXLine), 1); + + SAFE(read_string(&sx->mask, f)); + SAFE(read_string(&sx->by, f)); + SAFE(read_string(&sx->reason, f)); + SAFE(read_int32(&tmp32, f)); + sx->seton = tmp32; + SAFE(read_int32(&tmp32, f)); + sx->expires = tmp32; + + slist_add(&sglines, sx); + } + + if (ver >= 13) { + read_int16(&tmp16, f); + slist_setcapacity(&sqlines, tmp16); + + for (i = 0; i < sqlines.capacity; i++) { + sx = scalloc(sizeof(SXLine), 1); + + SAFE(read_string(&sx->mask, f)); + SAFE(read_string(&sx->by, f)); + SAFE(read_string(&sx->reason, f)); + SAFE(read_int32(&tmp32, f)); + sx->seton = tmp32; + SAFE(read_int32(&tmp32, f)); + sx->expires = tmp32; + + slist_add(&sqlines, sx); + } + } + + read_int16(&tmp16, f); + slist_setcapacity(&szlines, tmp16); + + for (i = 0; i < szlines.capacity; i++) { + sx = scalloc(sizeof(SXLine), 1); + + SAFE(read_string(&sx->mask, f)); + SAFE(read_string(&sx->by, f)); + SAFE(read_string(&sx->reason, f)); + SAFE(read_int32(&tmp32, f)); + sx->seton = tmp32; + SAFE(read_int32(&tmp32, f)); + sx->expires = tmp32; + + slist_add(&szlines, sx); + } + } + + if (ver >= 12) { + for (i = 0; i < 1024 && !failed; i++) { + hclast = &hcache[i]; + hcprev = NULL; + + while ((c = getc_db(f)) != 0) { + if (c != 1) + fatal("Invalid format in %s", OperDBName); + + hc = scalloc(1, sizeof(HostCache)); + + SAFE(read_string(&hc->host, f)); + SAFE(read_int16(&tmp16, f)); + hc->status = tmp16; + SAFE(read_int32(&tmp32, f)); + hc->used = tmp32; + + *hclast = hc; + hclast = &hc->next; + hc->prev = hcprev; + hcprev = hc; + } /* while (getc_db(f) != 0) */ + + *hclast = NULL; + } /* for (i) */ + } + + close_db(f); + +} + +#undef SAFE + +/*************************************************************************/ + +/* Save OperServ data. */ + +#define SAFE(x) do { \ + if ((x) < 0) { \ + restore_db(f); \ + log_perror("Write error on %s", OperDBName); \ + if (time(NULL) - lastwarn > WarningTimeout) { \ + wallops(NULL, "Write error on %s: %s", OperDBName, \ + strerror(errno)); \ + lastwarn = time(NULL); \ + } \ + return; \ + } \ +} while (0) + +void save_os_dbase(void) +{ + int i; + dbFILE *f; + static time_t lastwarn = 0; + Akill *ak; + SXLine *sx; + HostCache *hc; + + if (!(f = open_db(s_OperServ, OperDBName, "w", OPER_VERSION))) + return; + SAFE(write_int32(maxusercnt, f)); + SAFE(write_int32(maxusertime, f)); + + SAFE(write_int16(akills.count, f)); + for (i = 0; i < akills.count; i++) { + ak = akills.list[i]; + + SAFE(write_string(ak->user, f)); + SAFE(write_string(ak->host, f)); + SAFE(write_string(ak->by, f)); + SAFE(write_string(ak->reason, f)); + SAFE(write_int32(ak->seton, f)); + SAFE(write_int32(ak->expires, f)); + } + + SAFE(write_int16(sglines.count, f)); + for (i = 0; i < sglines.count; i++) { + sx = sglines.list[i]; + + SAFE(write_string(sx->mask, f)); + SAFE(write_string(sx->by, f)); + SAFE(write_string(sx->reason, f)); + SAFE(write_int32(sx->seton, f)); + SAFE(write_int32(sx->expires, f)); + } + + SAFE(write_int16(sqlines.count, f)); + for (i = 0; i < sqlines.count; i++) { + sx = sqlines.list[i]; + + SAFE(write_string(sx->mask, f)); + SAFE(write_string(sx->by, f)); + SAFE(write_string(sx->reason, f)); + SAFE(write_int32(sx->seton, f)); + SAFE(write_int32(sx->expires, f)); + } + + SAFE(write_int16(szlines.count, f)); + for (i = 0; i < szlines.count; i++) { + sx = szlines.list[i]; + + SAFE(write_string(sx->mask, f)); + SAFE(write_string(sx->by, f)); + SAFE(write_string(sx->reason, f)); + SAFE(write_int32(sx->seton, f)); + SAFE(write_int32(sx->expires, f)); + } + + for (i = 0; i < 1024; i++) { + for (hc = hcache[i]; hc; hc = hc->next) { + /* Don't save in-progress scans */ + if (hc->status < HC_NORMAL) + continue; + + SAFE(write_int8(1, f)); + + SAFE(write_string(hc->host, f)); + SAFE(write_int16(hc->status, f)); + SAFE(write_int32(hc->used, f)); + + } /* for (hc) */ + SAFE(write_int8(0, f)); + } /* for (i) */ + + close_db(f); + +} + +#undef SAFE + +/*************************************************************************/ + +void save_os_rdb_dbase(void) +{ +#ifdef USE_RDB + if (!rdb_open()) + return; + rdb_save_os_db(maxusercnt, maxusertime, &akills, &sglines, &sqlines, + &szlines, hcache[0]); + rdb_close(); +#endif +} + +/*************************************************************************/ + +/* Removes the nick structure from OperServ lists. */ + +void os_remove_nick(NickCore * nc) +{ + slist_remove(&servadmins, nc); + slist_remove(&servopers, nc); +} + +/*************************************************************************/ + +/* Does the given user have Services root privileges? + Now enhanced. */ + +int is_services_root(User * u) +{ + if ((NSStrictPrivileges && !is_oper(u)) + || (!skeleton && !nick_identified(u))) + return 0; + if (skeleton || (u->na->nc->flags & NI_SERVICES_ROOT)) + return 1; + return 0; +} + +/*************************************************************************/ + +/* Does the given user have Services admin privileges? */ + +int is_services_admin(User * u) +{ + if ((NSStrictPrivileges && !is_oper(u)) + || (!skeleton && !nick_identified(u))) + return 0; + if (skeleton + || (u->na->nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT))) + return 1; + return 0; +} + +/*************************************************************************/ + +/* Does the given user have Services oper privileges? */ + +int is_services_oper(User * u) +{ + if ((NSStrictPrivileges && !is_oper(u)) + || (!skeleton && !nick_identified(u))) + return 0; + if (skeleton + || (u->na->nc-> + flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN | + NI_SERVICES_ROOT))) + return 1; + return 0; +} + +/*************************************************************************/ + +/* Is the given nick a Services admin/root nick? */ + +int nick_is_services_admin(NickCore * nc) +{ + if (nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT)) + return 1; + + return 0; +} + +/*************************************************************************/ + +/* Is the given nick a Services oper/admin/root nick? */ + +int nick_is_services_oper(NickCore * nc) +{ + if (nc-> + flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN | NI_SERVICES_ROOT)) + return 1; + + return 0; +} + +/*************************************************************************/ +/**************************** Clone detection ****************************/ +/*************************************************************************/ + +/* We just got a new user; does it look like a clone? If so, send out a + * wallops. + */ + +void check_clones(User * user) +{ +#ifndef STREAMLINED + int i, clone_count; + long last_time; + + if (!CheckClones) + return; + + if (clonelist[0].host) + free(clonelist[0].host); + i = CLONE_DETECT_SIZE - 1; + memmove(clonelist, clonelist + 1, sizeof(struct clone) * i); + clonelist[i].host = sstrdup(GetHost(user)); + last_time = clonelist[i].time = time(NULL); + clone_count = 1; + while (--i >= 0 && clonelist[i].host) { + if (clonelist[i].time < last_time - CloneMaxDelay) + break; + if (stricmp(clonelist[i].host, GetHost(user)) == 0) { + ++clone_count; + last_time = clonelist[i].time; + if (clone_count >= CloneMinUsers) + break; + } + } + if (clone_count >= CloneMinUsers) { + /* Okay, we have clones. Check first to see if we already know + * about them. */ + for (i = CLONE_DETECT_SIZE - 1; i >= 0 && warnings[i].host; --i) { + if (stricmp(warnings[i].host, GetHost(user)) == 0) + break; + } + if (i < 0 + || warnings[i].time < user->my_signon - CloneWarningDelay) { + /* Send out the warning, and note it. */ + wallops(s_OperServ, + "\2WARNING\2 - possible clones detected from %s", + GetHost(user)); + alog("%s: possible clones detected from %s", s_OperServ, + GetHost(user)); + i = CLONE_DETECT_SIZE - 1; + if (warnings[0].host) + free(warnings[0].host); + memmove(warnings, warnings + 1, sizeof(struct clone) * i); + warnings[i].host = sstrdup(GetHost(user)); + warnings[i].time = clonelist[i].time; + if (KillClones) + kill_user(s_OperServ, user->nick, "Clone kill"); + } + } +#endif /* !STREAMLINED */ +} + +/*************************************************************************/ + +#ifdef DEBUG_COMMANDS + +/* Send clone arrays to given nick. */ + +static void send_clone_lists(User * u) +{ + int i; + + if (!CheckClones) { + notice(s_OperServ, u->nick, "CheckClones not enabled."); + return; + } + + notice(s_OperServ, u->nick, "clonelist[]"); + for (i = 0; i < CLONE_DETECT_SIZE; i++) { + if (clonelist[i].host) + notice(s_OperServ, u->nick, " %10ld %s", clonelist[i].time, + clonelist[i].host ? clonelist[i].host : "(null)"); + } + notice(s_OperServ, u->nick, "warnings[]"); + for (i = 0; i < CLONE_DETECT_SIZE; i++) { + if (clonelist[i].host) + notice(s_OperServ, u->nick, " %10ld %s", warnings[i].time, + warnings[i].host ? warnings[i].host : "(null)"); + } +} + +#endif /* DEBUG_COMMANDS */ + +/*************************************************************************/ +/*********************** OperServ command functions **********************/ +/*************************************************************************/ + +/* HELP command. */ + +static int do_help(User * u) +{ + const char *cmd = strtok(NULL, ""); + + if (!cmd) { + notice_help(s_OperServ, u, OPER_HELP); + if (is_services_oper(u)) + notice_help(s_OperServ, u, OPER_HELP_OPER_CMD); + if (is_services_admin(u)) + notice_help(s_OperServ, u, OPER_HELP_ADMIN_CMD); +#ifdef USE_MODULES + if (is_services_root(u)) + notice_help(s_OperServ, u, OPER_HELP_ROOT_CMD); +#endif + moduleDisplayHelp(5, u); + notice_help(s_OperServ, u, OPER_HELP_LOGGED); + } else { + mod_help_cmd(s_OperServ, u, OPERSERV, cmd); + } + return MOD_CONT; +} + +/*************************************************************************/ + +/* Global notice sending via GlobalNoticer. */ +/* Added name tag for globalmsg -Certus */ + +static int do_global(User * u) +{ + char *msg = strtok(NULL, ""); + + if (!msg) { + syntax_error(s_OperServ, u, "GLOBAL", OPER_GLOBAL_SYNTAX); + return MOD_CONT; + } + if (WallOSGlobal) + wallops(s_OperServ, "\2%s\2 just used GLOBAL command.", u->nick); + oper_global(u->nick, msg); + return MOD_CONT; +} + +void oper_global(char *nick, char *fmt, ...) +{ + va_list args; + char msg[2048]; /* largest valid message is 512, this should cover any global */ + int i; + + va_start(args, fmt); + vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + +#ifdef IRC_HYBRID + if (DomainNumber > 0) { + for (i = 0; i < DomainNumber; i++) { + if ((nick) && (!AnonymousGlobal)) { + send_cmd(s_GlobalNoticer, "NOTICE $$*.%s :[%s] %s", + NetworkDomains[i], nick, msg); + } else { + send_cmd(s_GlobalNoticer, "NOTICE $$*.%s :%s", + NetworkDomains[i], msg); + } + } + } else { + /* Go through all common top-level domains. If you have others, + * add them here. + |
