summaryrefslogtreecommitdiff
path: root/operserv.c
diff options
context:
space:
mode:
authorsvn 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
committersvn 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
commit55bf4dbcabf378e9472b7d31d6edf87f6ac853e9 (patch)
tree7a9454ea6b8750256e242cf6d5fba3ca7a4b5044 /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.c5099
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.
+