+ struct Privs *source, *defaults;
+ enum Priv priv;
+
+ if (!MyConnect(client))
+ return;
+
+ /* Clear out client's privileges. */
+ memset(cli_privs(client), 0, sizeof(struct Privs));
+
+ if (!IsAnOper(client) || !oper)
+ return;
+
+ if (!privs_defaults_set)
+ {
+ memset(&privs_global, -1, sizeof(privs_global));
+ FlagClr(&privs_global, PRIV_WALK_LCHAN);
+ FlagClr(&privs_global, PRIV_UNLIMIT_QUERY);
+ FlagClr(&privs_global, PRIV_SET);
+ FlagClr(&privs_global, PRIV_BADCHAN);
+ FlagClr(&privs_global, PRIV_LOCAL_BADCHAN);
+ FlagClr(&privs_global, PRIV_APASS_OPMODE);
+
+ memset(&privs_local, 0, sizeof(privs_local));
+ FlagSet(&privs_local, PRIV_CHAN_LIMIT);
+ FlagSet(&privs_local, PRIV_MODE_LCHAN);
+ FlagSet(&privs_local, PRIV_SHOW_INVIS);
+ FlagSet(&privs_local, PRIV_SHOW_ALL_INVIS);
+ FlagSet(&privs_local, PRIV_LOCAL_KILL);
+ FlagSet(&privs_local, PRIV_REHASH);
+ FlagSet(&privs_local, PRIV_LOCAL_GLINE);
+ FlagSet(&privs_local, PRIV_LOCAL_JUPE);
+ FlagSet(&privs_local, PRIV_LOCAL_OPMODE);
+ FlagSet(&privs_local, PRIV_WHOX);
+ FlagSet(&privs_local, PRIV_DISPLAY);
+ FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
+
+ privs_defaults_set = 1;
+ }
+
+ /* Decide whether to use global or local oper defaults. */
+ if (FlagHas(&oper->privs_dirty, PRIV_PROPAGATE))
+ defaults = FlagHas(&oper->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+ else if (FlagHas(&oper->conn_class->privs_dirty, PRIV_PROPAGATE))
+ defaults = FlagHas(&oper->conn_class->privs, PRIV_PROPAGATE) ? &privs_global : &privs_local;
+ else {
+ assert(0 && "Oper has no propagation and neither does connection class");
+ return;
+ }
+
+ /* For each feature, figure out whether it comes from the operator
+ * conf, the connection class conf, or the defaults, then apply it.
+ */
+ for (priv = 0; priv < PRIV_LAST_PRIV; ++priv)
+ {
+ /* Figure out most applicable definition for the privilege. */
+ if (FlagHas(&oper->privs_dirty, priv))
+ source = &oper->privs;
+ else if (FlagHas(&oper->conn_class->privs_dirty, priv))
+ source = &oper->conn_class->privs;
+ else
+ source = defaults;
+
+ /* Set it if necessary (privileges were already cleared). */
+ if (FlagHas(source, priv))
+ SetPriv(client, priv);
+ }
+
+ /* This should be handled in the config, but lets be sure... */
+ if (HasPriv(client, PRIV_PROPAGATE))
+ {
+ /* force propagating opers to display */
+ SetPriv(client, PRIV_DISPLAY);
+ }
+ else
+ {
+ /* if they don't propagate oper status, prevent desyncs */
+ ClrPriv(client, PRIV_KILL);
+ ClrPriv(client, PRIV_GLINE);
+ ClrPriv(client, PRIV_JUPE);
+ ClrPriv(client, PRIV_OPMODE);
+ ClrPriv(client, PRIV_BADCHAN);