Replace privilege-controlling Feature settings with
[ircu2.10.12-pk.git] / ircd / client.c
index 0b4e4f93daed6282a1bc688e7e69a4e9116f728d..8bfdfe8a01a686413e6d80316c90a91847d599e5 100644 (file)
@@ -120,75 +120,9 @@ void client_add_sendq(struct Connection* con, struct Connection** con_p)
   }
 }
 
-enum FeatureFlag {
-  FEATFLAG_NULL,
-  FEATFLAG_DISABLES_PRIV,
-  FEATFLAG_ENABLES_PRIV,
-  FEATFLAG_GLOBAL_OPERS,
-  FEATFLAG_LOCAL_OPERS,
-  FEATFLAG_ALL_OPERS
-};
-
-static struct
-{
-  enum Priv priv;
-  enum Feature feat;
-  enum FeatureFlag flag;
-} feattab[] =
-  {
-    { PRIV_WHOX, FEAT_LAST_F, FEATFLAG_ALL_OPERS },
-    { PRIV_DISPLAY, FEAT_LAST_F, FEATFLAG_ALL_OPERS },
-    { PRIV_CHAN_LIMIT, FEAT_OPER_NO_CHAN_LIMIT, FEATFLAG_ALL_OPERS },
-    { PRIV_MODE_LCHAN, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS },
-    { PRIV_LOCAL_OPMODE, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS },
-    { PRIV_WALK_LCHAN, FEAT_OPER_WALK_THROUGH_LMODES, FEATFLAG_ALL_OPERS },
-    { PRIV_DEOP_LCHAN, FEAT_NO_OPER_DEOP_LCHAN, FEATFLAG_ALL_OPERS },
-    { PRIV_SHOW_INVIS, FEAT_SHOW_INVISIBLE_USERS, FEATFLAG_ALL_OPERS },
-    { PRIV_SHOW_ALL_INVIS, FEAT_SHOW_ALL_INVISIBLE_USERS, FEATFLAG_ALL_OPERS },
-    { PRIV_UNLIMIT_QUERY, FEAT_UNLIMIT_OPER_QUERY, FEATFLAG_ALL_OPERS },
-    
-    { PRIV_KILL, FEAT_LOCAL_KILL_ONLY, FEATFLAG_DISABLES_PRIV },
-    { PRIV_GLINE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV },
-    { PRIV_JUPE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV },
-    { PRIV_OPMODE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV },
-    { PRIV_BADCHAN, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV },
-    
-    { PRIV_PROPAGATE, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_SEE_OPERS, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_LOCAL_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_REHASH, FEAT_OPER_REHASH, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_RESTART, FEAT_OPER_RESTART, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_DIE, FEAT_OPER_DIE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_GLINE, FEAT_OPER_GLINE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_LOCAL_GLINE, FEAT_OPER_LGLINE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_JUPE, FEAT_OPER_JUPE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_LOCAL_JUPE, FEAT_OPER_LJUPE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_OPMODE, FEAT_OPER_OPMODE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_LOCAL_OPMODE, FEAT_OPER_LOPMODE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_FORCE_OPMODE, FEAT_OPER_FORCE_OPMODE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_FORCE_LOCAL_OPMODE, FEAT_OPER_FORCE_LOPMODE, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_BADCHAN, FEAT_OPER_BADCHAN, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_LOCAL_BADCHAN, FEAT_OPER_LBADCHAN, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_SET, FEAT_OPER_SET, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_SEE_CHAN, FEAT_OPERS_SEE_IN_SECRET_CHANNELS, FEATFLAG_GLOBAL_OPERS },
-    { PRIV_WIDE_GLINE, FEAT_OPER_WIDE_GLINE, FEATFLAG_GLOBAL_OPERS },
-    
-    { PRIV_LOCAL_KILL, FEAT_LOCOP_KILL, FEATFLAG_LOCAL_OPERS },
-    { PRIV_REHASH, FEAT_LOCOP_REHASH, FEATFLAG_LOCAL_OPERS },
-    { PRIV_RESTART, FEAT_LOCOP_RESTART, FEATFLAG_LOCAL_OPERS },
-    { PRIV_DIE, FEAT_LOCOP_DIE, FEATFLAG_LOCAL_OPERS },
-    { PRIV_LOCAL_GLINE, FEAT_LOCOP_LGLINE, FEATFLAG_LOCAL_OPERS },
-    { PRIV_LOCAL_JUPE, FEAT_LOCOP_LJUPE, FEATFLAG_LOCAL_OPERS },
-    { PRIV_LOCAL_OPMODE, FEAT_LOCOP_LOPMODE, FEATFLAG_LOCAL_OPERS },
-    { PRIV_FORCE_LOCAL_OPMODE, FEAT_LOCOP_FORCE_LOPMODE, FEATFLAG_LOCAL_OPERS },
-    { PRIV_LOCAL_BADCHAN, FEAT_LOCOP_LBADCHAN, FEATFLAG_LOCAL_OPERS },
-    { PRIV_SET, FEAT_LOCOP_SET, FEATFLAG_LOCAL_OPERS },
-    { PRIV_SEE_CHAN, FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, FEATFLAG_LOCAL_OPERS },
-    { PRIV_WIDE_GLINE, FEAT_LOCOP_WIDE_GLINE, FEATFLAG_LOCAL_OPERS },
-    
-    { PRIV_LAST_PRIV, FEAT_LAST_F, FEATFLAG_NULL }
-  };
+static struct Privs privs_global;
+static struct Privs privs_local;
+static int privs_defaults_set;
 
 /* client_set_privs(struct Client* client)
  *
@@ -197,8 +131,27 @@ static struct
 void
 client_set_privs(struct Client *client, struct ConfItem *oper)
 {
-  int i;
+  struct Privs *source, *defaults;
+  enum Priv priv;
 
+  if (!privs_defaults_set)
+  {
+    memset(&privs_global, -1, sizeof(privs_global));
+    memset(&privs_local, 0, sizeof(privs_local));
+    PrivSet(&privs_local, PRIV_CHAN_LIMIT);
+    PrivSet(&privs_local, PRIV_MODE_LCHAN);
+    PrivSet(&privs_local, PRIV_SHOW_INVIS);
+    PrivSet(&privs_local, PRIV_SHOW_ALL_INVIS);
+    PrivSet(&privs_local, PRIV_LOCAL_KILL);
+    PrivSet(&privs_local, PRIV_REHASH);
+    PrivSet(&privs_local, PRIV_LOCAL_GLINE);
+    PrivSet(&privs_local, PRIV_LOCAL_JUPE);
+    PrivSet(&privs_local, PRIV_LOCAL_OPMODE);
+    PrivSet(&privs_local, PRIV_WHOX);
+    PrivSet(&privs_local, PRIV_DISPLAY);
+    PrivSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
+    privs_defaults_set = 1;
+  }
   memset(&(cli_privs(client)), 0, sizeof(struct Privs));
 
   if (!IsAnOper(client))
@@ -212,49 +165,41 @@ client_set_privs(struct Client *client, struct ConfItem *oper)
   else if (oper == NULL)
     return;
 
-  /* Copy across privs from the config. */
-  cli_privs(client) = oper->privs;
+  /* Clear out client's privileges. */
+  memset(&cli_privs(client), 0, sizeof(struct Privs));
+
+  /* Decide whether to use global or local oper defaults. */
+  if (PrivHas(&oper->privs_dirty, PRIV_PROPAGATE))
+    defaults = PrivHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+  else if (PrivHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE))
+    defaults = PrivHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+  else
+      assert(0 && "Oper has no propagation and neither does connection class");
 
