X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fclient.c;h=16367d15af183655ecc2a65a37da4ed9d41db0e5;hb=refs%2Fheads%2Fupstream;hp=33d45ee8ed92be94f0008bb6c21e654f4064e59b;hpb=9ba21beb4e8832a9a4f7355c096af81637bfa3df;p=ircu2.10.12-pk.git diff --git a/ircd/client.c b/ircd/client.c index 33d45ee..16367d1 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -15,29 +15,35 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ */ +/** @file + * @brief Implementation of functions for handling local clients. + * @version $Id$ + */ +#include "config.h" + #include "client.h" #include "class.h" #include "ircd.h" #include "ircd_features.h" +#include "ircd_log.h" #include "ircd_reply.h" #include "list.h" +#include "msgq.h" #include "numeric.h" #include "s_conf.h" #include "s_debug.h" #include "send.h" #include "struct.h" -#include +/* #include -- Now using assert in ircd_log.h */ +#include -#define BAD_PING ((unsigned int)-2) - -/* - * client_get_ping - * returns shortest ping time in attached server or client conf - * classes or PINGFREQUENCY +/** Find the shortest non-zero ping time attached to a client. + * If all attached ping times are zero, return the value for + * FEAT_PINGFREQUENCY. + * @param[in] acptr Client to find ping time for. + * @return Ping time in seconds. */ int client_get_ping(const struct Client* acptr) { @@ -45,6 +51,8 @@ int client_get_ping(const struct Client* acptr) struct ConfItem* aconf; struct SLink* link; + assert(cli_verify(acptr)); + for (link = cli_confs(acptr); link; link = link->next) { aconf = link->value.aconf; if (aconf->status & (CONF_CLIENT | CONF_SERVER)) { @@ -54,16 +62,34 @@ int client_get_ping(const struct Client* acptr) } } if (0 == ping) - ping = PINGFREQUENCY; + ping = feature_int(FEAT_PINGFREQUENCY); Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping)); + return ping; } -/* - * client_drop_sendq - * removes the client's connection from the list of connections with - * queued data +/** Find the default usermode for a client. + * @param[in] sptr Client to find default usermode for. + * @return Pointer to usermode string (or NULL, if there is no default). + */ +const char* client_get_default_umode(const struct Client* sptr) +{ + struct ConfItem* aconf; + struct SLink* link; + + assert(cli_verify(sptr)); + + for (link = cli_confs(sptr); link; link = link->next) { + aconf = link->value.aconf; + if ((aconf->status & CONF_CLIENT) && ConfUmode(aconf)) + return ConfUmode(aconf); + } + return NULL; +} + +/** Remove a connection from the list of connections with queued data. + * @param[in] con Connection with no queued data. */ void client_drop_sendq(struct Connection* con) { @@ -77,10 +103,9 @@ void client_drop_sendq(struct Connection* con) } } -/* - * client_add_sendq - * adds the client's connection to the list of connections with - * queued data +/** Add a connection to the list of connections with queued data. + * @param[in] con Connection with queued data. + * @param[in,out] con_p Previous pointer to next connection. */ void client_add_sendq(struct Connection* con, struct Connection** con_p) { @@ -94,102 +119,164 @@ void client_add_sendq(struct Connection* con, struct Connection** con_p) } } +/** Default privilege set for global operators. */ +static struct Privs privs_global; +/** Default privilege set for local operators. */ +static struct Privs privs_local; +/** Non-zero if #privs_global and #privs_local have been initialized. */ +static int privs_defaults_set; + /* client_set_privs(struct Client* client) * * Sets the privileges for opers. */ +/** 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) +client_set_privs(struct Client *client, struct ConfItem *oper) { - unsigned int privs = 0; - unsigned int antiprivs = 0; + struct Privs *source, *defaults; + enum Priv priv; - if (!IsAnOper(client)) { - cli_privs(client) = 0; /* clear privilege mask */ - return; - } else if (!MyConnect(client)) { - cli_privs(client) = ~(PRIV_SET); /* everything but set... */ + 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; } - /* This sequence is temporary until the .conf is carefully rewritten */ - - privs |= (PRIV_WHOX | PRIV_DISPLAY); - if (feature_bool(FEAT_OPER_NO_CHAN_LIMIT)) - privs |= PRIV_CHAN_LIMIT; - if (feature_bool(FEAT_OPER_MODE_LCHAN)) - privs |= (PRIV_MODE_LCHAN | PRIV_LOCAL_OPMODE); - if (feature_bool(FEAT_OPER_WALK_THROUGH_LMODES)) - privs |= PRIV_WALK_LCHAN; - if (feature_bool(FEAT_NO_OPER_DEOP_LCHAN)) - privs |= PRIV_DEOP_LCHAN; - if (feature_bool(FEAT_SHOW_INVISIBLE_USERS)) - privs |= PRIV_SHOW_INVIS; - if (feature_bool(FEAT_SHOW_ALL_INVISIBLE_USERS)) - privs |= PRIV_SHOW_ALL_INVIS; - if (feature_bool(FEAT_UNLIMIT_OPER_QUERY)) - privs |= PRIV_UNLIMIT_QUERY; - if (feature_bool(FEAT_LOCAL_KILL_ONLY)) - antiprivs |= PRIV_KILL; - if (!feature_bool(FEAT_CONFIG_OPERCMDS)) - antiprivs |= (PRIV_GLINE | PRIV_JUPE | PRIV_OPMODE | PRIV_BADCHAN); - - if (IsOper(client)) { - privs |= (PRIV_SET | PRIV_PROPAGATE | PRIV_SEE_OPERS); - if (feature_bool(FEAT_OPER_KILL)) - privs |= (PRIV_KILL | PRIV_LOCAL_KILL); - if (feature_bool(FEAT_OPER_REHASH)) - privs |= PRIV_REHASH; - if (feature_bool(FEAT_OPER_RESTART)) - privs |= PRIV_RESTART; - if (feature_bool(FEAT_OPER_DIE)) - privs |= PRIV_DIE; - if (feature_bool(FEAT_OPER_GLINE)) - privs |= PRIV_GLINE; - if (feature_bool(FEAT_OPER_LGLINE)) - privs |= PRIV_LOCAL_GLINE; - if (feature_bool(FEAT_OPER_JUPE)) - privs |= PRIV_JUPE; - if (feature_bool(FEAT_OPER_LJUPE)) - privs |= PRIV_LOCAL_JUPE; - if (feature_bool(FEAT_OPER_OPMODE)) - privs |= PRIV_OPMODE; - if (feature_bool(FEAT_OPER_LOPMODE)) - privs |= PRIV_LOCAL_OPMODE; - if (feature_bool(FEAT_OPER_BADCHAN)) - privs |= PRIV_BADCHAN; - if (feature_bool(FEAT_OPER_LBADCHAN)) - privs |= PRIV_LOCAL_BADCHAN; - if (feature_bool(FEAT_OPERS_SEE_IN_SECRET_CHANNELS)) - privs |= PRIV_SEE_CHAN; - } else { /* is a local operator */ - if (feature_bool(FEAT_LOCOP_KILL)) - privs |= PRIV_LOCAL_KILL; - if (feature_bool(FEAT_LOCOP_REHASH)) - privs |= PRIV_REHASH; - if (feature_bool(FEAT_LOCOP_RESTART)) - privs |= PRIV_RESTART; - if (feature_bool(FEAT_LOCOP_DIE)) - privs |= PRIV_DIE; - if (feature_bool(FEAT_LOCOP_LGLINE)) - privs |= PRIV_LOCAL_GLINE; - if (feature_bool(FEAT_LOCOP_LJUPE)) - privs |= PRIV_LOCAL_JUPE; - if (feature_bool(FEAT_LOCOP_LOPMODE)) - privs |= PRIV_LOCAL_OPMODE; - if (feature_bool(FEAT_LOCOP_LBADCHAN)) - privs |= PRIV_LOCAL_BADCHAN; - if (feature_bool(FEAT_LOCOP_SEE_IN_SECRET_CHANNELS)) - privs |= PRIV_SEE_CHAN; + /* 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; } - /* This is the end of the gross section */ + /* 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; - if (privs & PRIV_PROPAGATE) - privs |= PRIV_DISPLAY; + /* 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 - antiprivs |= (PRIV_KILL | PRIV_GLINE | PRIV_JUPE | PRIV_OPMODE | - PRIV_BADCHAN); + { + /* 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); + } +} + +/** Array mapping privilege values to names and vice versa. */ +static struct { + char *name; /**< Name of privilege. */ + unsigned int priv; /**< Enumeration value of privilege */ +} privtab[] = { +/** Helper macro to define an array entry for a privilege. */ +#define P(priv) { #priv, PRIV_ ## priv } + P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN), + P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL), + P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE), + P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE), + P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX), + P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE), + P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(LIST_CHAN), + P(FORCE_OPMODE), P(FORCE_LOCAL_OPMODE), P(APASS_OPMODE), +#undef P + { 0, 0 } +}; - cli_privs(client) = privs & ~antiprivs; +/** Report privileges of \a client to \a to. + * @param[in] to Client requesting privilege list. + * @param[in] client Client whos privileges should be listed. + * @return Zero. + */ +int +client_report_privs(struct Client *to, struct Client *client) +{ + struct MsgBuf *mb; + int found1 = 0; + int i; + + mb = msgq_make(to, rpl_str(RPL_PRIVS), cli_name(&me), cli_name(to), + cli_name(client)); + + for (i = 0; privtab[i].name; i++) + if (HasPriv(client, privtab[i].priv)) + msgq_append(0, mb, "%s%s", found1++ ? " " : "", privtab[i].name); + + send_buffer(to, mb, 0); /* send response */ + msgq_clean(mb); + + return 0; } + +int client_get_priv(struct Client* client, enum Priv priv) { + struct Privs *privs = &cli_privs(client); + struct SLink* list; + if(FlagHas(privs, priv)) + return 1; + + for (list = cli_confs(client); list != NULL; list = list->next) { + struct ConfItem *aconf; + aconf = list->value.aconf; + if (FlagHas(&aconf->privs, priv)) + return 1; + } + return 0; +} +