]> jfr.im git - solanum.git/blobdiff - modules/m_privs.c
chmode: Get elevated access for op-only queries
[solanum.git] / modules / m_privs.c
index a650203cab5a5bfa4c5f9f494f373ea69a47e64b..29e141ae0ced1c4e5836cea9b9c133f5d74bf9cf 100644 (file)
@@ -81,45 +81,57 @@ static struct mode_table auth_client_table[] = {
 
 DECLARE_MODULE_AV2(privs, NULL, NULL, privs_clist, NULL, NULL, NULL, NULL, privs_desc);
 
+static void append_priv(struct Client *source_p, struct Client *target_p, char *buf, const char *s1, const char *s2)
+{
+       /* 510 - ":" - " 270 " - " " - " :* " */
+       size_t sourcelen = strlen(source_p->name);
+       if (sourcelen < 9) sourcelen = 9;
+       size_t limit = 499 - strlen(me.name) - sourcelen - strlen(target_p->name);
+       if (strlen(s1) + strlen(s2) + strlen(buf) + 1 > limit)
+       {
+               sendto_one_numeric(source_p, RPL_PRIVS, "%s :* %s", target_p->name, buf);
+               buf[0] = '\0';
+       }
+       if (buf[0] != '\0')
+               rb_strlcat(buf, " ", BUFSIZE);
+       rb_strlcat(buf, s1, BUFSIZE);
+       rb_strlcat(buf, s2, BUFSIZE);
+}
+
 static void show_privs(struct Client *source_p, struct Client *target_p)
 {
-       char buf[512];
+       char buf[BUFSIZE];
        struct mode_table *p;
 
        buf[0] = '\0';
+
        if (target_p->user->privset)
-               rb_strlcat(buf, target_p->user->privset->privs, sizeof buf);
+               for (char *s = target_p->user->privset->privs; s != NULL; (s = strchr(s, ' ')) && s++)
+               {
+                       char *c = strchr(s, ' ');
+                       if (c) *c = '\0';
+                       append_priv(source_p, target_p, buf, s, "");
+                       if (c) *c = ' ';
+               }
+
        if (IsOper(target_p))
        {
                if (target_p->user->opername)
-               {
-                       if (buf[0] != '\0')
-                               rb_strlcat(buf, " ", sizeof buf);
-                       rb_strlcat(buf, "operator:", sizeof buf);
-                       rb_strlcat(buf, target_p->user->opername, sizeof buf);
-               }
+                       append_priv(source_p, target_p, buf, "operator:", target_p->user->opername);
 
                if (target_p->user->privset)
-               {
-                       if (buf[0] != '\0')
-                               rb_strlcat(buf, " ", sizeof buf);
-                       rb_strlcat(buf, "privset:", sizeof buf);
-                       rb_strlcat(buf, target_p->user->privset->name, sizeof buf);
-               }
+                       append_priv(source_p, target_p, buf, "privset:", target_p->user->privset->name);
        }
        p = &auth_client_table[0];
        while (p->name != NULL)
        {
                if (target_p->flags & p->mode)
-               {
-                       if (buf[0] != '\0')
-                               rb_strlcat(buf, " ", sizeof buf);
-                       rb_strlcat(buf, p->name, sizeof buf);
-               }
+                       append_priv(source_p, target_p, buf, p->name, "");
                p++;
        }
-       sendto_one_numeric(source_p, RPL_PRIVS, form_str(RPL_PRIVS),
-                       target_p->name, buf);
+
+       if (buf[0] != '\0')
+               sendto_one_numeric(source_p, RPL_PRIVS, "%s :%s", target_p->name, buf);
 }
 
 static void
@@ -165,6 +177,13 @@ mo_privs(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
                }
        }
 
+       if (target_p != source_p && !HasPrivilege(source_p, "oper:privs"))
+       {
+               sendto_one(source_p, form_str(ERR_NOPRIVS),
+                          me.name, source_p->name, "privs");
+               return;
+       }
+
        if (!IsServer(server_p))
                server_p = server_p->servptr;