-  /* Now go through the features and set the non-dirty flags to their feature
-   * determined defaults...
+  /* For each feature, figure out whether it comes from the operator
+   * conf, the connection class conf, or the defaults, then apply it.
    */
-  for (i = 0; feattab[i].priv != PRIV_LAST_PRIV; i++)
+  for (priv = 0; priv < PRIV_LAST_PRIV; ++priv)
   {
-    if (PrivHas(&oper->privs_dirty, feattab[i].priv))
-      continue;
-    if (feattab[i].feat != FEAT_LAST_F && !feature_bool(feattab[i].feat))
-      continue;
-    switch (feattab[i].flag)
-    {
-    case FEATFLAG_ENABLES_PRIV:
-      if (!feature_bool(feattab[i].feat))
-        continue;
-      PrivSet(&cli_privs(client), feattab[i].priv);
-      continue;
-    case FEATFLAG_DISABLES_PRIV:
-      PrivClr(&cli_privs(client), feattab[i].priv);
-      continue;
-    case FEATFLAG_ALL_OPERS:
-      if (IsAnOper(client))
-        PrivSet(&cli_privs(client), feattab[i].priv);
-      continue;
-    case FEATFLAG_GLOBAL_OPERS:
-      if (IsOper(client))
-        PrivSet(&cli_privs(client), feattab[i].priv);
-      continue;
-    case FEATFLAG_LOCAL_OPERS:
-      if (IsLocOp(client))
-        PrivSet(&cli_privs(client), feattab[i].priv);
-      continue;
-    default:
-      continue;  /* ?? */
-    }
+    /* Figure out most applicable definition for the privilege. */
+    if (PrivHas(&oper->privs_dirty, priv))
+      source = &oper->privs;
+    else if (PrivHas(&oper->conn_class->privs_dirty, priv))
+      source = &oper->conn_class->privs;
+    else
+      source = defaults;
+
+    /* Set it if necessary (privileges were already cleared). */
+    if (PrivHas(source, priv))
+      PrivSet(&cli_privs(client), priv);
   }
 
   /* This should be handled in the config, but lets be sure... */
   if (PrivHas(&cli_privs(client), PRIV_PROPAGATE))
+  {
     /* force propagating opers to display */
     PrivSet(&cli_privs(client), PRIV_DISPLAY);
+  }
   else
   {
     /* if they don't propagate oper status, prevent desyncs */