X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fclient.c;h=b4d3afe8b3da73f304f7517c5e28dfe4a53286da;hb=e22c93b27e9f501b7869b310dff7df384e06f7e6;hp=3caa2ded01044ae4180ac10a6152cbaeadbc5abe;hpb=8a9e24acc77018edf12c6c83956d0d9af801c340;p=ircu2.10.12-pk.git diff --git a/ircd/client.c b/ircd/client.c index 3caa2de..b4d3afe 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -15,96 +15,268 @@ * 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 - -#define BAD_PING ((unsigned int)-2) +/* #include -- Now using assert in ircd_log.h */ +#include -/* - * 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. */ -unsigned int client_get_ping(const struct Client* acptr) +int client_get_ping(const struct Client* acptr) { - unsigned int ping = 0; - unsigned int tmp; + int ping = 0; struct ConfItem* aconf; struct SLink* link; - for (link = acptr->confs; link; link = link->next) { + assert(cli_verify(acptr)); + + for (link = cli_confs(acptr); link; link = link->next) { aconf = link->value.aconf; if (aconf->status & (CONF_CLIENT | CONF_SERVER)) { - tmp = get_conf_ping(aconf); - if ((tmp != BAD_PING) && ((ping > tmp) || !ping)) + int tmp = get_conf_ping(aconf); + if (0 < tmp && (ping > tmp || !ping)) ping = tmp; } } if (0 == ping) - ping = PINGFREQUENCY; + ping = feature_int(FEAT_PINGFREQUENCY); - Debug((DEBUG_DEBUG, "Client %s Ping %d", acptr->name, ping)); - return (ping); + Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping)); + + return ping; } -#if 0 -#define BAD_CONF_CLASS ((unsigned int)-1) -#define BAD_CLIENT_CLASS ((unsigned int)-3) +/** 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; +} -unsigned int get_client_class(struct Client *acptr) +/** 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) { - struct SLink *tmp; - struct ConnectionClass *cl; - unsigned int retc = BAD_CLIENT_CLASS; - - if (acptr && !IsMe(acptr) && (acptr->confs)) - for (tmp = acptr->confs; tmp; tmp = tmp->next) - { - if (!tmp->value.aconf || !(cl = tmp->value.aconf->confClass)) - continue; - if (ConClass(cl) > retc || retc == BAD_CLIENT_CLASS) - retc = ConClass(cl); - } + if (con_prev_p(con)) { /* on the queued data list... */ + if (con_next(con)) + con_prev_p(con_next(con)) = con_prev_p(con); + *(con_prev_p(con)) = con_next(con); - Debug((DEBUG_DEBUG, "Returning Class %d For %s", retc, acptr->name)); + con_next(con) = 0; + con_prev_p(con) = 0; + } +} + +/** 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) +{ + if (!con_prev_p(con)) { /* not on the queued data list yet... */ + con_prev_p(con) = con_p; + con_next(con) = *con_p; - return (retc); + if (*con_p) + con_prev_p(*con_p) = &(con_next(con)); + *con_p = con; + } } -unsigned int get_sendq(struct Client *cptr) +/** 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, struct ConfItem *oper) { - assert(0 != cptr); - assert(0 != cptr->local); - - if (cptr->max_sendq) - return cptr->max_sendq; - - else if (cptr->confs) { - struct SLink* tmp; - struct ConnectionClass* cl; - - for (tmp = cptr->confs; tmp; tmp = tmp->next) { - if (!tmp->value.aconf || !(cl = tmp->value.aconf->confClass)) - continue; - if (ConClass(cl) != BAD_CLIENT_CLASS) { - cptr->max_sendq = MaxSendq(cl); - return cptr->max_sendq; - } - } + 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); + } +} + +/** 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 } +}; + +/** 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_privs(struct Client* client) { + int privs = cli_privs(client); + + // add privs from class + struct SLink *list; + + for (list = cli_confs(cptr); list != NULL; list = list->next) { + struct ConfItem *aconf; + aconf = list->value.aconf; + if (aconf->status & CONF_CLIENT) + privs |= aconf->privs; } - return DEFAULTMAXSENDQLENGTH; + return privs; } -#endif +