]> jfr.im git - solanum.git/blobdiff - modules/m_kline.c
Add umode +I to allow users to hide their idle time (#220)
[solanum.git] / modules / m_kline.c
index 14f6bbb525c48637f6c6b59eeb91fb9215c9a7f2..b5d5acda5e9a67f1994673a8e9f91910acca3f99 100644 (file)
@@ -81,10 +81,23 @@ static void apply_prop_kline(struct Client *source_p, struct ConfItem *aconf,
 static bool already_placed_kline(struct Client *, const char *, const char *, int);
 
 static void handle_remote_unkline(struct Client *source_p, const char *user, const char *host);
+static void remove_superseded_klines(const char *user, const char *host);
 static void remove_permkline_match(struct Client *, struct ConfItem *);
 static bool remove_temp_kline(struct Client *, struct ConfItem *);
 static void remove_prop_kline(struct Client *, struct ConfItem *);
 
+static bool
+is_local_kline(struct ConfItem *aconf)
+{
+       return aconf->lifetime == 0;
+}
+
+static bool
+is_temporary_kline(struct ConfItem *aconf)
+{
+       return aconf->lifetime == 0 && (aconf->flags & CONF_FLAGS_TEMPORARY);
+}
+
 
 /* mo_kline()
  *
@@ -152,9 +165,31 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
        }
 
        reason = LOCAL_COPY(parv[loc]);
+       if(strlen(reason) > BANREASONLEN)
+       {
+               sendto_one_notice(source_p, ":K-Line reason exceeds %d characters", BANREASONLEN);
+               return;
+       }
+
+       if(parse_netmask_strict(host, NULL, NULL) == HM_ERROR)
+       {
+               sendto_one_notice(source_p,
+                               ":[%s@%s] looks like an ill-formed IP K-line, refusing to set it",
+                               user, host);
+               return;
+       }
 
        if(target_server != NULL)
        {
+               if (tkline_time)
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                       "%s is adding a temporary %d min. K-Line for [%s@%s] on %s [%s]",
+                                       get_oper_name(source_p), tkline_time / 60, user, host, target_server, reason);
+               else
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
+                                       "%s is adding a K-Line for [%s@%s] on %s [%s]",
+                                       get_oper_name(source_p), user, host, target_server, reason);
+
                propagate_generic(source_p, "KLINE", target_server, CAP_KLN,
                                  "%d %s %s :%s", tkline_time, user, host, reason);
 
@@ -192,6 +227,9 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
        if(already_placed_kline(source_p, user, host, tkline_time))
                return;
 
+       if (!propagated)
+               remove_superseded_klines(user, host);
+
        rb_set_time();
        aconf = make_conf();
        aconf->status = CONF_KILL;
@@ -201,9 +239,6 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
        aconf->port = 0;
        aconf->info.oper = operhash_add(get_oper_name(source_p));
 
-       if(strlen(reason) > BANREASONLEN)
-               reason[BANREASONLEN] = '\0';
-
        /* Look for an oper reason */
        if((oper_reason = strchr(reason, '|')) != NULL)
        {
@@ -275,11 +310,6 @@ handle_remote_kline(struct Client *source_p, int tkline_time,
        struct ConfItem *aconf = NULL;
        char *oper_reason;
 
-       if(!find_shared_conf(source_p->username, source_p->host,
-                            source_p->servptr->name,
-                            (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE))
-               return;
-
        if(!valid_user_host(source_p, user, host))
                return;
 
@@ -295,6 +325,8 @@ handle_remote_kline(struct Client *source_p, int tkline_time,
        if(already_placed_kline(source_p, user, host, tkline_time))
                return;
 
+       remove_superseded_klines(user, host);
+
        aconf = make_conf();
 
        aconf->status = CONF_KILL;
@@ -387,6 +419,9 @@ mo_unkline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sour
                        return;
                }
 
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is removing the K-Line for [%s@%s] on %s",
+                               get_oper_name(source_p), user, host, parv[3]);
+
                propagate_generic(source_p, "UNKLINE", parv[3], CAP_UNKLN, "%s %s", user, host);
 
                if(match(parv[3], me.name) == 0)
@@ -403,25 +438,30 @@ mo_unkline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sour
                cluster_generic(source_p, "UNKLINE", SHARED_UNKLINE, CAP_UNKLN,
                                "%s %s", user, host);
 
-       if(aconf == NULL)
+       bool removed_kline = false;
+
+       while (aconf = find_exact_conf_by_address_filtered(host, CONF_KILL, user, is_local_kline), aconf != NULL)
        {
-               sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
-               return;
+               removed_kline = true;
+
+               if(remove_temp_kline(source_p, aconf))
+                       continue;
+
+               remove_permkline_match(source_p, aconf);
        }
 
-       if(aconf->lifetime)
+       aconf = find_exact_conf_by_address(host, CONF_KILL, user);
+       if (aconf)
        {
-               if(propagated)
+               if (propagated)
                        remove_prop_kline(source_p, aconf);
                else
                        sendto_one_notice(source_p, ":Cannot remove global K-Line %s@%s on specific servers", user, host);
-               return;
        }
-
-       if(remove_temp_kline(source_p, aconf))
-               return;
-
-       remove_permkline_match(source_p, aconf);
+       else if (!removed_kline)
+       {
+               sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
+       }
 }
 
 /* ms_unkline()
@@ -460,27 +500,22 @@ static void
 handle_remote_unkline(struct Client *source_p, const char *user, const char *host)
 {
        struct ConfItem *aconf;
+       bool removed_kline = false;
 
-       if(!find_shared_conf(source_p->username, source_p->host,
-                            source_p->servptr->name, SHARED_UNKLINE))
-               return;
-
-       aconf = find_exact_conf_by_address(host, CONF_KILL, user);
-       if(aconf == NULL)
-       {
-               sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
-               return;
-       }
-       if(aconf->lifetime)
+       while (aconf = find_exact_conf_by_address_filtered(host, CONF_KILL, user, is_local_kline), aconf != NULL)
        {
-               sendto_one_notice(source_p, ":Cannot remove global K-Line %s@%s on specific servers", user, host);
-               return;
-       }
+               removed_kline = true;
 
-       if(remove_temp_kline(source_p, aconf))
-               return;
+               if(remove_temp_kline(source_p, aconf))
+                       continue;
+
+               remove_permkline_match(source_p, aconf);
+       }
 
-       remove_permkline_match(source_p, aconf);
+       if (find_exact_conf_by_address(host, CONF_KILL, user))
+               sendto_one_notice(source_p, ":Cannot remove global K-Line %s@%s on specific servers", user, host);
+       else if (!removed_kline)
+               sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
 }
 
 /* apply_kline()
@@ -569,7 +604,7 @@ apply_prop_kline(struct Client *source_p, struct ConfItem *aconf,
 
        replace_old_ban(aconf);
 
-       rb_dlinkAddAlloc(aconf, &prop_bans);
+       add_prop_ban(aconf);
        add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf);
 
        /* no oper reason.. */
@@ -700,15 +735,12 @@ already_placed_kline(struct Client *source_p, const char *luser, const char *lho
        if(aconf == NULL && ConfigFileEntry.non_redundant_klines)
        {
                bits = 0;
-               if((t = parse_netmask(lhost, &iphost, &bits)) != HM_HOST)
-               {
-                       if(t == HM_IPV6)
-                               t = AF_INET6;
-                       else
-                               t = AF_INET;
-
-                       piphost = &iphost;
-               }
+               t = parse_netmask_strict(lhost, &iphost, &bits);
+               piphost = &iphost;
+               if (t == HM_IPV4)
+                       t = AF_INET;
+               else if (t == HM_IPV6)
+                       t = AF_INET6;
                else
                        piphost = NULL;
 
@@ -726,21 +758,46 @@ already_placed_kline(struct Client *source_p, const char *luser, const char *lho
                                aconf = NULL;
                }
        }
-       if(aconf != NULL)
+
+       if (aconf == NULL)
+               return false;
+
+       /* allow klines to be duplicated by longer ones */
+       if ((aconf->flags & CONF_FLAGS_TEMPORARY) &&
+                       (tkline == 0 || tkline > aconf->hold - rb_current_time()))
+               return false;
+
+       reason = aconf->passwd ? aconf->passwd : "<No Reason>";
+
+       sendto_one_notice(source_p,
+                         ":[%s@%s] already K-Lined by [%s@%s] - %s",
+                         luser, lhost, aconf->user, aconf->host, reason);
+       return true;
+}
+
+static void
+remove_superseded_klines(const char *user, const char *host)
+{
+       struct ConfItem *aconf;
+
+       while (aconf = find_exact_conf_by_address_filtered(host, CONF_KILL, user, is_temporary_kline), aconf != NULL)
        {
-               /* setting a tkline, or existing one is perm */
-               if(tkline || ((aconf->flags & CONF_FLAGS_TEMPORARY) == 0))
-               {
-                       reason = aconf->passwd ? aconf->passwd : "<No Reason>";
+               rb_dlink_node *ptr;
+               int i;
 
-                       sendto_one_notice(source_p,
-                                         ":[%s@%s] already K-Lined by [%s@%s] - %s",
-                                         luser, lhost, aconf->user, aconf->host, reason);
-                       return true;
+               for (i = 0; i < LAST_TEMP_TYPE; i++)
+               {
+                       RB_DLINK_FOREACH(ptr, temp_klines[i].head)
+                       {
+                               if (aconf == ptr->data)
+                               {
+                                       rb_dlinkDestroy(ptr, &temp_klines[i]);
+                                       delete_one_address_conf(aconf->host, aconf);
+                                       break;
+                               }
+                       }
                }
        }
-
-       return false;
 }
 
 /* remove_permkline_match()
@@ -805,11 +862,9 @@ remove_temp_kline(struct Client *source_p, struct ConfItem *aconf)
 static void
 remove_prop_kline(struct Client *source_p, struct ConfItem *aconf)
 {
-       rb_dlink_node *ptr;
        time_t now;
 
-       ptr = rb_dlinkFind(aconf, &prop_bans);
-       if (!ptr)
+       if (!lookup_prop_ban(aconf))
                return;
        sendto_one_notice(source_p,
                          ":Un-klined [%s@%s] from global k-lines",
@@ -837,5 +892,5 @@ remove_prop_kline(struct Client *source_p, struct ConfItem *aconf)
                        0,
                        (int)(aconf->lifetime - aconf->created));
        remove_reject_mask(aconf->user, aconf->host);
-       deactivate_conf(aconf, ptr, now);
+       deactivate_conf(aconf, now);
 }