/** Set the privileges for a client. * @param[in] client Client who has become an operator. * @param[in] oper Configuration item describing oper's privileges. */ void client_set_privs(struct Client *client, struct ConfItem *oper) { 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); #if defined(UNDERNET) FlagClr(&privs_global, PRIV_APASS_OPMODE); #endif 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); } }
int can_oper(struct Client *cptr, struct Client *sptr, char *name, char *password, struct ConfItem **_aconf) { struct ConfItem *aconf; aconf = find_conf_exact(name, sptr, CONF_OPERATOR); if (!aconf || IsIllegal(aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(no operator block)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } assert(0 != (aconf->status & CONF_OPERATOR)); if (!MyUser(sptr)) { if (FlagHas(&aconf->privs, PRIV_REMOTE)) { } else if (aconf->conn_class && FlagHas(&aconf->conn_class->privs, PRIV_REMOTE)) { } else { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(no remote oper priv)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } } if (!verify_sslclifp(sptr, aconf)) { send_reply(sptr, ERR_SSLCLIFP); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s " "(%s@%s) (SSL fingerprint mismatch)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } if (oper_password_match(password, aconf->passwd)) { if (MyUser(sptr)) { int attach_result = attach_conf(sptr, aconf); if ((ACR_OK != attach_result) && (ACR_ALREADY_AUTHORIZED != attach_result)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s " "(%s@%s) (no operator block)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } } *_aconf = aconf; return -1; } else { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(password mis-match)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } }