X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fclient.c;h=16367d15af183655ecc2a65a37da4ed9d41db0e5;hb=3e86180fb32d5eab15c761b75ba3d4520ef23bac;hp=17000c0650529d5c7cad3b676b8568371c36da3e;hpb=7a4d99a46663018958a866073c4fbb8b26f3cc86;p=ircu2.10.12-pk.git diff --git a/ircd/client.c b/ircd/client.c index 17000c0..16367d1 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -15,206 +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 -unsigned int client_get_ping(const struct Client* acptr) +/** 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) { - 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; - - Debug((DEBUG_DEBUG, "Client %s Ping %d", acptr->name, ping)); - return (ping); -} - -#if 0 -#define BAD_CONF_CLASS ((unsigned int)-1) -#define BAD_CLIENT_CLASS ((unsigned int)-3) - -unsigned int get_conf_class(struct ConfItem *aconf) -{ - if ((aconf) && (aconf->confClass)) - return (ConfClass(aconf)); + ping = feature_int(FEAT_PINGFREQUENCY); - Debug((DEBUG_DEBUG, "No Class For %s", (aconf) ? aconf->name : "*No Conf*")); - - return (BAD_CONF_CLASS); + Debug((DEBUG_DEBUG, "Client %s Ping %d", cli_name(acptr), ping)); + return ping; } -static unsigned int get_conf_ping(struct ConfItem *aconf) +/** 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) { - if ((aconf) && (aconf->confClass)) - return (ConfPingFreq(aconf)); + struct ConfItem* aconf; + struct SLink* link; - Debug((DEBUG_DEBUG, "No Ping For %s", (aconf) ? aconf->name : "*No Conf*")); + assert(cli_verify(sptr)); - return (BAD_PING); + 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 ConfClass *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)); - - return (retc); -} -unsigned int get_con_freq(struct ConfClass * clptr) -{ - if (clptr) - return (ConFreq(clptr)); - else - return (CONNECTFREQUENCY); + con_next(con) = 0; + con_prev_p(con) = 0; + } } -/* - * When adding a class, check to see if it is already present first. - * if so, then update the information for that class, rather than create - * a new entry for it and later delete the old entry. - * if no present entry is found, then create a new one and add it in - * immeadiately after the first one (class 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 add_class(unsigned int conClass, unsigned int ping, unsigned int confreq, - unsigned int maxli, unsigned int sendq) +void client_add_sendq(struct Connection* con, struct Connection** con_p) { - struct ConfClass *t, *p; + if (!con_prev_p(con)) { /* not on the queued data list yet... */ + con_prev_p(con) = con_p; + con_next(con) = *con_p; - t = find_class(conClass); - if ((t == classes) && (conClass != 0)) - { - p = (struct ConfClass *) make_class(); - NextClass(p) = NextClass(t); - NextClass(t) = p; + if (*con_p) + con_prev_p(*con_p) = &(con_next(con)); + *con_p = con; } - else - p = t; - Debug((DEBUG_DEBUG, "Add Class %u: p %p t %p - cf: %u pf: %u ml: %u sq: %d", - conClass, p, t, confreq, ping, maxli, sendq)); - ConClass(p) = conClass; - ConFreq(p) = confreq; - PingFreq(p) = ping; - MaxLinks(p) = maxli; - MaxSendq(p) = (sendq > 0) ? sendq : DEFAULTMAXSENDQLENGTH; - if (p != t) - Links(p) = 0; } -struct ConfClass *find_class(unsigned int cclass) +/** 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) { - struct ConfClass *cltmp; + struct Privs *source, *defaults; + enum Priv priv; - for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp)) - if (ConClass(cltmp) == cclass) - return cltmp; - return classes; -} + if (!MyConnect(client)) + return; -void check_class(void) -{ - struct ConfClass *cltmp, *cltmp2; + /* Clear out client's privileges. */ + memset(cli_privs(client), 0, sizeof(struct Privs)); - Debug((DEBUG_DEBUG, "Class check:")); + if (!IsAnOper(client) || !oper) + return; - for (cltmp2 = cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp2)) + if (!privs_defaults_set) { - Debug((DEBUG_DEBUG, - "Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %d", - ConClass(cltmp), ConFreq(cltmp), PingFreq(cltmp), - MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp))); - if (IsMarkedDelete(cltmp)) - { - NextClass(cltmp2) = NextClass(cltmp); - if (Links(cltmp) == 0) - free_class(cltmp); - } + 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 - cltmp2 = cltmp; + source = defaults; + + /* Set it if necessary (privileges were already cleared). */ + if (FlagHas(source, priv)) + SetPriv(client, priv); } -} -void initclass(void) -{ - classes = (struct ConfClass *) make_class(); - - ConClass(FirstClass()) = 0; - ConFreq(FirstClass()) = CONNECTFREQUENCY; - PingFreq(FirstClass()) = PINGFREQUENCY; - MaxLinks(FirstClass()) = MAXIMUM_LINKS; - MaxSendq(FirstClass()) = DEFAULTMAXSENDQLENGTH; - Links(FirstClass()) = 0; - NextClass(FirstClass()) = NULL; + /* 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); + } } -void report_classes(struct Client *sptr) +/** 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 ConfClass *cltmp; + struct MsgBuf *mb; + int found1 = 0; + int i; - for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp)) - send_reply(sptr, RPL_STATSYLINE, 'Y', ConClass(cltmp), PingFreq(cltmp), - ConFreq(cltmp), MaxLinks(cltmp), MaxSendq(cltmp)); + 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; } -unsigned int get_sendq(struct Client *cptr) -{ - assert(0 != cptr); - assert(0 != cptr->local); - - if (cptr->max_sendq) - return cptr->max_sendq; - - else if (cptr->confs) { - struct SLink* tmp; - struct ConfClass* 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; - } - } +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 DEFAULTMAXSENDQLENGTH; + return 0; } -#endif +