Only allow opers with access to GLINE to use a custom duration in BLOCK.
[srvx.git] / src / opserv.c
index cd384a600ef40f8c3a35c5c2876f8527febc2a24..5a3f98d91fd2b17f112dfa77c209682c57a9a6e7 100644 (file)
@@ -91,6 +91,7 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_NEED_CHANNEL", "You must specify a channel for $b%s$b." },
     { "OSMSG_INVALID_IRCMASK", "$b%s$b is an invalid IRC hostmask." },
     { "OSMSG_ADDED_BAN", "I have banned $b%s$b from $b%s$b." },
+    { "OSMSG_NO_GLINE_CMD", "The GLINE command is not bound so you can only block with the default duration." },
     { "OSMSG_GLINE_ISSUED", "G-line issued for $b%s$b." },
     { "OSMSG_GLINE_REMOVED", "G-line removed for $b%s$b." },
     { "OSMSG_GLINE_FORCE_REMOVED", "Unknown/expired G-line removed for $b%s$b." },
@@ -266,6 +267,7 @@ static dict_t opserv_hostinfo_dict; /* data is struct opserv_hostinfo* */
 static dict_t opserv_user_alerts; /* data is struct opserv_user_alert* */
 static dict_t opserv_nick_based_alerts; /* data is struct opserv_user_alert* */
 static dict_t opserv_channel_alerts; /* data is struct opserv_user_alert* */
+static dict_t opserv_account_alerts; /* data is struct opserv_user_alert* */
 static struct module *opserv_module;
 static struct log_type *OS_LOG;
 static unsigned int new_user_flood;
@@ -767,18 +769,35 @@ static MODCMD_FUNC(cmd_block)
     struct userNode *target;
     struct gline *gline;
     char *reason;
+    unsigned long duration = 0;
+    unsigned int offset = 2;
+    struct svccmd *gline_cmd;
 
     target = GetUserH(argv[1]);
     if (!target) {
-       reply("MSG_NICK_UNKNOWN", argv[1]);
-       return 0;
+        reply("MSG_NICK_UNKNOWN", argv[1]);
+        return 0;
     }
     if (IsService(target)) {
-       reply("MSG_SERVICE_IMMUNE", target->nick);
-       return 0;
+        reply("MSG_SERVICE_IMMUNE", target->nick);
+        return 0;
+    }
+    if(argc > 2 && (duration = ParseInterval(argv[2]))) {
+        offset = 3;
+    }
+    if(duration && duration != opserv_conf.block_gline_duration) {
+        // We require more access when the duration is not the default block duration.
+        gline_cmd = dict_find(cmd->parent->commands, "gline", NULL);
+        if(!gline_cmd)
+        {
+            reply("OSMSG_NO_GLINE_CMD");
+            return 0;
+        }
+        if(!svccmd_can_invoke(user, cmd->parent->bot, gline_cmd, channel, SVCCMD_NOISY))
+            return 0;
     }
-    reason = (argc > 2) ? unsplit_string(argv+2, argc-2, NULL) : NULL;
-    gline = opserv_block(target, user->handle_info->handle, reason, 0);
+    reason = (argc > offset) ? unsplit_string(argv+offset, argc-offset, NULL) : NULL;
+    gline = opserv_block(target, user->handle_info->handle, reason, duration);
     reply("OSMSG_GLINE_ISSUED", gline->target);
     return 1;
 }
@@ -1189,6 +1208,7 @@ static MODCMD_FUNC(cmd_whois)
        if (IsDeaf(target)) buffer[bpos++] = 'd';
        if (IsNoChan(target)) buffer[bpos++] = 'n';
         if (IsHiddenHost(target)) buffer[bpos++] = 'x';
+        if (IsNoIdle(target)) buffer[bpos++] = 'I';
         if (IsGagged(target)) buffer_cat(" (gagged)");
        if (IsRegistering(target)) buffer_cat(" (registered account)");
        buffer[bpos] = 0;
@@ -1479,11 +1499,15 @@ static MODCMD_FUNC(cmd_stats_uplink) {
 }
 
 static MODCMD_FUNC(cmd_stats_uptime) {
+    extern int lines_processed;
+    extern time_t boot_time;
+    double kernel_time;
+    double user_time;
     char uptime[INTERVALLEN];
+
+#if defined(HAVE_TIMES)
+    static double clocks_per_sec;
     struct tms buf;
-    extern time_t boot_time;
-    extern int lines_processed;
-    static long clocks_per_sec;
 
     if (!clocks_per_sec) {
 #if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
@@ -1495,12 +1519,27 @@ static MODCMD_FUNC(cmd_stats_uptime) {
             clocks_per_sec = CLOCKS_PER_SEC;
         }
     }
-    intervalString(uptime, time(NULL)-boot_time, user->handle_info);
     times(&buf);
-    reply("OSMSG_UPTIME_STATS",
-          uptime, lines_processed,
-          buf.tms_utime/(double)clocks_per_sec,
-          buf.tms_stime/(double)clocks_per_sec);
+    user_time = buf.tms_utime / clocks_per_sec;
+    kernel_time = buf.tms_stime / clocks_per_sec;
+#elif defined(HAVE_GETPROCESSTIMES)
+    FILETIME times[4];
+    LARGE_INTEGER li[2];
+
+    GetProcessTimes(GetCurrentProcess(), &times[0], &times[1], &times[2], &times[3]);
+    li[0].LowPart = times[2].dwLowDateTime;
+    li[0].HighPart = times[2].dwHighDateTime;
+    kernel_time = li[0].QuadPart * 1e-7;
+    li[1].LowPart = times[3].dwLowDateTime;
+    li[1].HighPart = times[3].dwHighDateTime;
+    user_time = li[1].QuadPart * 1e-7;
+#else
+    user_time = NAN;
+    system_time = NAN;
+#endif
+
+    intervalString(uptime, time(NULL)-boot_time, user->handle_info);
+    reply("OSMSG_UPTIME_STATS", uptime, lines_processed, user_time, kernel_time);
     return 1;
 }
 
@@ -2570,6 +2609,8 @@ opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_react
         dict_insert(opserv_channel_alerts, name_dup, alert);
     if (alert->discrim->mask_nick)
         dict_insert(opserv_nick_based_alerts, name_dup, alert);
+    if (alert->discrim->accountmask || alert->discrim->authed != -1)
+        dict_insert(opserv_account_alerts, name_dup, alert);
     return alert;
 }
 
@@ -3036,7 +3077,7 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in
                     discrim->max_ts = now - (ParseInterval(cmp+1) - 1);
                 }
             } else {
-                discrim->min_ts = now - ParseInterval(cmp+2);
+                discrim->min_ts = now - ParseInterval(cmp);
             }
         } else if (irccasecmp(argv[i], "access") == 0) {
             const char *cmp = argv[++i];
@@ -3056,7 +3097,7 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in
                     discrim->min_level = strtoul(cmp+1, NULL, 0) + 1;
                 }
             } else {
-                discrim->min_level = strtoul(cmp+2, NULL, 0);
+                discrim->min_level = strtoul(cmp, NULL, 0);
             }
         } else if ((irccasecmp(argv[i], "abuse") == 0)
                    && (irccasecmp(argv[++i], "opers") == 0)) {
@@ -3487,7 +3528,7 @@ opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[])
                 else
                     discrim->min_users = strtoul(cmp+1, NULL, 0) + 1;
             } else {
-                discrim->min_users = strtoul(cmp+2, NULL, 0);
+                discrim->min_users = strtoul(cmp, NULL, 0);
             }
        } else if (!irccasecmp(argv[i], "timestamp")) {
            const char *cmp = argv[++i];
@@ -3812,6 +3853,8 @@ opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_han
         send_channel_notice(opserv_conf.staff_auth_channel, opserv, IDENT_FORMAT" authed to %s account %s", IDENT_DATA(user), type, user->handle_info->handle);
     else
         send_channel_notice(opserv_conf.staff_auth_channel, opserv, "%s [%s@%s] authed to %s account %s", user->nick, user->ident, user->hostname, type, user->handle_info->handle);
+
+    dict_foreach(opserv_account_alerts, alert_check_user, user);
 }
 
 static MODCMD_FUNC(cmd_log)
@@ -3947,10 +3990,11 @@ static MODCMD_FUNC(cmd_delalert)
     for (i=1; i<argc; i++) {
         dict_remove(opserv_nick_based_alerts, argv[i]);
         dict_remove(opserv_channel_alerts, argv[i]);
-       if (dict_remove(opserv_user_alerts, argv[i]))
-           reply("OSMSG_REMOVED_ALERT", argv[i]);
+        dict_remove(opserv_account_alerts, argv[i]);
+        if (dict_remove(opserv_user_alerts, argv[i]))
+            reply("OSMSG_REMOVED_ALERT", argv[i]);
         else
-           reply("OSMSG_NO_SUCH_ALERT", argv[i]);
+            reply("OSMSG_NO_SUCH_ALERT", argv[i]);
     }
     return 1;
 }
@@ -4050,6 +4094,8 @@ opserv_db_init(void) {
     dict_set_free_keys(opserv_chan_warn, free);
     dict_set_free_data(opserv_chan_warn, free);
     /* set up opserv_user_alerts */
+    dict_delete(opserv_account_alerts);
+    opserv_account_alerts = dict_new();
     dict_delete(opserv_channel_alerts);
     opserv_channel_alerts = dict_new();
     dict_delete(opserv_nick_based_alerts);
@@ -4080,6 +4126,7 @@ opserv_db_cleanup(void)
     unreg_del_user_func(opserv_user_cleanup);
     dict_delete(opserv_hostinfo_dict);
     dict_delete(opserv_nick_based_alerts);
+    dict_delete(opserv_account_alerts);
     dict_delete(opserv_channel_alerts);
     dict_delete(opserv_user_alerts);
     for (nn=0; nn<ArrayLength(level_strings); ++nn)