From 5ba09703da9f8f21f3278dc0222cd6fe077cfe31 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Tue, 7 Jan 2003 10:06:45 +0000 Subject: [PATCH] - The big forward port. I probably broke lots of stuff, so please look over any changes you made to .11 and make sure they are forward ported correctly. A lot of the ircd was changed. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@896 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- include/channel.h | 3 +- include/class.h | 4 +- include/client.h | 331 +++++++------- include/gline.h | 5 +- include/handlers.h | 7 +- include/ircd.h | 1 + include/ircd_features.h | 61 ++- include/listener.h | 5 +- include/motd.h | 5 +- include/msg.h | 8 + include/msgq.h | 7 +- include/numeric.h | 10 +- include/opercmds.h | 1 + include/s_conf.h | 13 +- include/s_debug.h | 7 +- include/s_misc.h | 4 +- include/s_stats.h | 28 +- include/s_user.h | 14 +- include/send.h | 3 + include/struct.h | 4 + include/supported.h | 4 +- include/userload.h | 4 +- include/whocmds.h | 10 +- ircd/IPcheck.c | 2 +- ircd/Makefile.in | 2 + ircd/channel.c | 89 ++-- ircd/class.c | 3 +- ircd/client.c | 164 ++++--- ircd/gline.c | 85 ++-- ircd/ircd.c | 67 ++- ircd/ircd_features.c | 62 ++- ircd/ircd_lexer.l | 2 + ircd/ircd_log.c | 9 +- ircd/ircd_parser.y | 51 ++- ircd/ircd_relay.c | 9 +- ircd/ircd_snprintf.c | 4 +- ircd/jupe.c | 47 +- ircd/list.c | 2 +- ircd/listener.c | 106 +++-- ircd/m_account.c | 7 +- ircd/m_admin.c | 10 +- ircd/m_asll.c | 175 ++++++++ ircd/m_away.c | 7 +- ircd/m_burst.c | 22 +- ircd/m_clearmode.c | 25 +- ircd/m_create.c | 28 +- ircd/m_gline.c | 42 +- ircd/m_invite.c | 5 +- ircd/m_join.c | 140 +++--- ircd/m_kick.c | 11 +- ircd/m_kill.c | 28 +- ircd/m_links.c | 76 +++- ircd/m_lusers.c | 4 +- ircd/m_map.c | 77 +++- ircd/m_mode.c | 10 +- ircd/m_motd.c | 4 +- ircd/m_names.c | 1 + ircd/m_nick.c | 61 ++- ircd/m_notice.c | 6 +- ircd/m_oper.c | 23 +- ircd/m_opmode.c | 18 +- ircd/m_part.c | 12 +- ircd/m_ping.c | 13 +- ircd/m_pong.c | 32 +- ircd/m_privmsg.c | 6 +- ircd/m_server.c | 2 - ircd/m_settime.c | 127 +++--- ircd/m_squit.c | 19 +- ircd/m_stats.c | 954 ++-------------------------------------- ircd/m_time.c | 7 +- ircd/m_topic.c | 16 +- ircd/m_trace.c | 17 +- ircd/m_version.c | 23 +- ircd/m_wallchops.c | 4 +- ircd/m_wallvoices.c | 154 +++++++ ircd/m_who.c | 10 +- ircd/m_whois.c | 47 +- ircd/m_whowas.c | 15 +- ircd/map.c | 6 +- ircd/motd.c | 50 ++- ircd/msgq.c | 317 ++++++++++--- ircd/numnicks.c | 10 +- ircd/opercmds.c | 23 + ircd/parse.c | 29 +- ircd/random.c | 2 +- ircd/s_auth.c | 34 +- ircd/s_bsd.c | 37 +- ircd/s_conf.c | 49 ++- ircd/s_debug.c | 32 +- ircd/s_err.c | 6 +- ircd/s_misc.c | 46 +- ircd/s_numeric.c | 31 +- ircd/s_stats.c | 481 +++++++++++++++----- ircd/s_user.c | 290 ++++++------ ircd/send.c | 69 ++- ircd/userload.c | 4 +- ircd/whocmds.c | 47 +- 97 files changed, 2908 insertions(+), 2136 deletions(-) create mode 100644 ircd/m_asll.c create mode 100644 ircd/m_wallvoices.c diff --git a/include/channel.h b/include/channel.h index ff39e43..d12072c 100644 --- a/include/channel.h +++ b/include/channel.h @@ -113,9 +113,8 @@ struct Client; #define is_listed(x) ((x)->mode.mode & MODE_LISTED) #define IsLocalChannel(name) (*(name) == '&') -#define IsModelessChannel(name) (*(name) == '+') #define IsChannelName(name) (*(name) == '#' || \ - IsModelessChannel(name) || IsLocalChannel(name)) + IsLocalChannel(name)) typedef enum ChannelGetType { CGT_NO_CREATE, diff --git a/include/class.h b/include/class.h index 0e19746..df53e16 100644 --- a/include/class.h +++ b/include/class.h @@ -28,6 +28,7 @@ struct Client; struct ConfItem; +struct StatDesc; /* * Structures @@ -81,7 +82,8 @@ extern char *get_client_class(struct Client *acptr); extern void add_class(char *name, unsigned int ping, unsigned int confreq, unsigned int maxli, unsigned int sendq); extern void check_class(void); -extern void report_classes(struct Client *sptr); +extern void report_classes(struct Client *sptr, struct StatDesc *sd, int stat, + char *param); extern unsigned int get_sendq(struct Client* cptr); extern void class_send_meminfo(struct Client* cptr); diff --git a/include/client.h b/include/client.h index 3522c40..4d61472 100644 --- a/include/client.h +++ b/include/client.h @@ -66,51 +66,99 @@ struct AuthRequest; * source file, or in the source file itself (when only used in that file). */ -#define PRIV_CHAN_LIMIT 1 /* no channel limit on oper */ -#define PRIV_MODE_LCHAN 2 /* oper can mode local chans */ -#define PRIV_WALK_LCHAN 3 /* oper can walk thru local modes */ -#define PRIV_DEOP_LCHAN 4 /* no deop oper on local chans */ -#define PRIV_SHOW_INVIS 5 /* show local invisible users */ -#define PRIV_SHOW_ALL_INVIS 6 /* show all invisible users */ -#define PRIV_UNLIMIT_QUERY 7 /* unlimit who queries */ - -#define PRIV_KILL 8 /* oper can KILL */ -#define PRIV_LOCAL_KILL 9 /* oper can local KILL */ -#define PRIV_REHASH 10 /* oper can REHASH */ -#define PRIV_RESTART 11 /* oper can RESTART */ -#define PRIV_DIE 12 /* oper can DIE */ -#define PRIV_GLINE 13 /* oper can GLINE */ -#define PRIV_LOCAL_GLINE 14 /* oper can local GLINE */ -#define PRIV_JUPE 15 /* oper can JUPE */ -#define PRIV_LOCAL_JUPE 16 /* oper can local JUPE */ -#define PRIV_OPMODE 17 /* oper can OP/CLEARMODE */ -#define PRIV_LOCAL_OPMODE 18 /* oper can local OP/CLEARMODE */ -#define PRIV_SET 19 /* oper can SET */ -#define PRIV_WHOX 20 /* oper can use /who x */ -#define PRIV_BADCHAN 21 /* oper can BADCHAN */ -#define PRIV_LOCAL_BADCHAN 22 /* oper can local BADCHAN */ -#define PRIV_SEE_CHAN 23 /* oper can see in secret chans */ - -#define PRIV_PROPAGATE 24 /* propagate oper status */ -#define PRIV_DISPLAY 25 /* "Is an oper" displayed */ -#define PRIV_SEE_OPERS 26 /* display hidden opers */ - -#define PRIV_WIDE_GLINE 27 /* oper can set wider G-lines */ - -#define PRIV_LIST_CHAN 28 /* oper can list secret channels */ - -#define PRIV_LAST_PRIV 28 /* must be the same as the last priv */ - -#define _PRIV_NBITS (8 * sizeof(unsigned long)) - -#define _PRIV_IDX(priv) ((priv) / _PRIV_NBITS) -#define _PRIV_BIT(priv) (1 << ((priv) % _PRIV_NBITS)) - -struct Privs { - unsigned long priv_mask[(PRIV_LAST_PRIV / _PRIV_NBITS) + 1]; -}; - -struct Connection { +typedef unsigned long flagpage_t; + +#define FLAGSET_NBITS (8 * sizeof(flagpage_t)) +#define FLAGSET_INDEX(flag) (flag / FLAGSET_NBITS) +#define FLAGSET_MASK(flag) (1<<(flag % FLAGSET_NBITS)) + +#define DECLARE_FLAGSET(name,max) \ + struct name \ + { \ + unsigned long bits[((max + FLAGSET_NBITS - 1) / FLAGSET_NBITS)]; \ + }; + +#define FLAGSET_ISSET(set,flag) ((set).bits[FLAGSET_INDEX(flag)] & FLAGSET_MASK(flag)) +#define FLAGSET_SET(set, flag) (set).bits[FLAGSET_INDEX(flag)] |= FLAGSET_MASK(flag) +#define FLAGSET_CLEAR(set, flag) (set).bits[FLAGSET_INDEX(flag)] &= ~FLAGSET_MASK(flag) + +enum Priv + { + PRIV_CHAN_LIMIT, /* no channel limit on oper */ + PRIV_MODE_LCHAN, /* oper can mode local chans */ + PRIV_WALK_LCHAN, /* oper can walk thru local modes */ + PRIV_DEOP_LCHAN, /* no deop oper on local chans */ + PRIV_SHOW_INVIS, /* show local invisible users */ + PRIV_SHOW_ALL_INVIS, /* show all invisible users */ + PRIV_UNLIMIT_QUERY, /* unlimit who queries */ + PRIV_KILL, /* oper can KILL */ + PRIV_LOCAL_KILL, /* oper can local KILL */ + PRIV_REHASH, /* oper can REHASH */ + PRIV_RESTART, /* oper can RESTART */ + PRIV_DIE, /* oper can DIE */ + PRIV_GLINE, /* oper can GLINE */ + PRIV_LOCAL_GLINE, /* oper can local GLINE */ + PRIV_JUPE, /* oper can JUPE */ + PRIV_LOCAL_JUPE, /* oper can local JUPE */ + PRIV_OPMODE, /* oper can OP/CLEARMODE */ + PRIV_LOCAL_OPMODE, /* oper can local OP/CLEARMODE */ + PRIV_SET, /* oper can SET */ + PRIV_WHOX, /* oper can use /who x */ + PRIV_BADCHAN, /* oper can BADCHAN */ + PRIV_LOCAL_BADCHAN, /* oper can local BADCHAN */ + PRIV_SEE_CHAN, /* oper can see in secret chans */ + PRIV_PROPAGATE, /* propagate oper status */ + PRIV_DISPLAY, /* "Is an oper" displayed */ + PRIV_SEE_OPERS, /* display hidden opers */ + PRIV_WIDE_GLINE, /* oper can set wider G-lines */ + PRIV_LIST_CHAN, /* oper can list secret channels */ + PRIV_FORCE_OPMODE, + PRIV_FORCE_LOCAL_OPMODE, + PRIV_LAST_PRIV /* must be the same as the last priv */ + }; + +enum Flag + { + FLAG_PINGSENT, /* Unreplied ping sent */ + FLAG_DEADSOCKET, /* Local socket is dead--Exiting soon */ + FLAG_KILLED, /* Prevents "QUIT" from being sent for this */ + FLAG_BLOCKED, /* socket is in a blocked condition */ + FLAG_CLOSING, /* set when closing to suppress errors */ + FLAG_UPING, /* has active UDP ping request */ + FLAG_CHKACCESS, /* ok to check clients access if set */ + FLAG_HUB, /* server is a hub */ + FLAG_SERVICE, /* server is a service */ + FLAG_LOCAL, /* set for local clients */ + FLAG_GOTID, /* successful ident lookup achieved */ + FLAG_DOID, /* I-lines say must use ident return */ + FLAG_NONL, /* No \n in buffer */ + FLAG_TS8, /* Why do you want to know? */ + FLAG_MAP, /* Show server on the map */ + FLAG_JUNCTION, /* Junction causing the net.burst */ + FLAG_BURST, /* Server is receiving a net.burst */ + FLAG_BURST_ACK, /* Server is waiting for eob ack */ + FLAG_IPCHECK, /* Added or updated IPregistry data */ + FLAG_LOCOP, /* Local operator -- SRB */ + FLAG_SERVNOTICE, /* server notices such as kill */ + FLAG_OPER, /* Operator */ + FLAG_INVISIBLE, /* makes user invisible */ + FLAG_WALLOP, /* send wallops to them */ + FLAG_DEAF, /* Makes user deaf */ + FLAG_CHSERV, /* Disallow KICK or MODE -o on the user; + don't display channels in /whois */ + FLAG_DEBUG, /* send global debug/anti-hack info */ + FLAG_ACCOUNT, /* account name has been set */ + FLAG_HIDDENHOST, /* user's host is hidden */ + FLAG_LAST_FLAG, + FLAG_LOCAL_UMODES = FLAG_LOCOP, /* First local mode flag */ + FLAG_GLOBAL_UMODES = FLAG_OPER /* First global mode flag */ + }; + +DECLARE_FLAGSET(Privs, PRIV_LAST_PRIV); +DECLARE_FLAGSET(Flags, FLAG_LAST_FLAG); + +struct Connection +{ /* * The following fields are allocated only for local clients * (directly connected to *this* server with a socket. @@ -187,7 +235,7 @@ struct Client { time_t cli_firsttime; /* time client was created */ time_t cli_lastnick; /* TimeStamp on nick */ int cli_marker; /* /who processing marker */ - unsigned int cli_flags; /* client flags */ + struct Flags cli_flags; /* client flags */ unsigned int cli_hopcount; /* number of servers to this 0 = local */ struct in_addr cli_ip; /* Real ip# NOT defined for remote servers! */ short cli_status; /* Client type */ @@ -346,110 +394,81 @@ struct Client { (STAT_SERVER | STAT_CONNECTING | STAT_HANDSHAKE)) /* - * FLAGS macros - */ -#define FLAGS_PINGSENT 0x0001 /* Unreplied ping sent */ -#define FLAGS_DEADSOCKET 0x0002 /* Local socket is dead--Exiting soon */ -#define FLAGS_KILLED 0x0004 /* Prevents "QUIT" from being sent for this */ -#define FLAGS_OPER 0x0008 /* Operator */ -#define FLAGS_LOCOP 0x0010 /* Local operator -- SRB */ -#define FLAGS_INVISIBLE 0x0020 /* makes user invisible */ -#define FLAGS_WALLOP 0x0040 /* send wallops to them */ -#define FLAGS_SERVNOTICE 0x0080 /* server notices such as kill */ -#define FLAGS_BLOCKED 0x0100 /* socket is in a blocked condition */ -#define FLAGS_ACCOUNT 0x0200 /* account name has been set */ -#define FLAGS_CLOSING 0x0400 /* set when closing to suppress errors */ -#define FLAGS_UPING 0x0800 /* has active UDP ping request */ -#define FLAGS_CHKACCESS 0x1000 /* ok to check clients access if set */ -#define FLAGS_HUB 0x2000 /* server is a hub */ -#define FLAGS_SERVICE 0x4000 /* server is a service */ -#define FLAGS_HIDDENHOST 0x8000 /* user's host is hidden */ -#define FLAGS_LOCAL 0x00010000 /* set for local clients */ -#define FLAGS_GOTID 0x00020000 /* successful ident lookup achieved */ -#define FLAGS_DOID 0x00040000 /* I-lines say must use ident return */ -#define FLAGS_NONL 0x00080000 /* No \n in buffer */ -#define FLAGS_TS8 0x00100000 /* Why do you want to know? */ -#define FLAGS_MAP 0x00800000 /* Show server on the map */ -#define FLAGS_JUNCTION 0x01000000 /* Junction causing the net.burst */ -#define FLAGS_DEAF 0x02000000 /* Makes user deaf */ -#define FLAGS_CHSERV 0x04000000 /* Disallow KICK or MODE -o on the user; - don't display channels in /whois */ -#define FLAGS_BURST 0x08000000 /* Server is receiving a net.burst */ -#define FLAGS_BURST_ACK 0x10000000 /* Server is waiting for eob ack */ -#define FLAGS_DEBUG 0x20000000 /* send global debug/anti-hack info */ -#define FLAGS_IPCHECK 0x40000000 /* Added or updated IPregistry data */ - -#define SEND_UMODES \ - (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_DEAF|FLAGS_CHSERV|FLAGS_DEBUG|FLAGS_ACCOUNT|FLAGS_HIDDENHOST) -#define ALL_UMODES (SEND_UMODES|FLAGS_SERVNOTICE|FLAGS_LOCOP) -#define FLAGS_ID (FLAGS_DOID|FLAGS_GOTID) - -/* - * flags macros. + * flags macros */ -#define DoAccess(x) (cli_flags(x) & FLAGS_CHKACCESS) -#define IsAnOper(x) (cli_flags(x) & (FLAGS_OPER|FLAGS_LOCOP)) -#define IsBlocked(x) (cli_flags(x) & FLAGS_BLOCKED) -#define IsBurst(x) (cli_flags(x) & FLAGS_BURST) -#define IsBurstAck(x) (cli_flags(x) & FLAGS_BURST_ACK) -#define IsBurstOrBurstAck(x) (cli_flags(x) & (FLAGS_BURST|FLAGS_BURST_ACK)) -#define IsChannelService(x) (cli_flags(x) & FLAGS_CHSERV) -#define IsDead(x) (cli_flags(x) & FLAGS_DEADSOCKET) -#define IsDeaf(x) (cli_flags(x) & FLAGS_DEAF) -#define IsIPChecked(x) (cli_flags(x) & FLAGS_IPCHECK) -#define IsIdented(x) (cli_flags(x) & FLAGS_GOTID) -#define IsInvisible(x) (cli_flags(x) & FLAGS_INVISIBLE) -#define IsJunction(x) (cli_flags(x) & FLAGS_JUNCTION) -#define IsLocOp(x) (cli_flags(x) & FLAGS_LOCOP) -#define IsLocal(x) (cli_flags(x) & FLAGS_LOCAL) -#define IsOper(x) (cli_flags(x) & FLAGS_OPER) -#define IsUPing(x) (cli_flags(x) & FLAGS_UPING) -#define NoNewLine(x) (cli_flags(x) & FLAGS_NONL) -#define SendDebug(x) (cli_flags(x) & FLAGS_DEBUG) -#define SendServNotice(x) (cli_flags(x) & FLAGS_SERVNOTICE) -#define SendWallops(x) (cli_flags(x) & FLAGS_WALLOP) -#define IsHub(x) (cli_flags(x) & FLAGS_HUB) -#define IsService(x) (cli_flags(x) & FLAGS_SERVICE) -#define IsAccount(x) (cli_flags(x) & FLAGS_ACCOUNT) -#define IsHiddenHost(x) (cli_flags(x) & FLAGS_HIDDENHOST) -#define HasHiddenHost(x) (IsAccount(x) && IsHiddenHost(x)) +#define FlagSet(fset, flag) FLAGSET_SET(*fset, flag) +#define FlagClr(fset, flag) FLAGSET_CLEAR(*fset, flag) +#define FlagHas(fset, flag) FLAGSET_ISSET(*fset, flag) +#define SetFlag(cli, flag) FlagSet(&cli_flags(cli), flag) +#define ClrFlag(cli, flag) FlagClr(&cli_flags(cli), flag) +#define HasFlag(cli, flag) FlagHas(&cli_flags(cli), flag) + +#define DoAccess(x) HasFlag(x, FLAG_CHKACCESS) +#define IsAnOper(x) (HasFlag(x, FLAG_OPER) || HasFlag(x, FLAG_LOCOP)) +#define IsBlocked(x) HasFlag(x, FLAG_BLOCKED) +#define IsBurst(x) HasFlag(x, FLAG_BURST) +#define IsBurstAck(x) HasFlag(x, FLAG_BURST_ACK) +#define IsBurstOrBurstAck(x) (HasFlag(x, FLAG_BURST) || HasFlag(x, FLAG_BURST_ACK)) +#define IsChannelService(x) HasFlag(x, FLAG_CHSERV) +#define IsDead(x) HasFlag(x, FLAG_DEADSOCKET) +#define IsDeaf(x) HasFlag(x, FLAG_DEAF) +#define IsIPChecked(x) HasFlag(x, FLAG_IPCHECK) +#define IsIdented(x) HasFlag(x, FLAG_GOTID) +#define IsInvisible(x) HasFlag(x, FLAG_INVISIBLE) +#define IsJunction(x) HasFlag(x, FLAG_JUNCTION) +#define IsLocOp(x) HasFlag(x, FLAG_LOCOP) +#define IsLocal(x) HasFlag(x, FLAG_LOCAL) +#define IsOper(x) HasFlag(x, FLAG_OPER) +#define IsUPing(x) HasFlag(x, FLAG_UPING) +#define NoNewLine(x) HasFlag(x, FLAG_NONL) +#define SendDebug(x) HasFlag(x, FLAG_DEBUG) +#define SendServNotice(x) HasFlag(x, FLAG_SERVNOTICE) +#define SendWallops(x) HasFlag(x, FLAG_WALLOP) +#define IsHub(x) HasFlag(x, FLAG_HUB) +#define IsService(x) HasFlag(x, FLAG_SERVICE) +#define IsAccount(x) HasFlag(x, FLAG_ACCOUNT) +#define IsHiddenHost(x) HasFlag(x, FLAG_HIDDENHOST) +#define IsPingSent(x) HasFlag(x, FLAG_PINGSENT) #define IsPrivileged(x) (IsAnOper(x) || IsServer(x)) - -#define SetAccess(x) (cli_flags(x) |= FLAGS_CHKACCESS) -#define SetBurst(x) (cli_flags(x) |= FLAGS_BURST) -#define SetBurstAck(x) (cli_flags(x) |= FLAGS_BURST_ACK) -#define SetChannelService(x) (cli_flags(x) |= FLAGS_CHSERV) -#define SetDeaf(x) (cli_flags(x) |= FLAGS_DEAF) -#define SetDebug(x) (cli_flags(x) |= FLAGS_DEBUG) -#define SetGotId(x) (cli_flags(x) |= FLAGS_GOTID) -#define SetIPChecked(x) (cli_flags(x) |= FLAGS_IPCHECK) -#define SetInvisible(x) (cli_flags(x) |= FLAGS_INVISIBLE) -#define SetJunction(x) (cli_flags(x) |= FLAGS_JUNCTION) -#define SetLocOp(x) (cli_flags(x) |= FLAGS_LOCOP) -#define SetOper(x) (cli_flags(x) |= FLAGS_OPER) -#define SetUPing(x) (cli_flags(x) |= FLAGS_UPING) -#define SetWallops(x) (cli_flags(x) |= FLAGS_WALLOP) -#define SetServNotice(x) (cli_flags(x) |= FLAGS_SERVNOTICE) -#define SetHub(x) (cli_flags(x) |= FLAGS_HUB) -#define SetService(x) (cli_flags(x) |= FLAGS_SERVICE) -#define SetAccount(x) (cli_flags(x) |= FLAGS_ACCOUNT) -#define SetHiddenHost(x) (cli_flags(x) |= FLAGS_HIDDENHOST) - -#define ClearAccess(x) (cli_flags(x) &= ~FLAGS_CHKACCESS) -#define ClearBurst(x) (cli_flags(x) &= ~FLAGS_BURST) -#define ClearBurstAck(x) (cli_flags(x) &= ~FLAGS_BURST_ACK) -#define ClearChannelService(x) (cli_flags(x) &= ~FLAGS_CHSERV) -#define ClearDeaf(x) (cli_flags(x) &= ~FLAGS_DEAF) -#define ClearDebug(x) (cli_flags(x) &= ~FLAGS_DEBUG) -#define ClearIPChecked(x) (cli_flags(x) &= ~FLAGS_IPCHECK) -#define ClearInvisible(x) (cli_flags(x) &= ~FLAGS_INVISIBLE) -#define ClearLocOp(x) (cli_flags(x) &= ~FLAGS_LOCOP) -#define ClearOper(x) (cli_flags(x) &= ~FLAGS_OPER) -#define ClearUPing(x) (cli_flags(x) &= ~FLAGS_UPING) -#define ClearWallops(x) (cli_flags(x) &= ~FLAGS_WALLOP) -#define ClearServNotice(x) (cli_flags(x) &= ~FLAGS_SERVNOTICE) -#define ClearHiddenHost(x) (cli_flags(x) &= ~FLAGS_HIDDENHOST) +#define HasHiddenHost(x) (IsHiddenHost(x) && IsAccount(x)) + +#define SetAccess(x) SetFlag(x, FLAG_CHKACCESS) +#define SetBurst(x) SetFlag(x, FLAG_BURST) +#define SetBurstAck(x) SetFlag(x, FLAG_BURST_ACK) +#define SetChannelService(x) SetFlag(x, FLAG_CHSERV) +#define SetDeaf(x) SetFlag(x, FLAG_DEAF) +#define SetDebug(x) SetFlag(x, FLAG_DEBUG) +#define SetGotId(x) SetFlag(x, FLAG_GOTID) +#define SetIPChecked(x) SetFlag(x, FLAG_IPCHECK) +#define SetInvisible(x) SetFlag(x, FLAG_INVISIBLE) +#define SetJunction(x) SetFlag(x, FLAG_JUNCTION) +#define SetLocOp(x) SetFlag(x, FLAG_LOCOP) +#define SetOper(x) SetFlag(x, FLAG_OPER) +#define SetUPing(x) SetFlag(x, FLAG_UPING) +#define SetWallops(x) SetFlag(x, FLAG_WALLOP) +#define SetServNotice(x) SetFlag(x, FLAG_SERVNOTICE) +#define SetHub(x) SetFlag(x, FLAG_HUB) +#define SetService(x) SetFlag(x, FLAG_SERVICE) +#define SetAccount(x) SetFlag(x, FLAG_ACCOUNT) +#define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST) +#define SetPingSent(x) SetFlag(x, FLAG_PINGSENT) + +#define ClearAccess(x) ClrFlag(x, FLAG_CHKACCESS) +#define ClearBurst(x) ClrFlag(x, FLAG_BURST) +#define ClearBurstAck(x) ClrFlag(x, FLAG_BURST_ACK) +#define ClearChannelService(x) ClrFlag(x, FLAG_CHSERV) +#define ClearDeaf(x) ClrFlag(x, FLAG_DEAF) +#define ClearDebug(x) ClrFlag(x, FLAG_DEBUG) +#define ClearIPChecked(x) ClrFlag(x, FLAG_IPCHECK) +#define ClearInvisible(x) ClrFlag(x, FLAG_INVISIBLE) +#define ClearLocOp(x) ClrFlag(x, FLAG_LOCOP) +#define ClearOper(x) ClrFlag(x, FLAG_OPER) +#define ClearUPing(x) ClrFlag(x, FLAG_UPING) +#define ClearWallops(x) ClrFlag(x, FLAG_WALLOP) +#define ClearServNotice(x) ClrFlag(x, FLAG_SERVNOTICE) +#define ClearHiddenHost(x) ClrFlag(x, FLAG_HIDDENHOST) +#define ClearPingSent(x) ClrFlag(x, FLAG_PINGSENT) /* free flags */ #define FREEFLAG_SOCKET 0x0001 /* socket needs to be freed */ @@ -477,13 +496,14 @@ struct Client { #define SNO_THROTTLE 0x1000 /* host throttle add/remove notices */ #define SNO_OLDREALOP 0x2000 /* old oper-only messages */ #define SNO_CONNEXIT 0x4000 /* client connect/exit (ugh) */ -#define SNO_DEBUG 0x8000 /* debugging messages (DEBUGMODE only) */ +#define SNO_AUTO 0x8000 /* AUTO G-Lines */ +#define SNO_DEBUG 0x10000 /* debugging messages (DEBUGMODE only) */ #ifdef DEBUGMODE -# define SNO_ALL 0xffff /* Don't make it larger then significant, - * that looks nicer */ +# define SNO_ALL 0x1ffff /* Don't make it larger then significant, + * that looks nicer */ #else -# define SNO_ALL 0x7fff +# define SNO_ALL 0xffff #endif #define SNO_USER (SNO_ALL & ~SNO_OPER) @@ -493,12 +513,9 @@ struct Client { #define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP) #define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH) -#define PrivSet(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] |= \ - _PRIV_BIT(priv)) -#define PrivClr(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] &= \ - ~(_PRIV_BIT(priv))) -#define PrivHas(pset, priv) ((pset)->priv_mask[_PRIV_IDX(priv)] & \ - _PRIV_BIT(priv)) +#define PrivSet(fset, flag) FLAGSET_SET(*fset, flag) +#define PrivClr(fset, flag) FLAGSET_CLEAR(*fset, flag) +#define PrivHas(fset, flag) FLAGSET_ISSET(*fset, flag) #define GrantPriv(cli, priv) (PrivSet(&(cli_privs(cli)), priv)) #define RevokePriv(cli, priv) (PrivClr(&(cli_privs(cli)), priv)) diff --git a/include/gline.h b/include/gline.h index ec10009..3be3bd9 100644 --- a/include/gline.h +++ b/include/gline.h @@ -30,6 +30,7 @@ #include struct Client; +struct StatDesc; #define GLINE_MAX_EXPIRE 604800 /* max expire: 7 days */ @@ -90,6 +91,8 @@ extern void gline_free(struct Gline *gline); extern void gline_burst(struct Client *cptr); extern int gline_resend(struct Client *cptr, struct Gline *gline); extern int gline_list(struct Client *sptr, char *userhost); -extern void gline_stats(struct Client *sptr); +extern void gline_stats(struct Client *sptr, struct StatDesc *sd, int stat, + char *param); +extern int gline_memory_count(size_t *gl_size); #endif /* INCLUDED_gline_h */ diff --git a/include/handlers.h b/include/handlers.h index e65ab88..55abeaa 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -85,6 +85,7 @@ struct Client; extern int m_admin(struct Client*, struct Client*, int, char*[]); +extern int ms_asll(struct Client*, struct Client*, int, char*[]); extern int m_away(struct Client*, struct Client*, int, char*[]); extern int m_cnotice(struct Client*, struct Client*, int, char*[]); extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]); @@ -102,6 +103,7 @@ extern int m_links_redirect(struct Client*, struct Client*, int, char*[]); extern int m_list(struct Client*, struct Client*, int, char*[]); extern int m_lusers(struct Client*, struct Client*, int, char*[]); extern int m_map(struct Client*, struct Client*, int, char*[]); +extern int m_map_redirect(struct Client*, struct Client*, int, char*[]); extern int m_mode(struct Client*, struct Client*, int, char*[]); extern int m_motd(struct Client*, struct Client*, int, char*[]); extern int m_names(struct Client*, struct Client*, int, char*[]); @@ -131,10 +133,12 @@ extern int m_userhost(struct Client*, struct Client*, int, char*[]); extern int m_userip(struct Client*, struct Client*, int, char*[]); extern int m_version(struct Client*, struct Client*, int, char*[]); extern int m_wallchops(struct Client*, struct Client*, int, char*[]); +extern int m_wallvoices(struct Client*, struct Client*, int, char*[]); extern int m_who(struct Client*, struct Client*, int, char*[]); extern int m_whois(struct Client*, struct Client*, int, char*[]); extern int m_whowas(struct Client*, struct Client*, int, char*[]); extern int mo_admin(struct Client*, struct Client*, int, char*[]); +extern int mo_asll(struct Client*, struct Client*, int, char*[]); extern int mo_clearmode(struct Client*, struct Client*, int, char*[]); extern int mo_close(struct Client*, struct Client*, int, char*[]); extern int mo_connect(struct Client*, struct Client*, int, char*[]); @@ -144,7 +148,6 @@ extern int mo_gline(struct Client*, struct Client*, int, char*[]); extern int mo_info(struct Client*, struct Client*, int, char*[]); extern int mo_jupe(struct Client*, struct Client*, int, char*[]); extern int mo_kill(struct Client*, struct Client*, int, char*[]); -extern int mo_map(struct Client*, struct Client*, int, char*[]); extern int mo_notice(struct Client*, struct Client*, int, char*[]); extern int mo_oper(struct Client*, struct Client*, int, char*[]); extern int mo_opmode(struct Client*, struct Client*, int, char*[]); @@ -187,6 +190,7 @@ extern int ms_join(struct Client*, struct Client*, int, char*[]); extern int ms_jupe(struct Client*, struct Client*, int, char*[]); extern int ms_kick(struct Client*, struct Client*, int, char*[]); extern int ms_kill(struct Client*, struct Client*, int, char*[]); +extern int ms_links(struct Client*, struct Client*, int, char*[]); extern int ms_lusers(struct Client*, struct Client*, int, char*[]); extern int ms_mode(struct Client*, struct Client*, int, char*[]); extern int ms_motd(struct Client*, struct Client*, int, char*[]); @@ -214,6 +218,7 @@ extern int ms_version(struct Client*, struct Client*, int, char*[]); extern int ms_wallchops(struct Client*, struct Client*, int, char*[]); extern int ms_wallops(struct Client*, struct Client*, int, char*[]); extern int ms_wallusers(struct Client*, struct Client*, int, char*[]); +extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]); extern int ms_whois(struct Client*, struct Client*, int, char*[]); #endif /* INCLUDED_handlers_h */ diff --git a/include/ircd.h b/include/ircd.h index 73c2890..bca996f 100644 --- a/include/ircd.h +++ b/include/ircd.h @@ -45,6 +45,7 @@ struct Daemon * Proto types */ extern void server_die(const char* message); +extern void server_panic(const char* message); extern void server_restart(const char* message); extern struct Client me; diff --git a/include/ircd_features.h b/include/ircd_features.h index b274512..eea764b 100644 --- a/include/ircd_features.h +++ b/include/ircd_features.h @@ -22,6 +22,7 @@ */ struct Client; +struct StatDesc; enum Feature { /* Misc. features */ @@ -34,6 +35,7 @@ enum Feature { FEAT_SERVER_PORT, FEAT_NODEFAULTMOTD, FEAT_MOTD_BANNER, + FEAT_PROVIDER, FEAT_KILL_IPMISMATCH, FEAT_IDLE_FROM_MSG, FEAT_HUB, @@ -45,6 +47,8 @@ enum Feature { FEAT_HOST_HIDING, FEAT_HIDDEN_HOST, FEAT_HIDDEN_IP, + FEAT_AUTOHIDE, + FEAT_CONNEXIT_NOTICES, /* features that probably should not be touched */ FEAT_KILLCHASETIMELIMIT, @@ -97,6 +101,8 @@ enum Feature { FEAT_OPER_LJUPE, FEAT_OPER_OPMODE, FEAT_OPER_LOPMODE, + FEAT_OPER_FORCE_OPMODE, + FEAT_OPER_FORCE_LOPMODE, FEAT_OPER_BADCHAN, FEAT_OPER_LBADCHAN, FEAT_OPER_SET, @@ -112,12 +118,64 @@ enum Feature { FEAT_LOCOP_LGLINE, FEAT_LOCOP_LJUPE, FEAT_LOCOP_LOPMODE, + FEAT_LOCOP_FORCE_LOPMODE, FEAT_LOCOP_LBADCHAN, FEAT_LOCOP_SET, FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, FEAT_LOCOP_WIDE_GLINE, FEAT_LOCOP_LIST_CHAN, + /* HEAD_IN_SAND Features */ + FEAT_HIS_SNOTICES, + FEAT_HIS_SNOTICES_OPER_ONLY, + FEAT_HIS_DESYNCS, + FEAT_HIS_DEBUG_OPER_ONLY, + FEAT_HIS_WALLOPS, + FEAT_HIS_MAP, + FEAT_HIS_LINKS, + FEAT_HIS_TRACE, + FEAT_HIS_STATS_l, + FEAT_HIS_STATS_c, + FEAT_HIS_STATS_g, + FEAT_HIS_STATS_h, + FEAT_HIS_STATS_k, + FEAT_HIS_STATS_f, + FEAT_HIS_STATS_i, + FEAT_HIS_STATS_j, + FEAT_HIS_STATS_M, + FEAT_HIS_STATS_m, + FEAT_HIS_STATS_o, + FEAT_HIS_STATS_p, + FEAT_HIS_STATS_q, + FEAT_HIS_STATS_r, + FEAT_HIS_STATS_d, + FEAT_HIS_STATS_e, + FEAT_HIS_STATS_t, + FEAT_HIS_STATS_T, + FEAT_HIS_STATS_u, + FEAT_HIS_STATS_U, + FEAT_HIS_STATS_v, + FEAT_HIS_STATS_w, + FEAT_HIS_STATS_x, + FEAT_HIS_STATS_y, + FEAT_HIS_STATS_z, + FEAT_HIS_WHOIS_SERVERNAME, + FEAT_HIS_WHOIS_IDLETIME, + FEAT_HIS_WHO_SERVERNAME, + FEAT_HIS_WHO_HOPCOUNT, + FEAT_HIS_BANWHO, + FEAT_HIS_KILLWHO, + FEAT_HIS_REWRITE, + FEAT_HIS_REMOTE, + FEAT_HIS_NETSPLIT, + FEAT_HIS_SERVERNAME, + FEAT_HIS_SERVERINFO, + FEAT_HIS_URLSERVERS, + + /* Misc. random stuff */ + FEAT_NETWORK, + FEAT_URL_CLIENTS, + FEAT_LAST_F }; @@ -133,7 +191,8 @@ extern int feature_get(struct Client* from, const char* const* fields, extern void feature_unmark(void); extern void feature_mark(void); -extern void feature_report(struct Client* to); +extern void feature_report(struct Client* to, struct StatDesc* sd, int stat, + char* param); extern int feature_int(enum Feature feat); extern int feature_bool(enum Feature feat); diff --git a/include/listener.h b/include/listener.h index 26d5e86..ec03e16 100644 --- a/include/listener.h +++ b/include/listener.h @@ -36,6 +36,7 @@ #endif struct Client; +struct StatDesc; struct Listener { struct Listener* next; /* list node pointer */ @@ -62,8 +63,8 @@ extern void close_listeners(void); extern void count_listener_memory(int* count_out, size_t* size_out); extern const char* get_listener_name(const struct Listener* listener); extern void mark_listeners_closing(void); -extern void show_ports(struct Client* client, int show_hidden, - int port, int count); +extern void show_ports(struct Client* client, struct StatDesc* sd, int stat, + char* param); extern void release_listener(struct Listener* listener); #endif /* INCLUDED_listener_h */ diff --git a/include/motd.h b/include/motd.h index 5ee6e05..130ce16 100644 --- a/include/motd.h +++ b/include/motd.h @@ -34,6 +34,7 @@ struct Client; struct TRecord; +struct StatDesc; struct Motd { struct Motd* next; @@ -85,6 +86,8 @@ void motd_add(const char *hostmask, const char *path); void motd_clear(void); /* This is called to report T-lines */ -void motd_report(struct Client *to); +void motd_report(struct Client *to, struct StatDesc *sd, int stat, + char *param); +void motd_memory_count(struct Client *cptr); #endif /* INCLUDED_motd_h */ diff --git a/include/msg.h b/include/msg.h index 878ebb9..9087926 100644 --- a/include/msg.h +++ b/include/msg.h @@ -198,6 +198,10 @@ struct Client; #define TOK_WALLCHOPS "WC" #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS +#define MSG_WALLVOICES "WALLVOICES" /* WV */ +#define TOK_WALLVOICES "WV" +#define CMD_WALLVOICES MSG_WALLVOICES, TOK_WALLVOICES + #define MSG_CPRIVMSG "CPRIVMSG" /* CPRI */ #define TOK_CPRIVMSG "CP" #define CMD_CPRIVMSG MSG_CPRIVMSG, TOK_CPRIVMSG @@ -330,6 +334,10 @@ struct Client; #define TOK_ACCOUNT "AC" #define CMD_ACCOUNT MSG_ACCOUNT, TOK_ACCOUNT +#define MSG_ASLL "ASLL" /* ASLL */ +#define TOK_ASLL "LL" +#define CMD_ASLL MSG_ASLL, TOK_ASLL + #define MSG_POST "POST" /* POST */ #define TOK_POST "POST" diff --git a/include/msgq.h b/include/msgq.h index ae92211..b7b5535 100644 --- a/include/msgq.h +++ b/include/msgq.h @@ -35,6 +35,7 @@ struct iovec; struct Client; +struct StatDesc; struct MsgCounts { int alloc; @@ -92,8 +93,10 @@ extern void msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format, ...); extern void msgq_clean(struct MsgBuf *mb); extern void msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio); -extern void msgq_count_memory(size_t *msg_alloc, size_t *msg_used, - size_t *msgbuf_alloc, size_t *msgbuf_used); +extern void msgq_count_memory(struct Client *cptr, + size_t *msg_alloc, size_t *msg_used); +extern void msgq_histogram(struct Client *cptr, struct StatDesc *sd, int stat, + char *param); extern unsigned int msgq_bufleft(struct MsgBuf *mb); #endif /* INCLUDED_msgq_h */ diff --git a/include/numeric.h b/include/numeric.h index ebbb45f..ec38079 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -112,7 +112,7 @@ extern const struct Numeric* get_error_numeric(int err); RPL_STATSNLINE 226 unreal RPL_STATSGLINE 227 Dalnet RPL_STATSVLINE 227 unreal */ - +#define RPL_STATSQLINE 228 /* Undernet extension */ #define RPL_SERVICEINFO 231 /* unused */ #define RPL_ENDOFSERVICES 232 /* unused */ /* RPL_RULES 232 unreal */ @@ -250,7 +250,7 @@ extern const struct Numeric* get_error_numeric(int err); /* RPL_LISTSYNTAX 334 unreal */ /* RPL_CHANPASSOK 338 IRCnet extension (?)*/ #define RPL_WHOISACTUALLY 338 /* Undernet extension, dalnet */ -/* RPL_BADCHANPASS 339 mIRC/DALnet extension */ +/* RPL_BADCHANPASS 339 IRCnet extension (?) */ #define RPL_USERIP 340 /* Undernet extension */ #define RPL_INVITING 341 /* RPL_SUMMONING 342 removed from RFC1459 */ @@ -441,11 +441,13 @@ extern const struct Numeric* get_error_numeric(int err); #define ERR_TOOMANYUSERS 519 /* Undernet extension -Kev */ /* ERR_OPERONLY 520 unreal */ #define ERR_MASKTOOWIDE 520 /* Undernet extension -Kev */ -/* ERR_WHOTRUNC 520 austnet +/* ERR_WHOTRUNC 520 austnet */ +/* ERR_LISTSYNTAX 521 dalnet ERR_LISTSYNTAX 521 dalnet ERR_WHOSYNTAX 522 dalnet ERR_WHOLIMEXCEED 523 dalnet */ - +#define ERR_QUARANTINED 524 /* Undernet extension -Vampire */ + #define ERR_NOTLOWEROPLEVEL 550 /* Undernet extension */ #define ERR_NOTMANAGER 551 /* Undernet extension */ #define ERR_CHANSECURED 552 /* Undernet extension */ diff --git a/include/opercmds.h b/include/opercmds.h index 43a4d5b..df6a7e4 100644 --- a/include/opercmds.h +++ b/include/opercmds.h @@ -24,5 +24,6 @@ struct Client; */ extern char *militime(char* sec, char* usec); +extern char *militime_float(char *start); #endif /* INCLUDED_opercmds_h */ diff --git a/include/s_conf.h b/include/s_conf.h index ac61e36..8823ce7 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -66,6 +66,8 @@ struct ConfItem unsigned short port; unsigned char bits; /* Number of bits for ipkills. */ struct Privs privs; /* Priviledges for opers. */ + /* Used to detect if a privilege has been touched. */ + struct Privs privs_dirty; }; struct ServerConf { @@ -81,6 +83,13 @@ struct ServerConf { struct ConnectionClass* conn_class; }; +struct qline +{ + struct qline *next; + char *chname; + char *reason; +}; + struct DenyConf { struct DenyConf* next; char* hostmask; @@ -161,6 +170,7 @@ extern struct tm motd_tm; extern struct MotdItem* motd; extern struct MotdItem* rmotd; extern struct TRecord* tdata; +extern struct qline* GlobalQuarantineList; /* * Proto types @@ -192,8 +202,7 @@ extern void read_tlines(void); extern int find_kill(struct Client *cptr); extern int find_restrict(struct Client *cptr); extern struct MotdItem* read_motd(const char* motdfile); - -extern void set_initial_oper_privs(struct ConfItem *oper, int flags); +extern const char *find_quarantine(const char* chname); extern void lookup_confhost(struct ConfItem *aconf); extern void yyerror(const char *msg); diff --git a/include/s_debug.h b/include/s_debug.h index 9bc2560..30cf015 100644 --- a/include/s_debug.h +++ b/include/s_debug.h @@ -14,6 +14,7 @@ #endif struct Client; +struct StatDesc; #ifdef DEBUGMODE @@ -45,7 +46,8 @@ struct Client; extern void vdebug(int level, const char *form, va_list vl); extern void debug(int level, const char *form, ...); -extern void send_usage(struct Client *cptr, char *nick); +extern void send_usage(struct Client *cptr, struct StatDesc *sd, int stat, + char *param); #else /* !DEBUGMODE */ @@ -56,6 +58,7 @@ extern void send_usage(struct Client *cptr, char *nick); extern const char* debug_serveropts(void); extern void debug_init(int use_tty); -extern void count_memory(struct Client *cptr, char *nick); +extern void count_memory(struct Client *cptr, struct StatDesc *sd, int stat, + char *param); #endif /* INCLUDED_s_debug_h */ diff --git a/include/s_misc.h b/include/s_misc.h index 1dc068b..8c2983b 100644 --- a/include/s_misc.h +++ b/include/s_misc.h @@ -16,6 +16,7 @@ struct Client; +struct StatDesc; struct ConfItem; /*----------------------------------------------------------------------------- @@ -74,7 +75,8 @@ extern const char* get_client_host(const struct Client *cptr); extern void get_sockhost(struct Client *cptr, char *host); extern int vexit_client_msg(struct Client *cptr, struct Client *bcptr, struct Client *sptr, const char *pattern, va_list vl); -extern void tstats(struct Client *cptr, char *name); +extern void tstats(struct Client *cptr, struct StatDesc *sd, int stat, + char *param); extern struct ServerStatistics* ServerStats; diff --git a/include/s_stats.h b/include/s_stats.h index 17cc5ee..967aeac 100644 --- a/include/s_stats.h +++ b/include/s_stats.h @@ -27,13 +27,33 @@ struct Client; -extern const char *statsinfo[]; +struct StatDesc; + +/* Source of /stats, stats descriptor, stats char, extra param (might be 0) */ +typedef void (*StatFunc)(struct Client *, struct StatDesc *, int, char *); + +struct StatDesc +{ + char sd_c; /* stats character */ + unsigned int sd_flags; /* flags to control the stats */ + enum Feature sd_control; /* feature controlling stats */ + StatFunc sd_func; /* function to dispatch to */ + int sd_funcdata; /* extra data for the function */ + char *sd_desc; /* descriptive text */ +}; + +#define STAT_FLAG_OPERONLY 0x01 /* Oper-only stat */ +#define STAT_FLAG_OPERFEAT 0x02 /* Oper-only if the feature is true */ +#define STAT_FLAG_CASESENS 0x04 /* Flag is case-sensitive */ +#define STAT_FLAG_VARPARAM 0x08 /* may have an extra parameter */ + +extern struct StatDesc statsinfo[]; +extern struct StatDesc *statsmap[]; + extern void report_stats(struct Client *sptr, char stat); extern void report_configured_links(struct Client *sptr, int mask); extern int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[], char stat, int MustBeOper); -extern void report_crule_list(struct Client* to, int mask); -extern void report_motd_list(struct Client* to); -extern void report_deny_list(struct Client* to); +extern void stats_init(void); #endif /* INCLUDED_s_stats_h */ diff --git a/include/s_user.h b/include/s_user.h index 5615abb..587b599 100644 --- a/include/s_user.h +++ b/include/s_user.h @@ -14,6 +14,7 @@ struct Client; struct User; struct Channel; struct MsgBuf; +struct Flags; /* * Macros @@ -40,6 +41,11 @@ struct MsgBuf; #define HUNTED_ISME 0 /* if this server should execute the command */ #define HUNTED_PASS 1 /* if message passed onwards successfully */ +/* send sets for send_umode() */ +#define ALL_UMODES 0 /* both local and global user modes */ +#define SEND_UMODES 1 /* global user modes only */ +#define SEND_UMODES_BUT_OPER 2 /* global user modes except for FLAG_OPER */ + /* used when sending to #mask or $mask */ #define MATCH_SERVER 1 @@ -61,11 +67,10 @@ extern int register_user(struct Client* cptr, struct Client* sptr, extern void user_count_memory(size_t* count_out, size_t* bytes_out); -extern int do_nick_name(char* nick); extern int set_nick_name(struct Client* cptr, struct Client* sptr, const char* nick, int parc, char* parv[]); -extern void send_umode_out(struct Client* cptr, struct Client* sptr, int old, - int prop); +extern void send_umode_out(struct Client* cptr, struct Client* sptr, + struct Flags* old, int prop); extern int whisper(struct Client* source, const char* nick, const char* channel, const char* text, int is_notice); extern void send_user_info(struct Client* to, char* names, int rpl, @@ -88,7 +93,8 @@ extern int hunt_server_prio_cmd(struct Client *from, const char *cmd, int server, int parc, char *parv[]); extern struct Client* next_client(struct Client* next, const char* ch); extern char *umode_str(struct Client *cptr); -extern void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask); +extern void send_umode(struct Client *cptr, struct Client *sptr, + struct Flags *old, int sendset); extern int del_silence(struct Client *sptr, char *mask); extern void set_snomask(struct Client *, unsigned int, int); extern int is_snomask(char *); diff --git a/include/send.h b/include/send.h index 5554050..bf7e754 100644 --- a/include/send.h +++ b/include/send.h @@ -24,6 +24,7 @@ struct MsgBuf; */ extern void send_buffer(struct Client* to, struct MsgBuf* buf, int prio); +extern void kill_highest_sendq(int servers_too); extern void flush_connections(struct Client* cptr); extern void send_queued(struct Client *to); @@ -71,6 +72,8 @@ extern void sendcmdto_channel_butone(struct Client *from, const char *cmd, #define SKIP_DEAF 0x01 /* skip users that are +d */ #define SKIP_BURST 0x02 /* skip users that are bursting */ #define SKIP_NONOPS 0x04 /* skip users that aren't chanops */ +#define SKIP_NONVOICES 0x08 /* skip users that aren't voiced (includes + chanops) */ /* Send command to all users having a particular flag set */ extern void sendwallto_group_butone(struct Client *from, int type, diff --git a/include/struct.h b/include/struct.h index 2975fec..b173c30 100644 --- a/include/struct.h +++ b/include/struct.h @@ -52,6 +52,10 @@ struct Server { unsigned short nn_last; /* Last numeric nick for p9 servers only */ unsigned int nn_mask; /* [Remote] FD_SETSIZE - 1 */ char nn_capacity[4]; /* numeric representation of server capacity */ + + int asll_rtt; /* AsLL round-trip time */ + int asll_to; /* AsLL upstream lag */ + int asll_from; /* AsLL downstream lag */ char *last_error_msg; /* Allocated memory with last message receive with an ERROR */ char by[NICKLEN + 1]; diff --git a/include/supported.h b/include/supported.h index 329aff8..23eee85 100644 --- a/include/supported.h +++ b/include/supported.h @@ -34,6 +34,7 @@ #define FEATURES1 \ "WHOX"\ " WALLCHOPS"\ + " WALLVOICES"\ " USERIP"\ " CPRIVMSG"\ " CNOTICE"\ @@ -57,7 +58,8 @@ feature_int(FEAT_MAXBANS), NICKLEN, TOPICLEN, \ AWAYLEN, TOPICLEN -#define FEATURESVALUES2 "+#&", "(ov)@+", "b,k,l,imnpstr", "rfc1459", NETWORK +#define FEATURESVALUES2 "#&", "(ov)@+", "b,k,l,imnpstr", "rfc1459", \ + feature_str(FEAT_NETWORK) #endif /* INCLUDED_supported_h */ diff --git a/include/userload.h b/include/userload.h index c6dfd18..d44c16a 100644 --- a/include/userload.h +++ b/include/userload.h @@ -26,6 +26,7 @@ #define INCLUDED_userload_h struct Client; +struct StatDesc; /* * Structures @@ -42,7 +43,8 @@ struct current_load_st { */ extern void update_load(void); -extern void calc_load(struct Client *sptr); +extern void calc_load(struct Client *sptr, struct StatDesc *sd, int stat, + char *param); extern void initload(void); extern struct current_load_st current_load; diff --git a/include/whocmds.h b/include/whocmds.h index 298dae0..c91d402 100644 --- a/include/whocmds.h +++ b/include/whocmds.h @@ -36,14 +36,20 @@ struct Channel; #define WHO_FIELD_DIS 256 #define WHO_FIELD_REN 512 #define WHO_FIELD_IDL 1024 +#define WHO_FIELD_ACC 2048 #define WHO_FIELD_DEF ( WHO_FIELD_NIC | WHO_FIELD_UID | WHO_FIELD_HOS | WHO_FIELD_SER ) #define IS_VISIBLE_USER(s,ac) ((s==ac) || (!IsInvisible(ac))) -#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || ((b & WHOSELECT_EXTRA) && MyConnect(ac) && HasPriv((s), PRIV_SHOW_INVIS | PRIV_SHOW_ALL_INVIS))) +#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || \ + ((b & WHOSELECT_EXTRA) && MyConnect(ac) && \ + (HasPriv((s), PRIV_SHOW_INVIS) || \ + HasPriv((s), PRIV_SHOW_ALL_INVIS)))) -#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || ((b & WHOSELECT_EXTRA) && HasPriv((s), PRIV_SHOW_ALL_INVIS))) +#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || \ + ((b & WHOSELECT_EXTRA) && \ + HasPriv((s), PRIV_SHOW_ALL_INVIS))) #define SHOW_MORE(sptr, counter) (HasPriv(sptr, PRIV_UNLIMIT_QUERY) || (!(counter-- < 0)) ) diff --git a/ircd/IPcheck.c b/ircd/IPcheck.c index 47c102f..04ffb3a 100644 --- a/ircd/IPcheck.c +++ b/ircd/IPcheck.c @@ -384,7 +384,7 @@ void ip_registry_disconnect(struct Client *cptr) if (0 == entry) { /* * trying to find an entry for a server causes this to happen, - * servers should never have FLAGS_IPCHECK set + * servers should never have FLAG_IPCHECK set */ return; } diff --git a/ircd/Makefile.in b/ircd/Makefile.in index 0b55039..2aeed4a 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -111,6 +111,7 @@ IRCD_SRC = \ listener.c \ m_account.c \ m_admin.c \ + m_asll.c \ m_away.c \ m_burst.c \ m_clearmode.c \ @@ -175,6 +176,7 @@ IRCD_SRC = \ m_wallchops.c \ m_wallops.c \ m_wallusers.c \ + m_wallvoices.c \ m_who.c \ m_whois.c \ m_whowas.c \ diff --git a/ircd/channel.c b/ircd/channel.c index 56fa07f..62f21cf 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -31,7 +31,6 @@ #include "ircd_defs.h" #include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -383,11 +382,9 @@ int add_banid(struct Client *cptr, struct Channel *chptr, char *banid, assert(0 != ban->value.ban.banstr); strcpy(ban->value.ban.banstr, banid); -#ifdef HEAD_IN_SAND_BANWHO - if (IsServer(cptr)) + if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO)) DupString(ban->value.ban.who, cli_name(&me)); else -#endif DupString(ban->value.ban.who, cli_name(cptr)); assert(0 != ban->value.ban.who); @@ -442,6 +439,7 @@ static int is_banned(struct Client *cptr, struct Channel *chptr, struct Membership* member) { struct SLink* tmp; + char tmphost[HOSTLEN + 1]; char nu_host[NUH_BUFSIZE]; char nu_realhost[NUH_BUFSIZE]; char nu_ip[NUI_BUFSIZE]; @@ -457,10 +455,23 @@ static int is_banned(struct Client *cptr, struct Channel *chptr, s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username, (cli_user(cptr))->host); - if (HasHiddenHost(cptr)) - sr = make_nick_user_host(nu_realhost, cli_name(cptr), - (cli_user(cptr))->username, - cli_user(cptr)->realhost); + if (IsAccount(cptr)) + { + if (HasHiddenHost(cptr)) + { + sr = make_nick_user_host(nu_realhost, cli_name(cptr), + (cli_user(cptr))->username, + cli_user(cptr)->realhost); + } + else + { + ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s", + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST)); + sr = make_nick_user_host(nu_realhost, cli_name(cptr), + cli_user(cptr)->username, + tmphost); + } + } for (tmp = chptr->banlist; tmp; tmp = tmp->next) { if ((tmp->flags & CHFL_BAN_IPMASK)) { @@ -682,12 +693,11 @@ int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr) member = find_channel_member(cptr, chptr); /* - * You can't speak if your off channel, if the channel is modeless, or - * +n (no external messages) or +m (moderated). + * You can't speak if you're off channel, and it is +n (no external messages) + * or +m (moderated). */ if (!member) { if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) || - IsModelessChannel(chptr->chname) || ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr))) return 0; else @@ -1156,7 +1166,8 @@ int can_join(struct Client *sptr, struct Channel *chptr, char *key) a HACK(4) notice will be sent if he would not have been supposed to join normally. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && - !BadPtr(key) && compall("OVERRIDE",key) == 0) + !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 && + compall("OVERRIDE",key) == 0) overrideJoin = MAGIC_OPER_OVERRIDE; if (chptr->mode.mode & MODE_INVITEONLY) @@ -1523,8 +1534,9 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0) return 0; - /* Ok, if we were given the OPMODE flag, hide the source if its a user */ - if (mbuf->mb_dest & MODEBUF_DEST_OPMODE && !IsServer(mbuf->mb_source)) + /* Ok, if we were given the OPMODE flag, or its a server, hide the source. + */ + if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source)) app_source = &me; else app_source = mbuf->mb_source; @@ -1666,11 +1678,8 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) if (mbuf->mb_dest & MODEBUF_DEST_HACK2) sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s " "[%Tu]", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(mbuf->mb_source), -#else - cli_name(app_source), -#endif + cli_name(feature_bool(FEAT_HIS_SNOTICES) ? + mbuf->mb_source : app_source), mbuf->mb_channel->chname, rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr, @@ -1679,11 +1688,8 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) if (mbuf->mb_dest & MODEBUF_DEST_HACK3) sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s " "%s%s%s%s%s%s [%Tu]", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(mbuf->mb_source), -#else - cli_name(app_source), -#endif + cli_name(feature_bool(FEAT_HIS_SNOTICES) ? + mbuf->mb_source : app_source), mbuf->mb_channel->chname, rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr, mbuf->mb_channel->creationtime); @@ -2190,7 +2196,7 @@ mode_parse_key(struct ParseState *state, int *flag_p) return; state->done |= DONE_KEY; - t_len = KEYLEN + 1; + t_len = KEYLEN; /* clean up the key string */ s = t_str; @@ -2570,8 +2576,9 @@ mode_parse_ban(struct ParseState *state, int *flag_p) } else if (!mmatch(t_str, ban->value.ban.banstr)) ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */ - if (!ban->next && (newban->flags & MODE_ADD)) { - ban->next = newban; /* add our"ban with its flags */ + if (!ban->next && (newban->flags & MODE_ADD)) + { + ban->next = newban; /* add our ban with its flags */ break; /* get out of loop */ } } @@ -2646,7 +2653,7 @@ mode_process_bans(struct ParseState *state) } else { if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) && (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) || - count >= feature_int(FEAT_MAXBANS))) { + count > feature_int(FEAT_MAXBANS))) { send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname, ban->value.ban.banstr); count--; @@ -2778,7 +2785,8 @@ mode_process_clients(struct ParseState *state) if (MyUser(state->sptr)) { /* don't allow local opers to be deopped on local channels */ - if (state->cli_change[i].client != state->sptr && + if (MyUser(state->sptr) && + state->cli_change[i].client != state->sptr && IsLocalChannel(state->chptr->chname) && HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) { send_reply(state->sptr, ERR_ISOPERLCHAN, @@ -3106,6 +3114,7 @@ void joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags) { unsigned int len; + int is_local; assert(0 != jbuf); @@ -3116,6 +3125,8 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags) return; } + is_local = IsLocalChannel(chan->chname); + if (jbuf->jb_type == JOINBUF_TYPE_PART || jbuf->jb_type == JOINBUF_TYPE_PARTALL) { /* Send notification to channel */ @@ -3135,14 +3146,14 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags) * the original m_part.c */ if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || - IsLocalChannel(chan->chname)) /* got to remove user here */ + is_local) /* got to remove user here */ remove_user_from_channel(jbuf->jb_source, chan); } else { /* Add user to channel */ add_user_to_channel(chan, jbuf->jb_source, flags, 0); /* send notification to all servers */ - if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname)) + if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local) sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "%H %Tu", chan, chan->creationtime); @@ -3150,14 +3161,13 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags) sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan); /* send an op, too, if needed */ - if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE && - !IsModelessChannel(chan->chname)) + if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE) sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C", chan, jbuf->jb_source); } if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || - jbuf->jb_type == JOINBUF_TYPE_JOIN || IsLocalChannel(chan->chname)) + jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local) return; /* don't send to remote */ /* figure out if channel name will cause buffer to be overflowed */ @@ -3220,3 +3230,14 @@ joinbuf_flush(struct JoinBuf *jbuf) return 0; } + +/* Returns TRUE (1) if client is invited, FALSE (0) if not */ +int IsInvited(struct Client* cptr, struct Channel* chptr) +{ + struct SLink *lp; + + for (lp = (cli_user(cptr))->invited; lp; lp = lp->next) + if (lp->value.chptr == chptr) + return 1; + return 0; +} diff --git a/ircd/class.c b/ircd/class.c index ba5d719..c922dbb 100644 --- a/ircd/class.c +++ b/ircd/class.c @@ -231,7 +231,8 @@ struct ConnectionClass* find_class(const char *name) } void -report_classes(struct Client *sptr) +report_classes(struct Client *sptr, struct StatDesc *sd, int stat, + char *param) { struct ConnectionClass *cltmp; diff --git a/ircd/client.c b/ircd/client.c index fc4dd9c..f960a1d 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -103,74 +103,72 @@ void client_add_sendq(struct Connection* con, struct Connection** con_p) static struct { - unsigned int priv; + enum Priv priv; + enum + { + FEATFLAG_DISABLES_PRIV, + FEATFLAG_ENABLES_PRIV, + FEATFLAG_GLOBAL_OPERS, + FEATFLAG_LOCAL_OPERS, + FEATFLAG_ALL_OPERS + } flag; enum Feature feat; - unsigned int flag; } feattab[] = { - { PRIV_WHOX, FEAT_LAST_F, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_DISPLAY, FEAT_LAST_F, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_CHAN_LIMIT, FEAT_OPER_NO_CHAN_LIMIT, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_MODE_LCHAN, FEAT_OPER_MODE_LCHAN, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_LOCAL_OPMODE, FEAT_OPER_MODE_LCHAN, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_WALK_LCHAN, FEAT_OPER_WALK_THROUGH_LMODES, - (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_DEOP_LCHAN, FEAT_NO_OPER_DEOP_LCHAN, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_SHOW_INVIS, FEAT_SHOW_INVISIBLE_USERS, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_SHOW_ALL_INVIS, FEAT_SHOW_ALL_INVISIBLE_USERS, - (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_UNLIMIT_QUERY, FEAT_UNLIMIT_OPER_QUERY, - (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_LIST_CHAN, FEAT_LIST_CHAN, (FLAGS_OPER | FLAGS_LOCOP) }, - { PRIV_KILL, FEAT_LOCAL_KILL_ONLY, 0 }, - { PRIV_GLINE, FEAT_CONFIG_OPERCMDS, ~0 }, - { PRIV_JUPE, FEAT_CONFIG_OPERCMDS, ~0 }, - { PRIV_OPMODE, FEAT_CONFIG_OPERCMDS, ~0 }, - { PRIV_BADCHAN, FEAT_CONFIG_OPERCMDS, ~0 }, - { PRIV_PROPAGATE, FEAT_LAST_F, FLAGS_OPER }, - { PRIV_SEE_OPERS, FEAT_LAST_F, FLAGS_OPER }, - { PRIV_KILL, FEAT_OPER_KILL, FLAGS_OPER }, - { PRIV_LOCAL_KILL, FEAT_OPER_KILL, FLAGS_OPER }, - { PRIV_REHASH, FEAT_OPER_REHASH, FLAGS_OPER }, - { PRIV_RESTART, FEAT_OPER_RESTART, FLAGS_OPER }, - { PRIV_DIE, FEAT_OPER_DIE, FLAGS_OPER }, - { PRIV_GLINE, FEAT_OPER_GLINE, FLAGS_OPER }, - { PRIV_LOCAL_GLINE, FEAT_OPER_LGLINE, FLAGS_OPER }, - { PRIV_JUPE, FEAT_OPER_JUPE, FLAGS_OPER }, - { PRIV_LOCAL_JUPE, FEAT_OPER_LJUPE, FLAGS_OPER }, - { PRIV_OPMODE, FEAT_OPER_OPMODE, FLAGS_OPER }, - { PRIV_LOCAL_OPMODE, FEAT_OPER_LOPMODE, FLAGS_OPER }, - { PRIV_BADCHAN, FEAT_OPER_BADCHAN, FLAGS_OPER }, - { PRIV_LOCAL_BADCHAN, FEAT_OPER_LBADCHAN, FLAGS_OPER }, - { PRIV_SET, FEAT_OPER_SET, FLAGS_OPER }, - { PRIV_SEE_CHAN, FEAT_OPERS_SEE_IN_SECRET_CHANNELS, FLAGS_OPER }, - { PRIV_WIDE_GLINE, FEAT_OPER_WIDE_GLINE, FLAGS_OPER }, - { PRIV_LIST_CHAN, FEAT_OPER_LIST_CHAN, FLAGS_OPER }, - { PRIV_LOCAL_KILL, FEAT_LOCOP_KILL, FLAGS_LOCOP }, - { PRIV_REHASH, FEAT_LOCOP_REHASH, FLAGS_LOCOP }, - { PRIV_RESTART, FEAT_LOCOP_RESTART, FLAGS_LOCOP }, - { PRIV_DIE, FEAT_LOCOP_DIE, FLAGS_LOCOP }, - { PRIV_LOCAL_GLINE, FEAT_LOCOP_LGLINE, FLAGS_LOCOP }, - { PRIV_LOCAL_JUPE, FEAT_LOCOP_LJUPE, FLAGS_LOCOP }, - { PRIV_LOCAL_OPMODE, FEAT_LOCOP_LOPMODE, FLAGS_LOCOP }, - { PRIV_LOCAL_BADCHAN, FEAT_LOCOP_LBADCHAN, FLAGS_LOCOP }, - { PRIV_SET, FEAT_LOCOP_SET, FLAGS_LOCOP }, - { PRIV_SEE_CHAN, FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, FLAGS_LOCOP }, - { PRIV_WIDE_GLINE, FEAT_LOCOP_WIDE_GLINE, FLAGS_LOCOP }, - { PRIV_LIST_CHAN, FEAT_LOCOP_LIST_CHAN, FLAGS_LOCOP }, - { 0, FEAT_LAST_F, 0 } + { PRIV_WHOX, FEAT_LAST_F, FEATFLAG_ALL_OPERS }, + { PRIV_DISPLAY, FEAT_LAST_F, FEATFLAG_ALL_OPERS }, + { PRIV_CHAN_LIMIT, FEAT_OPER_NO_CHAN_LIMIT, FEATFLAG_ALL_OPERS }, + { PRIV_MODE_LCHAN, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS }, + { PRIV_LOCAL_OPMODE, FEAT_OPER_MODE_LCHAN, FEATFLAG_ALL_OPERS }, + { PRIV_WALK_LCHAN, FEAT_OPER_WALK_THROUGH_LMODES, FEATFLAG_ALL_OPERS }, + { PRIV_DEOP_LCHAN, FEAT_NO_OPER_DEOP_LCHAN, FEATFLAG_ALL_OPERS }, + { PRIV_SHOW_INVIS, FEAT_SHOW_INVISIBLE_USERS, FEATFLAG_ALL_OPERS }, + { PRIV_SHOW_ALL_INVIS, FEAT_SHOW_ALL_INVISIBLE_USERS, FEATFLAG_ALL_OPERS }, + { PRIV_UNLIMIT_QUERY, FEAT_UNLIMIT_OPER_QUERY, FEATFLAG_ALL_OPERS }, + + { PRIV_KILL, FEAT_LOCAL_KILL_ONLY, FEATFLAG_DISABLES_PRIV }, + { PRIV_GLINE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, + { PRIV_JUPE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, + { PRIV_OPMODE, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, + { PRIV_BADCHAN, FEAT_CONFIG_OPERCMDS, FEATFLAG_ENABLES_PRIV }, + + { PRIV_PROPAGATE, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS }, + { PRIV_SEE_OPERS, FEAT_LAST_F, FEATFLAG_GLOBAL_OPERS }, + { PRIV_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS }, + { PRIV_LOCAL_KILL, FEAT_OPER_KILL, FEATFLAG_GLOBAL_OPERS }, + { PRIV_REHASH, FEAT_OPER_REHASH, FEATFLAG_GLOBAL_OPERS }, + { PRIV_RESTART, FEAT_OPER_RESTART, FEATFLAG_GLOBAL_OPERS }, + { PRIV_DIE, FEAT_OPER_DIE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_GLINE, FEAT_OPER_GLINE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_LOCAL_GLINE, FEAT_OPER_LGLINE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_JUPE, FEAT_OPER_JUPE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_LOCAL_JUPE, FEAT_OPER_LJUPE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_OPMODE, FEAT_OPER_OPMODE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_LOCAL_OPMODE, FEAT_OPER_LOPMODE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_FORCE_OPMODE, FEAT_OPER_FORCE_OPMODE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_FORCE_LOCAL_OPMODE, FEAT_OPER_FORCE_LOPMODE, FEATFLAG_GLOBAL_OPERS }, + { PRIV_BADCHAN, FEAT_OPER_BADCHAN, FEATFLAG_GLOBAL_OPERS }, + { PRIV_LOCAL_BADCHAN, FEAT_OPER_LBADCHAN, FEATFLAG_GLOBAL_OPERS }, + { PRIV_SET, FEAT_OPER_SET, FEATFLAG_GLOBAL_OPERS }, + { PRIV_SEE_CHAN, FEAT_OPERS_SEE_IN_SECRET_CHANNELS, FEATFLAG_GLOBAL_OPERS }, + { PRIV_WIDE_GLINE, FEAT_OPER_WIDE_GLINE, FEATFLAG_GLOBAL_OPERS }, + + { PRIV_LOCAL_KILL, FEAT_LOCOP_KILL, FEATFLAG_LOCAL_OPERS }, + { PRIV_REHASH, FEAT_LOCOP_REHASH, FEATFLAG_LOCAL_OPERS }, + { PRIV_RESTART, FEAT_LOCOP_RESTART, FEATFLAG_LOCAL_OPERS }, + { PRIV_DIE, FEAT_LOCOP_DIE, FEATFLAG_LOCAL_OPERS }, + { PRIV_LOCAL_GLINE, FEAT_LOCOP_LGLINE, FEATFLAG_LOCAL_OPERS }, + { PRIV_LOCAL_JUPE, FEAT_LOCOP_LJUPE, FEATFLAG_LOCAL_OPERS }, + { PRIV_LOCAL_OPMODE, FEAT_LOCOP_LOPMODE, FEATFLAG_LOCAL_OPERS }, + { PRIV_FORCE_LOCAL_OPMODE, FEAT_LOCOP_FORCE_LOPMODE, FEATFLAG_LOCAL_OPERS }, + { PRIV_LOCAL_BADCHAN, FEAT_LOCOP_LBADCHAN, FEATFLAG_LOCAL_OPERS }, + { PRIV_SET, FEAT_LOCOP_SET, FEATFLAG_LOCAL_OPERS }, + { PRIV_SEE_CHAN, FEAT_LOCOP_SEE_IN_SECRET_CHANNELS, FEATFLAG_LOCAL_OPERS }, + { PRIV_WIDE_GLINE, FEAT_LOCOP_WIDE_GLINE, FEATFLAG_LOCAL_OPERS }, + + { PRIV_LAST_PRIV, FEAT_LAST_F, 0 } }; -void -set_initial_oper_privs(struct ConfItem *oper, int flags) -{ - int i; - memset(&oper->privs, 0, sizeof(oper->privs)); - for (i = 0; feattab[i].priv; i++) - if ((feattab[i].flag | flags) != 0 && feattab[i].flag != ~0) - PrivSet(&oper->privs, feattab[i].priv); -} - /* client_set_privs(struct Client* client) * * Sets the privileges for opers. @@ -196,12 +194,39 @@ client_set_privs(struct Client *client, struct ConfItem *oper) /* Copy across privs from the config. */ cli_privs(client) = oper->privs; - /* Remove privileges disallowed by features... */ - for (i = 0; feattab[i].priv; i++) - if (feattab[i].flag == 0 && feature_bool(feattab[i].feat)) - PrivClr(&cli_privs(client), feattab[i].priv); - else if (feattab[i].flag == ~0 && !feature_bool(feattab[i].feat)) + /* Now go through the features and set the non-dirty flags to their feature + * determined defaults... + */ + for (i = 0; feattab[i].priv != PRIV_LAST_PRIV; i++) + { + if (PrivHas(&oper->privs_dirty, feattab[i].priv)) + continue; + if (feattab[i].feat != FEAT_LAST_F && !feature_bool(feattab[i].priv)) + continue; + switch (feattab[i].flag) + { + case FEATFLAG_ENABLES_PRIV: + if (!feature_bool(feattab[i].feat)) + continue; + PrivSet(&cli_privs(client), feattab[i].priv); + continue; + case FEATFLAG_DISABLES_PRIV: PrivClr(&cli_privs(client), feattab[i].priv); + continue; + case FEATFLAG_ALL_OPERS: + if (IsAnOper(client)) + PrivSet(&cli_privs(client), feattab[i].priv); + continue; + case FEATFLAG_GLOBAL_OPERS: + if (IsOper(client)) + PrivSet(&cli_privs(client), feattab[i].priv); + continue; + case FEATFLAG_LOCAL_OPERS: + if (IsLocOp(client)) + PrivSet(&cli_privs(client), feattab[i].priv); + continue; + } + } /* This should be handled in the config, but lets be sure... */ if (PrivHas(&cli_privs(client), PRIV_PROPAGATE)) @@ -229,7 +254,8 @@ static struct { 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(DISPLAY), P(SEE_OPERS), P(FORCE_OPMODE), P(FORCE_LOCAL_OPMODE), + P(WIDE_GLINE), #undef P { 0, 0 } }; diff --git a/ircd/gline.c b/ircd/gline.c index 8ac50df..ebbe642 100644 --- a/ircd/gline.c +++ b/ircd/gline.c @@ -27,7 +27,6 @@ #include "ircd_alloc.h" #include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -36,6 +35,7 @@ #include "s_bsd.h" #include "s_debug.h" #include "s_misc.h" +#include "s_stats.h" #include "send.h" #include "struct.h" #include "support.h" @@ -317,9 +317,9 @@ gline_add(struct Client *cptr, struct Client *sptr, char *userhost, assert(0 != reason); /* NO_OLD_GLINE allows *@#channel to work correctly */ - if (*userhost == '#' || *userhost == '&' || *userhost == '+' + if (*userhost == '#' || *userhost == '&' # ifndef NO_OLD_GLINE - || userhost[2] == '#' || userhost[2] == '&' || userhost[2] == '+' + || userhost[2] == '#' || userhost[2] == '&' # endif /* OLD_GLINE */ ) { if ((flags & GLINE_LOCAL) && !HasPriv(sptr, PRIV_LOCAL_BADCHAN)) @@ -327,7 +327,7 @@ gline_add(struct Client *cptr, struct Client *sptr, char *userhost, flags |= GLINE_BADCHAN; # ifndef NO_OLD_GLINE - if (userhost[2] == '#' || userhost[2] == '&' || userhost[2] == '+') + if (userhost[2] == '#' || userhost[2] == '&') user = userhost + 2; else # endif /* OLD_GLINE */ @@ -368,18 +368,16 @@ gline_add(struct Client *cptr, struct Client *sptr, char *userhost, expire += CurrentTime; /* convert from lifetime to timestamp */ /* Inform ops... */ - sendto_opmask_butone(0, SNO_GLINE, "%s adding %s %s for %s%s%s, expiring at " - "%Tu: %s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name((cli_user(sptr))->server), -#endif - flags & GLINE_LOCAL ? "local" : "global", - flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", user, - flags & GLINE_BADCHAN ? "" : "@", - flags & GLINE_BADCHAN ? "" : host, + sendto_opmask_butone(0, ircd_strncmp(reason, "AUTO", 4) ? SNO_GLINE : + SNO_AUTO, "%s adding %s %s for %s%s%s, expiring at " + "%Tu: %s", + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), + (flags & GLINE_LOCAL) ? "local" : "global", + (flags & GLINE_BADCHAN) ? "BADCHAN" : "GLINE", user, + (flags & GLINE_BADCHAN) ? "" : "@", + (flags & GLINE_BADCHAN) ? "" : host, expire + TSoffset, reason); /* and log it */ @@ -431,18 +429,15 @@ gline_activate(struct Client *cptr, struct Client *sptr, struct Gline *gline, /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s activating global %s for %s%s%s, " - "expiring at %Tu: %s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name((cli_user(sptr))->server), -#endif - GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", - gline->gl_user, GlineIsBadChan(gline) ? "" : "@", - GlineIsBadChan(gline) ? "" : gline->gl_host, - gline->gl_expire + TSoffset, gline->gl_reason); - + "expiring at %Tu: %s", + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), + GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", + gline->gl_user, GlineIsBadChan(gline) ? "" : "@", + GlineIsBadChan(gline) ? "" : gline->gl_host, + gline->gl_expire + TSoffset, gline->gl_reason); + log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, "%#C activating global %s for %s%s%s, expiring at %Tu: %s", sptr, GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user, @@ -495,12 +490,9 @@ gline_deactivate(struct Client *cptr, struct Client *sptr, struct Gline *gline, /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s %s %s for %s%s%s, expiring at %Tu: " "%s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name((cli_user(sptr))->server), -#endif + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), msg, GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user, GlineIsBadChan(gline) ? "" : "@", GlineIsBadChan(gline) ? "" : gline->gl_host, @@ -546,9 +538,9 @@ gline_find(char *userhost, unsigned int flags) } if ((flags & (GLINE_BADCHAN | GLINE_ANY)) == GLINE_BADCHAN || - *userhost == '#' || *userhost == '&' || *userhost == '+' + *userhost == '#' || *userhost == '&' #ifndef NO_OLD_GLINE - || userhost[2] == '#' || userhost[2] == '&' || userhost[2] == '+' + || userhost[2] == '#' || userhost[2] == '&' #endif /* NO_OLD_GLINE */ ) return 0; @@ -734,7 +726,8 @@ gline_list(struct Client *sptr, char *userhost) } void -gline_stats(struct Client *sptr) +gline_stats(struct Client *sptr, struct StatDesc *sd, int stat, + char *param) { struct Gline *gline; struct Gline *sgline; @@ -749,3 +742,21 @@ gline_stats(struct Client *sptr) gline->gl_expire + TSoffset, gline->gl_reason); } } + +int +gline_memory_count(size_t *gl_size) +{ + struct Gline *gline; + unsigned int gl = 0; + + for (gline = GlobalGlineList; gline; gline = gline->gl_next) + { + gl++; + gl_size += sizeof(struct Gline); + gl_size += gline->gl_user ? (strlen(gline->gl_user) + 1) : 0; + gl_size += gline->gl_host ? (strlen(gline->gl_host) + 1) : 0; + gl_size += gline->gl_reason ? (strlen(gline->gl_reason) + 1) : 0; + } + return gl; +} + diff --git a/ircd/ircd.c b/ircd/ircd.c index 87c171f..27d56ba 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -42,6 +42,7 @@ #include "msg.h" #include "numeric.h" #include "numnicks.h" +#include "opercmds.h" #include "parse.h" #include "res.h" #include "s_auth.h" @@ -115,7 +116,8 @@ int running = 1; /*---------------------------------------------------------------------------- * API: server_die *--------------------------------------------------------------------------*/ -void server_die(const char* message) { +void server_die(const char *message) +{ /* log_write will send out message to both log file and as server notice */ log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message); flush_connections(0); @@ -123,11 +125,24 @@ void server_die(const char* message) { running = 0; } +/*---------------------------------------------------------------------------- + * API: server_panic + *--------------------------------------------------------------------------*/ +void server_panic(const char *message) +{ + /* inhibit sending server notice--we may be panicing due to low memory */ + log_write(LS_SYSTEM, L_CRIT, LOG_NOSNOTICE, "Server panic: %s", message); + flush_connections(0); + log_close(); + close_connections(1); + exit(1); +} /*---------------------------------------------------------------------------- * API: server_restart *--------------------------------------------------------------------------*/ -void server_restart(const char* message) { +void server_restart(const char *message) +{ static int restarting = 0; /* inhibit sending any server notices; we may be in a loop */ @@ -345,7 +360,7 @@ static void check_pings(struct Event* ev) { Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d", cli_name(cptr), - (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", + IsPingSent(cptr) ? "[Ping Sent]" : "[]", max_ping, (int)(CurrentTime - cli_lasttime(cptr)))); @@ -359,50 +374,58 @@ static void check_pings(struct Event* ev) { continue; } + /* Quit the client after max_ping*2 - they should have answered by now */ + if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) ) + { + /* If it was a server, then tell ops about it. */ + if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) + sendto_opmask_butone(0, SNO_OLDSNO, + "No response from %s, closing link", + cli_name(cptr)); + exit_client_msg(cptr, cptr, &me, "Ping timeout"); + continue; + } + /* Unregistered clients pingout after max_ping seconds, they don't * get given a second chance - if they were then people could not quite * finish registration and hold resources without being subject to k/g * lines */ - if (!IsRegistered(cptr)) { + if (!IsRegistered(cptr)) + { /* Display message if they have sent a NICK and a USER but no * nospoof PONG. */ - if (*(cli_name(cptr)) && cli_user(cptr) && *(cli_user(cptr))->username) { + if (*(cli_name(cptr)) && cli_user(cptr) && *(cli_user(cptr))->username) + { send_reply(cptr, SND_EXPLICIT | ERR_BADPING, ":Your client may not be compatible with this server."); send_reply(cptr, SND_EXPLICIT | ERR_BADPING, - ":Compatible clients are available at " - URL_CLIENTS); + ":Compatible clients are available at %s", + feature_str(FEAT_URL_CLIENTS)); } exit_client_msg(cptr,cptr,&me, "Ping Timeout"); continue; } - if (!(cli_flags(cptr) & FLAGS_PINGSENT)) { + if (!IsPingSent(cptr)) + { /* If we havent PINGed the connection and we havent heard from it in a * while, PING it to make sure it is still alive. */ - cli_flags(cptr) |= FLAGS_PINGSENT; + SetPingSent(cptr); /* If we're late in noticing don't hold it against them :) */ cli_lasttime(cptr) = CurrentTime - max_ping; if (IsUser(cptr)) - sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me)); + sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me)); else - sendcmdto_one(&me, CMD_PING, cptr, ":%s", cli_name(&me)); - } - - /* Quit the client after max_ping*2 - they should have answered by now */ - if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) ) { - /* If it was a server, then tell ops about it. */ - if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) - sendto_opmask_butone(0, SNO_OLDSNO, - "No response from %s, closing link", - cli_name(cptr)); - exit_client_msg(cptr, cptr, &me, "Ping timeout"); - continue; + { + char *asll_ts = militime_float(NULL); + sendcmdto_one(&me, CMD_PING, cptr, "!%s %s %s", asll_ts, + cli_name(cptr), asll_ts); + } } expire = cli_lasttime(cptr) + max_ping * 2; diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c index 2c4b966..f0ad610 100644 --- a/ircd/ircd_features.c +++ b/ircd/ircd_features.c @@ -241,6 +241,7 @@ static struct FeatureDesc { F_I(SERVER_PORT, FEAT_OPER, 4400, 0), F_B(NODEFAULTMOTD, 0, 1, 0), F_S(MOTD_BANNER, FEAT_NULL, 0, 0), + F_S(PROVIDER, FEAT_NULL, 0, 0), F_B(KILL_IPMISMATCH, FEAT_OPER, 0, 0), F_B(IDLE_FROM_MSG, 0, 1, 0), F_B(HUB, 0, 0, 0), @@ -249,15 +250,17 @@ static struct FeatureDesc { F_N(RANDOM_SEED, FEAT_NODISP, random_seed_set, 0, 0, 0, 0, 0, 0), F_S(DEFAULT_LIST_PARAM, FEAT_NULL, 0, list_set_default), F_I(NICKNAMEHISTORYLENGTH, 0, 800, whowas_realloc), - F_B(HOST_HIDING, 0, 0, 0), + F_B(HOST_HIDING, 0, 1, 0), F_S(HIDDEN_HOST, FEAT_CASE, "users.undernet.org", 0), F_S(HIDDEN_IP, 0, "127.0.0.1", 0), + F_B(AUTOHIDE, 0, 1, 0), + F_B(CONNEXIT_NOTICES, 0, 0, 0), /* features that probably should not be touched */ F_I(KILLCHASETIMELIMIT, 0, 30, 0), F_I(MAXCHANNELSPERUSER, 0, 10, 0), F_I(AVBANLEN, 0, 40, 0), - F_I(MAXBANS, 0, 30, 0), + F_I(MAXBANS, 0, 45, 0), F_I(MAXSILES, 0, 15, 0), F_I(HANGONGOODLINK, 0, 300, 0), F_I(HANGONRETRYDELAY, 0, 10, 0), @@ -304,6 +307,8 @@ static struct FeatureDesc { F_B(OPER_LJUPE, 0, 1, 0), F_B(OPER_OPMODE, 0, 1, 0), F_B(OPER_LOPMODE, 0, 1, 0), + F_B(OPER_FORCE_OPMODE, 0, 1, 0), + F_B(OPER_FORCE_LOPMODE, 0, 1, 0), F_B(OPER_BADCHAN, 0, 0, 0), F_B(OPER_LBADCHAN, 0, 0, 0), F_B(OPER_SET, 0, 0, 0), @@ -319,12 +324,63 @@ static struct FeatureDesc { F_B(LOCOP_LGLINE, 0, 1, 0), F_B(LOCOP_LJUPE, 0, 1, 0), F_B(LOCOP_LOPMODE, 0, 1, 0), + F_B(LOCOP_FORCE_LOPMODE, 0, 1, 0), F_B(LOCOP_LBADCHAN, 0, 0, 0), F_B(LOCOP_SET, 0, 0, 0), F_B(LOCOP_SEE_IN_SECRET_CHANNELS, 0, 0, 0), F_B(LOCOP_WIDE_GLINE, 0, 0, 0), F_B(LOCOP_LIST_CHAN, 0, 0, 0), + /* HEAD_IN_SAND Features */ + F_B(HIS_SNOTICES, 0, 1, 0), + F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0), + F_B(HIS_DESYNCS, 0, 1, 0), + F_B(HIS_DEBUG_OPER_ONLY, 0, 1, 0), + F_B(HIS_WALLOPS, 0, 1, 0), + F_B(HIS_MAP, 0, 1, 0), + F_B(HIS_LINKS, 0, 1, 0), + F_B(HIS_TRACE, 0, 1, 0), + F_B(HIS_STATS_l, 0, 1, 0), + F_B(HIS_STATS_c, 0, 1, 0), + F_B(HIS_STATS_g, 0, 1, 0), + F_B(HIS_STATS_h, 0, 1, 0), + F_B(HIS_STATS_k, 0, 1, 0), + F_B(HIS_STATS_f, 0, 1, 0), + F_B(HIS_STATS_i, 0, 1, 0), + F_B(HIS_STATS_j, 0, 1, 0), + F_B(HIS_STATS_M, 0, 1, 0), + F_B(HIS_STATS_m, 0, 1, 0), + F_B(HIS_STATS_o, 0, 1, 0), + F_B(HIS_STATS_p, 0, 1, 0), + F_B(HIS_STATS_q, 0, 1, 0), + F_B(HIS_STATS_r, 0, 1, 0), + F_B(HIS_STATS_d, 0, 1, 0), + F_B(HIS_STATS_e, 0, 1, 0), + F_B(HIS_STATS_t, 0, 1, 0), + F_B(HIS_STATS_T, 0, 1, 0), + F_B(HIS_STATS_u, 0, 0, 0), + F_B(HIS_STATS_U, 0, 1, 0), + F_B(HIS_STATS_v, 0, 1, 0), + F_B(HIS_STATS_w, 0, 0, 0), + F_B(HIS_STATS_x, 0, 1, 0), + F_B(HIS_STATS_y, 0, 1, 0), + F_B(HIS_STATS_z, 0, 1, 0), + F_B(HIS_WHOIS_SERVERNAME, 0, 1, 0), + F_B(HIS_WHOIS_IDLETIME, 0, 1, 0), + F_B(HIS_WHO_SERVERNAME, 0, 1, 0), + F_B(HIS_WHO_HOPCOUNT, 0, 1, 0), + F_B(HIS_BANWHO, 0, 1, 0), + F_B(HIS_KILLWHO, 0, 1, 0), + F_B(HIS_REWRITE, 0, 1, 0), + F_I(HIS_REMOTE, 0, 1, 0), + F_B(HIS_NETSPLIT, 0, 1, 0), + F_S(HIS_SERVERNAME, 0, "*.undernet.org", 0), + F_S(HIS_SERVERINFO, 0, "The Undernet Underworld", 0), + F_S(HIS_URLSERVERS, 0, "http://www.undernet.org/servers.php", 0), + + /* Misc. random stuff */ + F_S(NETWORK, 0, "UnderNet", 0), + F_S(URL_CLIENTS, 0, "ftp://ftp.undernet.org/pub/irc/clients", 0), #undef F_S #undef F_B #undef F_I @@ -687,7 +743,7 @@ feature_init(void) /* report all F-lines */ void -feature_report(struct Client* to) +feature_report(struct Client* to, struct StatDesc* sd, int stat, char* param) { int i; diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l index f3d893b..35ecc04 100644 --- a/ircd/ircd_lexer.l +++ b/ircd/ircd_lexer.l @@ -120,7 +120,9 @@ all return ALL; ip return IP; crule return CRULE; kill return KILL; +quarantine return QUARANTINE; features return FEATURES; +channel return CHANNEL; bypass_local_channel_limits return TPRIV_CHAN_LIMIT; set_local_channel_modes return TPRIV_MODE_LCHAN; protected_local_channel return TPRIV_DEOP_LCHAN; diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c index bbc3e36..37e942b 100644 --- a/ircd/ircd_log.c +++ b/ircd/ircd_log.c @@ -637,7 +637,8 @@ log_set_file(const char *subsys, const char *filename) desc->mark &= ~LOG_MARK_FILE; /* file has been reset to defaults */ /* no change, don't go to the trouble of destroying and recreating */ - if (desc->file && filename && !strcmp(desc->file->file, filename)) + if (desc->file && desc->file->file && filename && + !strcmp(desc->file->file, filename)) return 0; /* debug log is special, since it has to be opened on fd 2 */ @@ -868,10 +869,12 @@ log_feature_report(struct Client *to, int flag) { int i; - for (i = 0; i < LS_LAST_SYSTEM; i++) { + for (i = 0; i < LS_LAST_SYSTEM; i++) + { if (logDesc[i].mark & LOG_MARK_FILE) /* report file */ send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FILE %s", - logDesc[i].name, logDesc[i].file->file); + logDesc[i].name, (logDesc[i].file && logDesc[i].file->file ? + logDesc[i].file->file : "(terminal)")); if (logDesc[i].mark & LOG_MARK_FACILITY) /* report facility */ send_reply(to, SND_EXPLICIT | RPL_STATSFLINE, "F LOG %s FACILITY %s", diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 8db80e6..4e63ff9 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -62,6 +62,8 @@ extern struct DenyConf* denyConfList; extern struct CRuleConf* cruleConfList; extern struct ServerConf* serverConfList; + extern struct qline *GlobalQuarantineList; + int yylex(void); /* Now all the globals we need :/... */ @@ -73,6 +75,7 @@ struct ConfItem *aconf; struct DenyConf *dconf; struct ServerConf *sconf; + struct qline *qconf = NULL; %} %token QSTRING @@ -85,6 +88,7 @@ %token CONTACT %token CONNECT %token CLASS +%token CHANNEL %token PINGFREQ %token CONNECTFREQ %token MAXLINKS @@ -134,6 +138,7 @@ %token ALL %token IP %token FEATURES +%token QUARANTINE /* and now a lot of priviledges... */ %token TPRIV_CHAN_LIMIT, TPRIV_MODE_LCHAN, TPRIV_DEOP_LCHAN, TPRIV_WALK_LCHAN %token TPRIV_KILL, TPRIV_LOCAL_KILL, TPRIV_REHASH, TPRIV_RESTART, TPRIV_DIE @@ -159,7 +164,7 @@ blocks: blocks block | block; block: adminblock | generalblock | classblock | connectblock | serverblock | operblock | portblock | jupeblock | clientblock | - killblock | cruleblock | motdblock | featuresblock; + killblock | cruleblock | motdblock | featuresblock | quarantineblock; /* The timespec, sizespec and expr was ripped straight from * ircd-hybrid-7. */ @@ -470,7 +475,6 @@ operblock: OPER aconf = MyMalloc(sizeof(*aconf)); memset(aconf, 0, sizeof(*aconf)); aconf->status = CONF_OPERATOR; - set_initial_oper_privs(aconf, (FLAGS_OPER | FLAGS_LOCOP)); } '{' operitems '}' ';' { if (aconf->name != NULL && aconf->passwd != NULL && aconf->host != NULL) @@ -509,12 +513,8 @@ operlocal: LOCAL '=' YES ';' * permission values here. But for now, I am just going with local * opers... */ aconf->status = CONF_LOCOP; - /* XXX blow away existing priviledges. */ - set_initial_oper_privs(aconf, FLAGS_LOCOP); } | LOCAL '=' NO ';' { - /* XXX blow away existing priviledges. */ - set_initial_oper_privs(aconf, (FLAGS_OPER|FLAGS_LOCOP)); aconf->status = CONF_OPERATOR; }; @@ -540,9 +540,15 @@ operclass: CLASS '=' QSTRING ';' operpriv: privtype '=' yesorno ';' { if ($3 == 1) + { + PrivSet(&aconf->privs_dirty, $1); PrivSet(&aconf->privs, $1); + } else + { + PrivSet(&aconf->privs_dirty, $1); PrivClr(&aconf->privs, $1); + } }; privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | @@ -865,3 +871,36 @@ extrastring: QSTRING if (stringno < MAX_STRINGS) stringlist[stringno++] = $1; }; + +quarantineblock: QUARANTINE '{' +{ + if (qconf != NULL) + qconf = MyMalloc(sizeof(*qconf)); + else + { + if (qconf->chname != NULL) + MyFree(qconf->chname); + if (qconf->reason != NULL) + MyFree(qconf->reason); + } + memset(qconf, 0, sizeof(*qconf)); +} quarantineitems '}' ';' +{ + if (qconf->chname == NULL || qconf->reason == NULL) + { + log_write(LS_CONFIG, L_ERROR, 0, "quarantine blocks need a channel name " + "and a reason."); + return; + } + qconf->next = GlobalQuarantineList; + GlobalQuarantineList = qconf; + qconf = NULL; +}; + +quarantineitems: CHANNEL NAME '=' QSTRING ';' +{ + DupString(qconf->chname, yylval.text); +} | REASON '=' QSTRING ';' +{ + DupString(qconf->reason, yylval.text); +}; diff --git a/ircd/ircd_relay.c b/ircd/ircd_relay.c index d499050..2b59926 100644 --- a/ircd/ircd_relay.c +++ b/ircd/ircd_relay.c @@ -31,6 +31,7 @@ #include "ircd.h" #include "ircd_chattr.h" #include "ircd_reply.h" +#include "ircd_features.h" #include "ircd_string.h" #include "match.h" #include "msg.h" @@ -158,8 +159,7 @@ void relay_directed_message(struct Client* sptr, char* name, char* server, const assert(0 != text); assert(0 != server); - if ((acptr = FindServer(server + 1)) == NULL || - !IsChannelService(acptr)) + if ((acptr = FindServer(server + 1)) == NULL || !IsChannelService(acptr)) { send_reply(sptr, ERR_NOSUCHNICK, name); return; @@ -313,8 +313,9 @@ void server_relay_private_message(struct Client* sptr, const char* name, const c * nickname addressed? */ if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) { - send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left " NETWORK ". " - "Failed to deliver: [%.20s]", text); + send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. " + "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK), + text); return; } if (is_silenced(sptr, acptr)) diff --git a/ircd/ircd_snprintf.c b/ircd/ircd_snprintf.c index 8706e80..0a762aa 100644 --- a/ircd/ircd_snprintf.c +++ b/ircd/ircd_snprintf.c @@ -1434,7 +1434,9 @@ adds(struct BufData *buf_p, int s_len, const char *s) { int overflow = 0; - while (*s && s_len) { /* while the string exists and has non-zero length */ + /* while the string exists and has non-zero length */ + while (s_len && *s) + { /* poor man's inlining; see addc(), above */ if (buf_p->limit == 0) { /* We've gone past the limit... */ buf_p->overflow++; diff --git a/ircd/jupe.c b/ircd/jupe.c index 80691c7..e76455b 100644 --- a/ircd/jupe.c +++ b/ircd/jupe.c @@ -27,8 +27,8 @@ #include "hash.h" #include "ircd.h" #include "ircd_alloc.h" +#include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -123,13 +123,10 @@ jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason, /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at " - "%Tu: %s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name(cli_user(sptr)->server), -#endif + "%Tu: %s", + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset, reason); @@ -173,12 +170,9 @@ jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe, /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring " "at %Tu: %s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name(cli_user(sptr)->server), -#endif + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); @@ -221,12 +215,9 @@ jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe, /* Inform ops and log it */ sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: " "%s", -#ifdef HEAD_IN_SAND_SNOTICES - cli_name(sptr), -#else - IsServer(sptr) ? cli_name(sptr) : - cli_name(cli_user(sptr)->server), -#endif + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? + cli_name(sptr) : + cli_name((cli_user(sptr))->server), JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); @@ -340,3 +331,19 @@ jupe_list(struct Client *sptr, char *server) /* end of jupe information */ return send_reply(sptr, RPL_ENDOFJUPELIST); } + +int +jupe_memory_count(size_t *ju_size) +{ + struct Jupe *jupe; + unsigned int ju = 0; + + for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next) + { + ju++; + ju_size += sizeof(struct Jupe); + ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0; + ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0; + } + return ju; +} diff --git a/ircd/list.c b/ircd/list.c index 79dab30..10fe840 100644 --- a/ircd/list.c +++ b/ircd/list.c @@ -314,7 +314,7 @@ void remove_client_from_list(struct Client *cptr) assert(!cli_next(cptr) || cli_verify(cli_next(cptr))); assert(!IsMe(cptr)); - /* Only try to remove cptr from the list if it IS in the list. + /* Only try remove cptr from the list if it IS in the list. * cli_next(cptr) cannot be NULL here, as &me is always the end * the list, and we never remove &me. -GW */ diff --git a/ircd/listener.c b/ircd/listener.c index 6959ff7..7b05e49 100644 --- a/ircd/listener.c +++ b/ircd/listener.c @@ -34,6 +34,7 @@ #include "s_bsd.h" #include "s_conf.h" #include "s_misc.h" +#include "s_stats.h" #include "send.h" #include "sys.h" /* MAXCLIENTS */ @@ -116,12 +117,20 @@ void count_listener_memory(int* count_out, size_t* size_out) * side effects - show ports * author - Dianora */ -void show_ports(struct Client* sptr, int show_hidden, int port, int count) +void show_ports(struct Client* sptr, struct StatDesc* sd, int stat, + char* param) { - struct Listener* listener = 0; - char flags[8]; + struct Listener *listener = 0; + char flags[8]; + int show_hidden = IsOper(sptr); + int count = (IsOper(sptr) || MyUser(sptr)) ? 100 : 8; + int port = 0; + assert(0 != sptr); + if (param) + port = atoi(param); + for (listener = ListenerPollList; listener; listener = listener->next) { if (port && port != listener->port) continue; @@ -441,9 +450,24 @@ static void accept_connection(struct Event* ev) * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. + * + * This piece of code implements multi-accept, based + * on the idea that poll/select can only be efficient, + * if we succeed in handling all available events, + * i.e. accept all pending connections. + * + * http://www.hpl.hp.com/techreports/2000/HPL-2000-174.html */ - if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, - &addrlen))) { + while (1) + { + if ((fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen)) + == -1) + { + if (errno == EAGAIN || +#ifdef EWOULDBLOCK + errno == EWOULDBLOCK) +#endif + return; /* Lotsa admins seem to have problems with not giving enough file * descriptors to their server so we'll add a generic warning mechanism * here. If it turns out too many messages are generated for @@ -452,38 +476,46 @@ static void accept_connection(struct Event* ev) sendto_opmask_butone(0, SNO_TCPCOMMON, "Unable to accept connection: %m"); return; + } + /* + * check for connection limit. If this fd exceeds the limit, + * all further accept()ed connections will also exceed it. + * Enable the server to clear out other connections before + * continuing to accept() new connections. + */ + if (fd > MAXCLIENTS - 1) + { + ++ServerStats->is_ref; + send(fd, "ERROR :All connections in use\r\n", 32, 0); + close(fd); + return; + } + /* + * check to see if listener is shutting down. Continue + * to accept(), because it makes sense to clear our the + * socket's queue as fast as possible. + */ + if (!listener->active) + { + ++ServerStats->is_ref; + send(fd, "ERROR :Use another port\r\n", 25, 0); + close(fd); + continue; + } + /* + * check to see if connection is allowed for this address mask + */ + if (!connection_allowed((const char*) &addr, + (const char*) &listener->mask)) + { + ++ServerStats->is_ref; + send(fd, "ERROR :Use another port\r\n", 25, 0); + close(fd); + continue; + } + ++ServerStats->is_ac; + /* nextping = CurrentTime; */ + add_connection(listener, fd); } - /* - * check for connection limit - */ - if (fd > MAXCLIENTS - 1) { - ++ServerStats->is_ref; - send(fd, "ERROR :All connections in use\r\n", 32, 0); - close(fd); - return; - } - /* - * check to see if listener is shutting down - */ - if (!listener->active) { - ++ServerStats->is_ref; - send(fd, "ERROR :Use another port\r\n", 25, 0); - close(fd); - return; - } - /* - * check to see if connection is allowed for this address mask - */ - if (!connection_allowed((const char*) &addr, - (const char*) &listener->mask)) { - ++ServerStats->is_ref; - send(fd, "ERROR :Use another port\r\n", 25, 0); - close(fd); - return; - } - ++ServerStats->is_ac; -/* nextping = CurrentTime; */ - - add_connection(listener, fd); } } diff --git a/ircd/m_account.c b/ircd/m_account.c index f5615e5..aa795ed 100644 --- a/ircd/m_account.c +++ b/ircd/m_account.c @@ -120,8 +120,13 @@ int ms_account(struct Client* cptr, struct Client* sptr, int parc, assert(0 == cli_user(acptr)->account[0]); + if (strlen(parv[2]) > ACCOUNTLEN) + return protocol_violation(cptr, + "Received account (%s) longer than %d for %s; " + "ignoring.", + parv[2], ACCOUNTLEN, cli_name(acptr)); ircd_strncpy(cli_user(acptr)->account, parv[2], ACCOUNTLEN); - hide_hostmask(acptr, FLAGS_ACCOUNT); + hide_hostmask(acptr, FLAG_ACCOUNT); sendcmdto_serv_butone(sptr, CMD_ACCOUNT, cptr, "%C %s", acptr, cli_user(acptr)->account); diff --git a/ircd/m_admin.c b/ircd/m_admin.c index e9b4488..dd8d0f4 100644 --- a/ircd/m_admin.c +++ b/ircd/m_admin.c @@ -84,7 +84,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "msg.h" #include "numeric.h" @@ -115,10 +115,12 @@ static int send_admin_info(struct Client* sptr) */ int m_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { + struct Client *acptr; + assert(0 != cptr); assert(cptr == sptr); - if (parc > 1) + if (parc > 1 && (!(acptr = find_match_server(parv[1])) || !IsMe(acptr))) return send_reply(sptr, ERR_NOPRIVILEGES); return send_admin_info(sptr); @@ -135,8 +137,8 @@ int mo_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(0 != cptr); assert(cptr == sptr); - if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, HEAD_IN_SAND_REMOTE, ":%C", 1, - parc, parv) != HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_ADMIN, cptr, feature_int(FEAT_HIS_REMOTE), + ":%C", 1, parc, parv) != HUNTED_ISME) return 0; return send_admin_info(sptr); } diff --git a/ircd/m_asll.c b/ircd/m_asll.c new file mode 100644 index 0000000..5da2c87 --- /dev/null +++ b/ircd/m_asll.c @@ -0,0 +1,175 @@ +/* + * IRC - Internet Relay Chat, ircd/m_asll.c + * Copyright (C) 2002 Alex Badea + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#include "config.h" + +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "numeric.h" +#include "numnicks.h" +#include "match.h" +#include "msg.h" +#include "send.h" +#include "s_bsd.h" +#include "s_user.h" + +#include +#include + +static int send_asll_reply(struct Client *from, struct Client *to, char *server, + int rtt, int up, int down) +{ + sendcmdto_one(from, CMD_NOTICE, to, + (up || down) ? "%C :AsLL for %s -- RTT: %ims Upstream: %ims Downstream: %ims" : + rtt ? "%C :AsLL for %s -- RTT: %ims [no asymm info]" : + "%C :AsLL for %s -- [unknown]", + to, server, rtt, up, down); + return 0; +} + +/* + * ms_asll - server message handler + */ +int ms_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + char *mask; + struct Client *acptr; + int i; + + if (parc < 2) + return need_more_params(sptr, "ASLL"); + + if (parc > 5) { + if (!(acptr = findNUser(parv[1]))) + return 0; + if (MyUser(acptr)) + send_asll_reply(sptr, acptr, parv[2], atoi(parv[3]), atoi(parv[4]), atoi(parv[5])); + else + sendcmdto_prio_one(sptr, CMD_ASLL, acptr, "%C %s %s %s %s", + acptr, parv[2], parv[3], parv[4], parv[5]); + return 0; + } + + if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME) + return 0; + mask = parv[1]; + + for (i = 0; i <= HighestFd; i++) { + acptr = LocalClientArray[i]; + if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr))) + continue; + sendcmdto_prio_one(&me, CMD_ASLL, sptr, "%C %s %i %i %i", sptr, + cli_name(acptr), cli_serv(acptr)->asll_rtt, + cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from); + } + return 0; +} + +/* + * mo_asll - oper message handler + */ +int mo_asll(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + char *mask; + struct Client *acptr; + int i; + + if (parc < 2) + return need_more_params(sptr, "ASLL"); + + if (parc == 2 && MyUser(sptr)) + parv[parc++] = cli_name(&me); + + if (hunt_server_prio_cmd(sptr, CMD_ASLL, cptr, 1, "%s %C", 2, parc, parv) != HUNTED_ISME) + return 0; + mask = parv[1]; + + for (i = 0; i <= HighestFd; i++) { + acptr = LocalClientArray[i]; + if (!acptr || !IsServer(acptr) || !MyConnect(acptr) || match(mask, cli_name(acptr))) + continue; + send_asll_reply(&me, sptr, cli_name(acptr), cli_serv(acptr)->asll_rtt, + cli_serv(acptr)->asll_to, cli_serv(acptr)->asll_from); + } + return 0; +} diff --git a/ircd/m_away.c b/ircd/m_away.c index b926a6a..8718f07 100644 --- a/ircd/m_away.c +++ b/ircd/m_away.c @@ -153,12 +153,15 @@ static int user_set_away(struct User* user, char* message) int m_away(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char* away_message = parv[1]; + int was_away = cli_user(sptr)->away != 0; assert(0 != cptr); assert(cptr == sptr); - if (user_set_away(cli_user(sptr), away_message)) { - sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, ":%s", away_message); + if (user_set_away(cli_user(sptr), away_message)) + { + if (!was_away) + sendcmdto_serv_butone(sptr, CMD_AWAY, cptr, ":%s", away_message); send_reply(sptr, RPL_NOWAWAY); } else { diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 15475b8..7726e7d 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -86,7 +86,7 @@ #include "hash.h" #include "ircd.h" #include "ircd_alloc.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "list.h" @@ -178,7 +178,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct ModeBuf modebuf, *mbuf = 0; struct Channel *chptr; time_t timestamp; - struct Membership *member; + struct Membership *member, *nmember; struct SLink *lp, **lp_p; unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST); int param, nickpos = 0, banpos = 0; @@ -198,11 +198,15 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) * than the burst TS (anti net.ride). The modes hack is here because * we have to do this before mode_parse, as chptr may go away. */ - for (param = 3; param < parc; param++) { + for (param = 3; param < parc; param++) + { if (parv[param][0] != '+') continue; - if (strchr(parv[param], 'i') || strchr(parv[param], 'k')) { - for (member = chptr->members; member; member = member->next_member) { + if (strchr(parv[param], 'i') || strchr(parv[param], 'k')) + { + for (member = chptr->members; member; member = nmember) + { + nmember = member->next_member; if (!MyUser(member->user) || IsZombie(member)) continue; sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user); @@ -303,11 +307,9 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) newban = make_link(); /* create new ban */ DupString(newban->value.ban.banstr, ban); -#ifdef HEAD_IN_SAND_BANWHO - DupString(newban->value.ban.who, cli_name(&me)); -#else - DupString(newban->value.ban.who, cli_name(sptr)); -#endif + + DupString(newban->value.ban.who, + cli_name(feature_bool(FEAT_HIS_BANWHO) ? &me : sptr)); newban->value.ban.when = TStime(); newban->flags = CHFL_BAN | CHFL_BURST_BAN; /* set flags */ diff --git a/ircd/m_clearmode.c b/ircd/m_clearmode.c index 9005bed..ac164d2 100644 --- a/ircd/m_clearmode.c +++ b/ircd/m_clearmode.c @@ -95,6 +95,7 @@ #include "msg.h" #include "numeric.h" #include "numnicks.h" +#include "s_conf.h" #include "send.h" #include "support.h" @@ -133,10 +134,6 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr, struct SLink *link, *next; struct Membership *member; - /* Um...yeah, like it's supposed to have any modes at all. */ - if (IsModelessChannel(chptr->chname)) - return 0; - /* Ok, so what are we supposed to get rid of? */ for (; *control; control++) { for (flag_p = flags; flag_p[0]; flag_p += 2) @@ -279,6 +276,8 @@ mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr; char *control = "ovpsmikbl"; /* default control string */ + const char *chname, *qreason; + int force = 0; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "CLEARMODE"); @@ -289,14 +288,28 @@ mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (parc > 2) control = parv[2]; + chname = parv[1]; + if (*chname == '!') + { + chname++; + if (!HasPriv(sptr, IsLocalChannel(chname) ? + PRIV_FORCE_LOCAL_OPMODE : + PRIV_FORCE_OPMODE)) + return send_reply(sptr, ERR_NOPRIVILEGES); + force = 1; + } + clean_channelname(parv[1]); if (!HasPriv(sptr, IsLocalChannel(parv[1]) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); - if (('#' != *parv[1] && '&' != *parv[1]) || !(chptr = FindChannel(parv[1]))) - return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); + if (('#' != *chname && '&' != *chname) || !(chptr = FindChannel(chname))) + return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); + if (!force && (qreason = find_quarantine(chptr->chname))) + return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason); + return do_clearmode(cptr, sptr, chptr, control); } diff --git a/ircd/m_create.c b/ircd/m_create.c index 7f8689c..f496aae 100644 --- a/ircd/m_create.c +++ b/ircd/m_create.c @@ -122,9 +122,6 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) chanTS = atoi(parv[2]); - joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); - joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS); - /* A create that didn't appear during a burst has that servers idea of * the current time. Use it for lag calculations. */ @@ -133,18 +130,28 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) cli_serv(cli_user(sptr)->server)->lag = TStime() - chanTS; /* If this server is >1 minute fast, warn */ - if (TStime() - chanTS<-60) { + if (TStime() - chanTS<-60) + { static time_t rate; sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate, - "Timestamp drift from %C (%is)", + "Timestamp drift from %C (%is); issuing " + "SETTIME to correct this", cli_user(sptr)->server, chanTS - TStime()); - /* If this server is >5 minutes fast, squit it */ if (TStime() - chanTS<-5*60*60) return exit_client(sptr, sptr, &me, "Timestamp Drift/Bogus TS"); + /* Now issue a SETTIME to resync. If we're in the wrong, our + * (RELIABLE_CLOCK) hub will bounce a SETTIME back to us. + */ + sendcmdto_prio_one(&me, CMD_SETTIME, cli_user(sptr)->server, + "%Tu %C", TStime(), cli_user(sptr)->server); } + joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); + joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, chanTS); + + /* For each channel in the comma seperated list: */ for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ",")) { @@ -153,7 +160,8 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (IsLocalChannel(name)) continue; - if ((chptr = FindChannel(name))) { + if ((chptr = FindChannel(name))) + { name = chptr->chname; /* Check if we need to bounce a mode */ @@ -171,15 +179,15 @@ int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) badop = 1; } - } else /* Channel doesn't exist: create it */ + } + else /* Channel doesn't exist: create it */ chptr = get_channel(sptr, name, CGT_CREATE); if (!badop) /* Set/correct TS */ chptr->creationtime = chanTS; joinbuf_join(badop ? &join : &create, chptr, - (badop || IsModelessChannel(name)) ? - CHFL_DEOPPED : CHFL_CHANOP); + (badop || CHFL_CHANOP)); } joinbuf_flush(&join); /* flush out the joins and creates */ diff --git a/ircd/m_gline.c b/ircd/m_gline.c index e0d0f9a..cee85ac 100644 --- a/ircd/m_gline.c +++ b/ircd/m_gline.c @@ -126,25 +126,29 @@ ms_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct Gline *agline; unsigned int flags = 0; time_t expire_off, lastmod = 0; - char *mask = parv[2], *target = parv[1], *reason; + char *mask = parv[2], *target = parv[1], *reason = "No reason"; - if (*mask == '!') { + if (*mask == '!') + { mask++; - - if (HasPriv(sptr, PRIV_WIDE_GLINE)) - flags |= GLINE_OPERFORCE; + flags |= GLINE_OPERFORCE; } - if ((parc == 3 && *mask == '-') || parc == 5) { + if ((parc == 3 && *mask == '-') || parc == 5) + { if (!find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) return need_more_params(sptr, "GLINE"); - reason = parv[4]; + if (parc > 4) + reason = parv[4]; flags |= GLINE_FORCE; - } else if (parc > 5) { + } + else if (parc > 5) + { lastmod = atoi(parv[4]); reason = parv[5]; - } else + } + else return need_more_params(sptr, "GLINE"); if (!(target[0] == '*' && target[1] == '\0')) { @@ -263,12 +267,16 @@ mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } else return need_more_params(sptr, "GLINE"); - if (target) { - if (!(target[0] == '*' && target[1] == '\0')) { + if (target) + { + if (!(target[0] == '*' && target[1] == '\0')) + { if (!(acptr = find_match_server(target))) return send_reply(sptr, ERR_NOSUCHSERVER, target); - if (!IsMe(acptr)) { /* manually propagate, since we don't set it */ + /* manually propagate, since we don't set it */ + if (!IsMe(acptr)) + { if (!feature_bool(FEAT_CONFIG_OPERCMDS)) return send_reply(sptr, ERR_DISABLED, "GLINE"); @@ -280,12 +288,9 @@ mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) flags & GLINE_ACTIVE ? '+' : '-', mask, parv[3], TStime(), reason); return 0; - } else if (!HasPriv(sptr, PRIV_LOCAL_GLINE)) - return send_reply(sptr, ERR_NOPRIVILEGES); - + } flags |= GLINE_LOCAL; - } else if (!HasPriv(sptr, PRIV_GLINE)) - return send_reply(sptr, ERR_NOPRIVILEGES); + } } if (!(flags & GLINE_LOCAL) && !feature_bool(FEAT_CONFIG_OPERCMDS)) @@ -293,6 +298,9 @@ mo_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) agline = gline_find(mask, GLINE_ANY | GLINE_EXACT); + if (!HasPriv(sptr, (flags & GLINE_LOCAL ? PRIV_LOCAL_GLINE : PRIV_GLINE))) + return send_reply(sptr, ERR_NOPRIVILEGES); + if (agline) { if (GlineIsLocal(agline) && !(flags & GLINE_LOCAL)) /* global over local */ gline_free(agline); diff --git a/ircd/m_invite.c b/ircd/m_invite.c index 7b0b493..ca5401e 100644 --- a/ircd/m_invite.c +++ b/ircd/m_invite.c @@ -146,7 +146,8 @@ int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) return 0; if (!(chptr = FindChannel(parv[2]))) { - if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2])) { + if (IsLocalChannel(parv[2])) + { send_reply(sptr, ERR_NOTONCHANNEL, parv[2]); return 0; } @@ -195,7 +196,7 @@ int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (MyConnect(acptr)) add_invite(acptr, chptr); - if (!IsLocalChannel(chptr->chname)) + if (!IsLocalChannel(chptr->chname) || MyConnect(acptr)) sendcmdto_one(sptr, CMD_INVITE, acptr, "%s :%H", cli_name(acptr), chptr); return 0; diff --git a/ircd/m_join.c b/ircd/m_join.c index 8843b5d..d2bfcfe 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -101,21 +101,6 @@ #include #include -/* - * Helper function to see if there are any control characters - * in a given string - */ -static char * -HasControlChars(char *mstring) -{ - unsigned char *j; - for(j = mstring; *j ; j++) { - if(*j <= 32) { return j; } - } - - return 0; -} - /* * Helper function to find last 0 in a comma-separated list of * channel names. @@ -185,7 +170,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct ModeBuf mbuf; struct Gline *gline; unsigned int flags = 0; - int i; + int i, j, k = 0; char *p = 0; char *chanlist; char *name; @@ -208,7 +193,21 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (join0(&join, cptr, sptr, name)) /* did client do a JOIN 0? */ continue; - if (!IsChannelName(name) || HasControlChars(name)) { /* bad channel name */ + if (!IsChannelName(name)) + { + /* bad channel name */ + send_reply(sptr, ERR_NOSUCHCHANNEL, name); + continue; + } + + /* This checks if the channel contains control codes and rejects em + * until they are gone, then we will do it otherwise - *SOB Mode* + */ + for (k = 0, j = 0; name[j]; j++) + if (IsCntrl(name[j])) + k++; + if (k > 0) + { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } @@ -220,13 +219,15 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) continue; } - if ((chptr = FindChannel(name))) { + if ((chptr = FindChannel(name))) + { if (find_member_link(chptr, sptr)) continue; /* already on channel */ flags = CHFL_DEOPPED; - } else - flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP; + } + else + flags = CHFL_CHANOP; if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { @@ -253,31 +254,43 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (check_target_limit(sptr, chptr, chptr->chname, 0)) continue; /* exceeded target limit */ else if (!is_level0_op && (i = can_join(sptr, chptr, keys))) { - if (i > MAGIC_OPER_OVERRIDE) { /* oper overrode mode */ - switch (i - MAGIC_OPER_OVERRIDE) { - case ERR_CHANNELISFULL: /* figure out which mode */ - i = 'l'; - break; - - case ERR_INVITEONLYCHAN: - i = 'i'; - break; - - case ERR_BANNEDFROMCHAN: - i = 'b'; - break; - - case ERR_BADCHANNELKEY: - i = 'k'; - break; - } - - /* send accountability notice */ - sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " - "(overriding +%c)", sptr, chptr, i); - } else { - send_reply(sptr, i, chptr->chname); - continue; + if (i > MAGIC_OPER_OVERRIDE) + { /* oper overrode mode */ + switch (i - MAGIC_OPER_OVERRIDE) + { + case ERR_CHANNELISFULL: /* figure out which mode */ + i = 'l'; + break; + + case ERR_INVITEONLYCHAN: + i = 'i'; + break; + + case ERR_BANNEDFROMCHAN: + i = 'b'; + break; + + case ERR_BADCHANNELKEY: + i = 'k'; + break; + + case ERR_NEEDREGGEDNICK: + i = 'r'; + break; + + default: + i = '?'; + break; + } + + /* send accountability notice */ + sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " + "(overriding +%c)", sptr, chptr, i); + } + else + { + send_reply(sptr, i, chptr->chname); + continue; } } /* else if ((i = can_join(sptr, chptr, keys))) */ @@ -294,12 +307,14 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } } else if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* couldn't get channel */ - else if (check_target_limit(sptr, chptr, chptr->chname, 1)) { + else if (check_target_limit(sptr, chptr, chptr->chname, 1)) + { /* Note: check_target_limit will only ever return 0 here */ chptr->members = 0; destruct_channel(chptr); /* created it... */ continue; - } else + } + else joinbuf_join(&create, chptr, flags | CHFL_CHANNEL_MANAGER); del_invite(sptr, chptr); @@ -333,8 +348,14 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) char *chanlist; char *name; - if (IsServer(sptr)) { - return protocol_violation(sptr,"%s tried to JOIN a channel, duh!", cli_name(sptr)); + if (IsServer(sptr)) + { + return protocol_violation(cptr, + "%s tried to JOIN %s, duh!", + cli_name(sptr), + (parc < 2 || *parv[1] == '\0') ? "a channel" : + parv[1] + ); } if (parc < 2 || *parv[1] == '\0') @@ -354,25 +375,29 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (join0(&join, cptr, sptr, name)) /* did client do a JOIN 0? */ continue; - if (IsLocalChannel(name) || !IsChannelName(name)) { - protocol_violation(sptr,"%s tried to join %s",cli_name(cptr),name); + if (IsLocalChannel(name) || !IsChannelName(name)) + { + protocol_violation(cptr, "%s tried to join %s", cli_name(sptr), name); continue; } - if (!(chptr = FindChannel(name))) { + if (!(chptr = FindChannel(name))) + { /* No channel exists, so create one */ - if (!(chptr = get_channel(sptr, name, CGT_CREATE))) { + if (!(chptr = get_channel(sptr, name, CGT_CREATE))) + { protocol_violation(sptr,"couldn't get channel %s for %s", name,cli_name(sptr)); continue; } - flags = CHFL_DEOPPED | ((cli_flags(sptr) & FLAGS_TS8) ? CHFL_SERVOPOK : 0); + flags = CHFL_DEOPPED | (HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0); /* when the network is 2.10.11+ then remove MAGIC_REMOTE_JOIN_TS */ chptr->creationtime = creation ? creation : MAGIC_REMOTE_JOIN_TS; } else { /* We have a valid channel? */ - if ((member = find_member_link(chptr, sptr))) { + if ((member = find_member_link(chptr, sptr))) + { /* It is impossible to get here --Run */ if (!IsZombie(member)) /* already on channel */ continue; @@ -380,8 +405,9 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK); remove_user_from_channel(sptr, chptr); chptr = FindChannel(name); - } else - flags = CHFL_DEOPPED | ((cli_flags(sptr) & FLAGS_TS8) ? CHFL_SERVOPOK : 0); + } + else + flags = CHFL_DEOPPED | (HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0); /* Always copy the timestamp when it is older, that is the only way to ensure network-wide synchronization of creation times. */ if (creation && creation < chptr->creationtime) diff --git a/ircd/m_kick.c b/ircd/m_kick.c index 4a72005..4aed611 100644 --- a/ircd/m_kick.c +++ b/ircd/m_kick.c @@ -110,7 +110,7 @@ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct Membership* member2; char *name, *comment; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); @@ -122,7 +122,7 @@ int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) return send_reply(sptr, ERR_NOSUCHCHANNEL, name); if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2) - || !IsChanOp(member2) || IsModelessChannel(name)) + || !IsChanOp(member2)) return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name); if (!(who = find_chasing(sptr, parv[2], 0))) @@ -176,7 +176,7 @@ int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) struct Membership *member = 0, *sptr_link = 0; char *name, *comment; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 3 || *parv[1] == '\0') return need_more_params(sptr, "KICK"); @@ -195,7 +195,10 @@ int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) member = 0; /* Send HACK notice, but not for servers in BURST */ - if (IsServer(sptr) && !IsBurstOrBurstAck(sptr)) + /* 2002-10-17: Don't send HACK if the users local server is kicking them */ + if (IsServer(sptr) && + !IsBurstOrBurstAck(sptr) && + sptr!=cli_from(who)) sendto_opmask_butone(0, SNO_HACK4, "HACK: %C KICK %H %C %s", sptr, chptr, who, comment); diff --git a/ircd/m_kill.c b/ircd/m_kill.c index 1a47c9b..4f7f7fb 100644 --- a/ircd/m_kill.c +++ b/ircd/m_kill.c @@ -84,8 +84,8 @@ #include "client.h" #include "hash.h" #include "ircd.h" +#include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -104,11 +104,11 @@ * */ static int do_kill(struct Client* cptr, struct Client* sptr, - struct Client* victim, char* inpath, char* path, char *msg) + struct Client* victim, char* inpath, char* path, char* msg) { assert(0 != cptr); assert(0 != sptr); - assert(IsUser(victim)); + assert(!IsServer(victim)); /* * Notify all *local* opers about the KILL (this includes the one @@ -135,11 +135,11 @@ static int do_kill(struct Client* cptr, struct Client* sptr, inpath, path, msg); /* - * Set FLAGS_KILLED. This prevents exit_one_client from sending + * Set FLAG_KILLED. This prevents exit_one_client from sending * the unnecessary QUIT for this. (This flag should never be * set in any other place) */ - cli_flags(victim) |= FLAGS_KILLED; + SetFlag(victim, FLAG_KILLED); } /* @@ -150,19 +150,15 @@ static int do_kill(struct Client* cptr, struct Client* sptr, * In accordance with the new hiding rules, the victim * always sees the kill as coming from me. */ -#ifdef HEAD_IN_SAND_KILLWHO if (MyConnect(victim)) - sendcmdto_one(&me, CMD_KILL, victim, "%C :%s %s", victim, - HEAD_IN_SAND_SERVERNAME, msg); - return exit_client_msg(cptr, victim, &me, "Killed (%s %s)", - HEAD_IN_SAND_SERVERNAME, msg); -#else - if (MyConnect(victim)) - sendcmdto_one(sptr, CMD_KILL, victim, "%C :%s %s", victim, - cli_name(sptr), msg); - return exit_client_msg(cptr, victim, sptr, "Killed (%s %s)", cli_name(sptr), + sendcmdto_one(feature_bool(FEAT_HIS_KILLWHO) ? &me : sptr, CMD_KILL, + victim, "%C :%s %s", victim, feature_bool(FEAT_HIS_KILLWHO) + ? feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr), msg); + return exit_client_msg(cptr, victim, feature_bool(FEAT_HIS_KILLWHO) + ? &me : sptr, "Killed (%s %s)", + feature_bool(FEAT_HIS_KILLWHO) ? + feature_str(FEAT_HIS_SERVERNAME) : cli_name(sptr), msg); -#endif } /* diff --git a/ircd/m_links.c b/ircd/m_links.c index 60cd7d3..63f615d 100644 --- a/ircd/m_links.c +++ b/ircd/m_links.c @@ -84,7 +84,7 @@ #include "client.h" #include "ircd.h" #include "ircd_defs.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -113,7 +113,16 @@ int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char *mask; - struct Client *acptr = 0; + struct Client *acptr; + + if (feature_bool(FEAT_HIS_LINKS) && !IsAnOper(sptr)) + { + send_reply(sptr, RPL_ENDOFLINKS, parc < 2 ? "*" : parv[1]); + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, + "/LINKS has been disabled, from CFV-165. Visit ", + feature_str(FEAT_HIS_URLSERVERS)); + return 0; + } if (parc > 2) { @@ -141,24 +150,45 @@ int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) return 0; } -#ifdef HEAD_IN_SAND_LINKS -int m_links_redirect(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) -{ - if (parc > 2) - return send_reply(cptr, ERR_NOPRIVILEGES); - - map_dump_links_head_in_sand(sptr, parv[1]); - - send_reply(sptr, RPL_ENDOFLINKS, BadPtr(parv[1]) ? "*" : parv[1]); - - return 0; -} - -#endif HEAD_IN_SAND_LINKS - - - - - - - +/* + * ms_links - server message handler + * + * parv[0] = sender prefix + * parv[1] = servername mask + * + * or + * + * parv[0] = sender prefix + * parv[1] = server to query + * parv[2] = servername mask + */ +int +ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) + { + char *mask; + struct Client *acptr; + + if (parc > 2) + { + if (hunt_server_cmd(sptr, CMD_LINKS, cptr, 1, "%C :%s", 1, parc, parv) != + HUNTED_ISME) + return 0; + mask = parv[2]; + } + else + mask = parc < 2 ? 0 : parv[1]; + + for (acptr = GlobalClientList, collapse(mask); acptr; acptr = cli_next(acptr)) + { + if (!IsServer(acptr) && !IsMe(acptr)) + continue; + if (!BadPtr(mask) && match(mask, cli_name(acptr))) + continue; + send_reply(sptr, RPL_LINKS, cli_name(acptr), cli_name(cli_serv(acptr)->up), + cli_hopcount(acptr), cli_serv(acptr)->prot, + ((cli_info(acptr))[0] ? cli_info(acptr) : "(Unknown Location)")); + } + + send_reply(sptr, RPL_ENDOFLINKS, BadPtr(mask) ? "*" : mask); + return 0; + } diff --git a/ircd/m_lusers.c b/ircd/m_lusers.c index 02da8d7..0409235 100644 --- a/ircd/m_lusers.c +++ b/ircd/m_lusers.c @@ -107,8 +107,8 @@ int m_lusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { int longoutput = MyUser(sptr) || IsOper(sptr); if (parc > 2) - if (hunt_server_cmd(sptr, CMD_LUSERS, cptr, HEAD_IN_SAND_REMOTE, "%s :%C", - 2, parc, parv) != HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_LUSERS, cptr, feature_int(FEAT_HIS_REMOTE), + "%s :%C", 2, parc, parv) != HUNTED_ISME) return 0; send_reply(sptr, RPL_LUSERCLIENT, UserStats.clients - UserStats.inv_clients, diff --git a/ircd/m_map.c b/ircd/m_map.c index 1e4e48b..fb9897f 100644 --- a/ircd/m_map.c +++ b/ircd/m_map.c @@ -102,6 +102,66 @@ #include #include +static void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length) +{ + const char *chr; + static char prompt[64]; + struct DLink *lp; + char *p = prompt + prompt_length; + int cnt = 0; + + *p = '\0'; + if (prompt_length > 60) + send_reply(cptr, RPL_MAPMORE, prompt, cli_name(server)); + else + { + char lag[512]; + if (cli_serv(server)->lag>10000) + lag[0]=0; + else if (cli_serv(server)->lag<0) + strcpy(lag,"(0s)"); + else + sprintf(lag,"(%is)",cli_serv(server)->lag); + if (IsBurst(server)) + chr = "*"; + else if (IsBurstAck(server)) + chr = "!"; + else + chr = ""; + send_reply(cptr, RPL_MAP, prompt, chr, cli_name(server), + lag, (server == &me) ? UserStats.local_clients : + cli_serv(server)->clients); + } + if (prompt_length > 0) + { + p[-1] = ' '; + if (p[-2] == '`') + p[-2] = ' '; + } + if (prompt_length > 60) + return; + strcpy(p, "|-"); + for (lp = cli_serv(server)->down; lp; lp = lp->next) + if (match(mask, cli_name(lp->value.cptr))) + ClrFlag(lp->value.cptr, FLAG_MAP); + else + { + SetFlag(lp->value.cptr, FLAG_MAP); + cnt++; + } + for (lp = cli_serv(server)->down; lp; lp = lp->next) + { + if (!HasFlag(lp->value.cptr, FLAG_MAP)) + continue; + if (--cnt == 0) + *p = '`'; + dump_map(cptr, lp->value.cptr, mask, prompt_length + 2); + } + if (prompt_length > 0) + p[-1] = '-'; +} + + /* * m_map - generic message handler * -- by Run @@ -111,13 +171,16 @@ */ int m_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { -#ifdef HEAD_IN_SAND_MAP - map_dump_head_in_sand(sptr); -#else - if(parc < 2) + if (feature_bool(FEAT_HIS_MAP) && !IsAnOper(sptr)) + { + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s", sptr, + "/MAP has been disabled, from CFV-165. " + "Visit ", feature_str(FEAT_HIS_URLSERVERS)); + return 0; + } + if (parc < 2) parv[1] = "*"; - map_dump(sptr, &me, parv[1], 0); -#endif /* HEAD_IN_SAND_MAP */ + dump_map(sptr, &me, parv[1], 0); send_reply(sptr, RPL_MAPEND); return 0; @@ -128,7 +191,7 @@ int mo_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (parc < 2) parv[1] = "*"; - map_dump(sptr, &me, parv[1], 0); + dump_map(sptr, &me, parv[1], 0); send_reply(sptr, RPL_MAPEND); return 0; diff --git a/ircd/m_mode.c b/ircd/m_mode.c index 474f39b..362bc76 100644 --- a/ircd/m_mode.c +++ b/ircd/m_mode.c @@ -112,11 +112,10 @@ m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) clean_channelname(parv[1]); - if (('#' != *parv[1] && '&' != *parv[1] && '+' != *parv[1]) || - !(chptr = FindChannel(parv[1]))) + if (!IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1]))) return set_user_mode(cptr, sptr, parc, parv); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); member = find_member_link(chptr, sptr); @@ -168,10 +167,11 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (IsLocalChannel(parv[1])) return 0; - if (('#' != *parv[1] && '+' != *parv[1])|| !(chptr = FindChannel(parv[1]))) + if (IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1])) || + IsLocalChannel(parv[1])) return set_user_mode(cptr, sptr, parc, parv); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (IsServer(sptr)) { if (find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) diff --git a/ircd/m_motd.c b/ircd/m_motd.c index b33cfd2..e2cd87d 100644 --- a/ircd/m_motd.c +++ b/ircd/m_motd.c @@ -83,7 +83,7 @@ #include "client.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -115,7 +115,7 @@ */ int m_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { - if (hunt_server_cmd(sptr, CMD_MOTD, cptr, HEAD_IN_SAND_REMOTE, "%C", 1, + if (hunt_server_cmd(sptr, CMD_MOTD, cptr, feature_int(FEAT_HIS_REMOTE), "%C", 1, parc, parv) != HUNTED_ISME) return 0; diff --git a/ircd/m_names.c b/ircd/m_names.c index 01df991..b15f105 100644 --- a/ircd/m_names.c +++ b/ircd/m_names.c @@ -335,6 +335,7 @@ int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) * non secret channels. */ do_names(sptr, chptr, NAMES_VIS); + send_reply(sptr, RPL_ENDOFNAMES, para); } } else { /* Channel doesn't exist. */ send_reply(sptr, RPL_ENDOFNAMES, para); diff --git a/ircd/m_nick.c b/ircd/m_nick.c index 06287dd..48e022c 100644 --- a/ircd/m_nick.c +++ b/ircd/m_nick.c @@ -86,9 +86,9 @@ #include "hash.h" #include "ircd.h" #include "ircd_chattr.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" -#include "ircd_policy.h" #include "msg.h" #include "numeric.h" #include "numnicks.h" @@ -101,6 +101,38 @@ #include #include + /* +* 'do_nick_name' ensures that the given parameter (nick) is really a proper +* string for a nickname (note, the 'nick' may be modified in the process...) +* +* RETURNS the length of the final NICKNAME (0, if nickname is invalid) +* +* Nickname characters are in range 'A'..'}', '_', '-', '0'..'9' +* anything outside the above set will terminate nickname. +* In addition, the first character cannot be '-' or a Digit. +* +* Note: +* The '~'-character should be allowed, but a change should be global, +* some confusion would result if only few servers allowed it... +*/ +static int do_nick_name(char* nick) +{ + char* ch = nick; + char* end = ch + NICKLEN; + assert(0 != ch); + + /* first character in [0..9-] */ + if (*ch == '-' || IsDigit(*ch)) + return 0; + for ( ; (ch < end) && *ch; ++ch) + if (!IsNickChar(*ch)) + break; + + *ch = '\0'; + + return (ch - nick); +} + /* * m_nick - message handler for local clients * parv[0] = sender prefix @@ -140,10 +172,7 @@ int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) strcpy(nick, arg); /* - * If do_nick_name() returns a null name OR if the server sent a nick - * name and do_nick_name() changed it in some way (due to rules of nick - * creation) then reject it. If from a server and we reject it, - * and KILL it. -avalon 4/4/92 + * If do_nick_name() returns a null name then reject it. */ if (0 == do_nick_name(nick)) { send_reply(sptr, ERR_ERRONEUSNICKNAME, arg); @@ -209,6 +238,11 @@ int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) * "dormant nick" way of generating collisions... * * XXX - hmmm can this happen after one is registered? + * + * Yes, client 1 connects to IRC and registers, client 2 connects and + * sends "NICK foo" but doesn't send anything more. client 1 now does + * /nick foo, they should succeed and client 2 gets disconnected with + * the message below. */ if (IsUnknown(acptr) && MyConnect(acptr)) { ++ServerStats->is_ref; @@ -418,11 +452,11 @@ int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) sendcmdto_serv_butone(&me, CMD_KILL, cptr, "%s :%s (%s)", nick, cli_name(&me), type); /* Don't go sending off a QUIT message... */ - cli_flags(sptr) |= FLAGS_KILLED; + SetFlag(sptr, FLAG_KILLED); /* Remove them locally. */ exit_client_msg(cptr, sptr, &me, - "Killed (" HEAD_IN_SAND_SERVERNAME " (Nick collision))", - type); + "Killed (%s (%s))", + feature_str(FEAT_HIS_SERVERNAME), type); /* * We have killed sptr off, zero out it's pointer so if it's used * again we'll know about it --Bleep @@ -439,14 +473,15 @@ int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) send_reply(acptr, ERR_NICKCOLLISION, nick); ServerStats->is_kill++; - cli_flags(acptr) |= FLAGS_KILLED; + SetFlag(acptr, FLAG_KILLED); /* * This exits the client we had before getting the NICK message */ - sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :" HEAD_IN_SAND_SERVERNAME - " (%s)", acptr, type); - exit_client_msg(cptr, acptr, &me, "Killed (" HEAD_IN_SAND_SERVERNAME " (%s))", - type); + sendcmdto_serv_butone(&me, CMD_KILL, NULL, "%C :%s" + " (%s)", acptr, feature_str(FEAT_HIS_SERVERNAME), + type); + exit_client_msg(cptr, acptr, &me, "Killed (%s (%s))", + feature_str(FEAT_HIS_SERVERNAME), type); if (lastnick == cli_lastnick(acptr)) return 0; if (sptr == NULL) diff --git a/ircd/m_notice.c b/ircd/m_notice.c index b195172..09d68a7 100644 --- a/ircd/m_notice.c +++ b/ircd/m_notice.c @@ -112,7 +112,7 @@ int m_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(0 != cptr); assert(cptr == sptr); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE); @@ -155,7 +155,7 @@ int ms_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) char* name; char* server; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 3) { /* @@ -202,7 +202,7 @@ int mo_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(0 != cptr); assert(cptr == sptr); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE); diff --git a/ircd/m_oper.c b/ircd/m_oper.c index 1166840..d334d68 100644 --- a/ircd/m_oper.c +++ b/ircd/m_oper.c @@ -143,7 +143,8 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) aconf = find_conf_exact(name, cli_username(sptr), ircd_ntoa((const char*) &(cli_ip(cptr))), CONF_OPS); - if (!aconf || IsIllegal(aconf)) { + if (!aconf || IsIllegal(aconf)) + { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); @@ -151,8 +152,9 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } assert(0 != (aconf->status & CONF_OPS)); - if (oper_password_match(password, aconf->passwd)) { - unsigned int old_mode = (cli_flags(sptr) & ALL_UMODES); + if (oper_password_match(password, aconf->passwd)) + { + struct Flags old_mode = cli_flags(sptr); if (ACR_OK != attach_conf(sptr, aconf)) { send_reply(sptr, ERR_NOOPERHOST); @@ -175,13 +177,14 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } cli_handler(cptr) = OPER_HANDLER; + SetFlag(sptr, FLAG_WALLOP); + SetFlag(sptr, FLAG_SERVNOTICE); + SetFlag(sptr, FLAG_DEBUG); - cli_flags(sptr) |= (FLAGS_WALLOP | FLAGS_SERVNOTICE | FLAGS_DEBUG); - set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); client_set_privs(sptr, aconf); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ - send_umode_out(cptr, sptr, old_mode, HasPriv(sptr, PRIV_PROPAGATE)); + send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) is now operator (%c)", @@ -190,7 +193,8 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); } - else { + else + { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); @@ -208,9 +212,10 @@ int ms_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) /* * if message arrived from server, trust it, and set to oper */ - if (!IsServer(sptr) && !IsOper(sptr)) { + if (!IsServer(sptr) && !IsOper(sptr)) + { ++UserStats.opers; - cli_flags(sptr) |= FLAGS_OPER; + SetFlag(sptr, FLAG_OPER); sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%s :+o", parv[0]); } return 0; diff --git a/ircd/m_opmode.c b/ircd/m_opmode.c index ddfd734..aab68f5 100644 --- a/ircd/m_opmode.c +++ b/ircd/m_opmode.c @@ -138,6 +138,8 @@ int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; + char *chname, *qreason; + int force = 0; struct Membership *member; if (!feature_bool(FEAT_CONFIG_OPERCMDS)) @@ -146,14 +148,22 @@ int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (parc < 3) return need_more_params(sptr, "OPMODE"); - clean_channelname(parv[1]); + chname = parv[1]; + if (*chname == '!') + { + chname++; + if (!HasPriv(sptr, IsLocalChannel(chname) ? PRIV_FORCE_LOCAL_OPMODE : PRIV_FORCE_OPMODE)) + return send_reply(sptr, ERR_NOPRIVILEGES); + force = 1; + } + clean_channelname(chname); if (!HasPriv(sptr, - IsLocalChannel(parv[1]) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) + IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) return send_reply(sptr, ERR_NOPRIVILEGES); - if (('#' != *parv[1] && '&' != *parv[1]) || !(chptr = FindChannel(parv[1]))) - return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); + if (!IsChannelName(chname) || !(chptr = FindChannel(chname))) + return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); if (!(member = find_member_link(chptr, sptr))) return send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); diff --git a/ircd/m_part.c b/ircd/m_part.c index 020b97a..4924692 100644 --- a/ircd/m_part.c +++ b/ircd/m_part.c @@ -110,7 +110,7 @@ int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) char *p = 0; char *name; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); /* check number of arguments */ if (parc < 2 || parv[1][0] == '\0') @@ -168,7 +168,7 @@ int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) char *p = 0; char *name; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); /* check number of arguments */ if (parc < 2 || parv[1][0] == '\0') @@ -194,6 +194,14 @@ int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (IsZombie(member)) /* figure out special flags... */ flags |= CHFL_ZOMBIE; + /* + * XXX BUG: If a client /part's with a part notice, on channels where + * he's banned, local clients will not see the part notice, but remote + * clients will. + */ + if (!member_can_send_to_channel(member)) + flags |= CHFL_BANNED; + /* part user from channel */ joinbuf_join(&parts, chptr, flags); } diff --git a/ircd/m_ping.c b/ircd/m_ping.c index 82c493b..435b7c6 100644 --- a/ircd/m_ping.c +++ b/ircd/m_ping.c @@ -140,10 +140,12 @@ #include "msg.h" #include "numeric.h" #include "numnicks.h" +#include "opercmds.h" #include "s_debug.h" #include "send.h" #include +#include #include /* @@ -175,15 +177,24 @@ int m_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) int mo_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Client* acptr; - char* destination; + char *destination, *origin; assert(0 != cptr); assert(cptr == sptr); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NOORIGIN); + origin = parv[1]; destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */ + if (parc > 3) + { + /* AsLL ping, send reply back */ + int diff = atoi(militime_float(parv[3])); + sendcmdto_one(&me, CMD_PONG, sptr, "%C %s %s %i %s", &me, origin, + parv[3], diff, militime_float(NULL)); + return 0; + } if (!EmptyString(destination) && 0 != ircd_strcmp(destination, cli_name(&me))) { if ((acptr = FindServer(destination))) sendcmdto_one(sptr, CMD_PING, acptr, "%C :%s", sptr, destination); diff --git a/ircd/m_pong.c b/ircd/m_pong.c index 74b4fcb..a1ecc21 100644 --- a/ircd/m_pong.c +++ b/ircd/m_pong.c @@ -89,6 +89,7 @@ #include "msg.h" #include "numeric.h" #include "numnicks.h" +#include "opercmds.h" #include "s_user.h" #include "send.h" @@ -116,15 +117,32 @@ int ms_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } origin = parv[1]; destination = parv[2]; - cli_flags(cptr) &= ~FLAGS_PINGSENT; - cli_flags(sptr) &= ~FLAGS_PINGSENT; + ClrFlag(cptr, FLAG_PINGSENT); + ClrFlag(sptr, FLAG_PINGSENT); cli_lasttime(cptr) = CurrentTime; - if (!EmptyString(destination) && 0 != ircd_strcmp(destination, cli_name(&me))) { + if (parc > 5) + { + /* AsLL pong */ + cli_serv(cptr)->asll_rtt = atoi(militime_float(parv[3])); + cli_serv(cptr)->asll_to = atoi(parv[4]); + cli_serv(cptr)->asll_from = atoi(militime_float(parv[5])); + return 0; + } + + if (EmptyString(destination)) + return 0; + + if (*destination == '!') + { + /* AsLL ping reply from a non-AsLL server */ + cli_serv(cptr)->asll_rtt = atoi(militime_float(destination + 1)); + } + else if (0 != ircd_strcmp(destination, cli_name(&me))) + { struct Client* acptr; - if ((acptr = FindClient(destination))) { + if ((acptr = FindClient(destination))) sendcmdto_one(sptr, CMD_PONG, acptr, "%s %s", origin, destination); - } } return 0; } @@ -142,7 +160,7 @@ int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(cptr == sptr); assert(!IsRegistered(sptr)); - cli_flags(cptr) &= ~FLAGS_PINGSENT; + ClrFlag(cptr, FLAG_PINGSENT); cli_lasttime(cptr) = CurrentTime; /* * Check to see if this is a PONG :cookie reply from an @@ -175,7 +193,7 @@ int m_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); - cli_flags(cptr) &= ~FLAGS_PINGSENT; + ClrFlag(cptr, FLAG_PINGSENT); cli_lasttime(cptr) = CurrentTime; return 0; } diff --git a/ircd/m_privmsg.c b/ircd/m_privmsg.c index aee3c85..1d257e3 100644 --- a/ircd/m_privmsg.c +++ b/ircd/m_privmsg.c @@ -111,7 +111,7 @@ int m_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(cptr == sptr); assert(0 != cli_user(sptr)); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (feature_bool(FEAT_IDLE_FROM_MSG)) cli_user(sptr)->last = CurrentTime; @@ -152,7 +152,7 @@ int ms_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) char* name; char* server; - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 3) { /* @@ -201,7 +201,7 @@ int mo_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) assert(cptr == sptr); assert(0 != cli_user(sptr)); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(cptr, FLAG_TS8); if (feature_bool(FEAT_IDLE_FROM_MSG)) cli_user(sptr)->last = CurrentTime; diff --git a/ircd/m_server.c b/ircd/m_server.c index c426132..3dafded 100644 --- a/ircd/m_server.c +++ b/ircd/m_server.c @@ -85,7 +85,6 @@ #include "hash.h" #include "ircd.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" @@ -103,7 +102,6 @@ #include "s_serv.h" #include "send.h" #include "userload.h" -#include "map.h" #include #include diff --git a/ircd/m_settime.c b/ircd/m_settime.c index ad6ac3c..6240b52 100644 --- a/ircd/m_settime.c +++ b/ircd/m_settime.c @@ -104,71 +104,87 @@ * * parv[0] = sender prefix * parv[1] = new time - * parv[2] = servername (Only used when sptr is an Oper). + * parv[2] = server name (Only used when sptr is an Oper). */ int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { time_t t; - long int dt; + long dt; static char tbuf[11]; struct DLink *lp; - if (!IsPrivileged(sptr)) - return 0; - if (parc < 2) return need_more_params(sptr, "SETTIME"); - if (parc == 2 && MyUser(sptr)) - parv[parc++] = cli_name(&me); - t = atoi(parv[1]); dt = TStime() - t; if (t < OLDEST_TS || dt < -9000000) { - sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr); + if (IsServer(sptr)) + protocol_violation(sptr, "SETTIME: Bad value (%Tu, delta %l)", t, dt); + else + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value (%Tu, " + "delta %l)", sptr, t, dt); + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :SETTIME: Bad value", sptr); return 0; } - if (IsServer(sptr)) /* send to unlagged servers */ + /* reset time... */ + if (feature_bool(FEAT_RELIABLE_CLOCK)) { - if (feature_bool(FEAT_RELIABLE_CLOCK)) { - ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); - parv[1] = tbuf; - } + ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); + parv[1] = tbuf; + } + if (BadPtr(parv[2])) + { for (lp = cli_serv(&me)->down; lp; lp = lp->next) - if (cptr != lp->value.cptr && MsgQLength(&(cli_sendQ(lp->value.cptr))) < 8000) - sendcmdto_one(sptr, CMD_NOTICE, lp->value.cptr, "%s", parv[1]); + if (cptr != lp->value.cptr) + sendcmdto_prio_one(sptr, CMD_SETTIME, lp->value.cptr, "%s", parv[1]); } else { - ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); - parv[1] = tbuf; if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc, - parv) != HUNTED_ISME) + parv) != HUNTED_ISME) + { + /* If the destination was *not* me, but I'm RELIABLE_CLOCK and the + * delta is more than 30 seconds off, bounce back a corrected + * SETTIME + */ + if (feature_bool(FEAT_RELIABLE_CLOCK) && (dt > 30 || dt < -30)) + sendcmdto_prio_one(&me, CMD_SETTIME, cptr, "%s %C", parv[1], cptr); return 0; + } } - if (feature_bool(FEAT_RELIABLE_CLOCK)) { + if (feature_bool(FEAT_RELIABLE_CLOCK)) + { + /* don't apply settime--reliable */ if ((dt > 600) || (dt < -600)) - sendcmdto_serv_butone(&me, CMD_WALLOPS, 0, ":Bad SETTIME from %s: %Tu", - cli_name(sptr), t); - if (IsUser(sptr)) { + sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu " + "(delta %l)", cli_name(sptr), t, dt); + /* Let user know we're ignoring him */ + if (IsUser(sptr)) + { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld " "seconds %s : RELIABLE_CLOCK is defined", sptr, (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards"); } - } else { + } + else + { sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld " "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards"); + /* Apply time change... */ TSoffset -= dt; - if (IsUser(sptr)) { + /* Let the issuing user know what we did... */ + if (IsUser(sptr)) + { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s", - sptr, (dt < 0) ? -dt : dt, - (dt < 0) ? "forwards" : "backwards"); + sptr, (dt < 0) ? -dt : dt, + (dt < 0) ? "forwards" : "backwards"); } } @@ -185,12 +201,12 @@ int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { time_t t; - long int dt; + long dt; static char tbuf[11]; - struct DLink *lp; - if (!IsPrivileged(sptr)) - return 0; + /* Must be a global oper */ + if (!IsOper(sptr)) + return send_reply(sptr, ERR_NOPRIVILEGES); if (parc < 2) return need_more_params(sptr, "SETTIME"); @@ -199,6 +215,14 @@ int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) parv[parc++] = cli_name(&me); t = atoi(parv[1]); + /* If we're reliable_clock or if the oper specified a 0 time, use current */ + if (!t || feature_bool(FEAT_RELIABLE_CLOCK)) + { + t = TStime(); + ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); + parv[1] = tbuf; + } + dt = TStime() - t; if (t < OLDEST_TS || dt < -9000000) @@ -207,45 +231,30 @@ int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) return 0; } - if (IsServer(sptr)) /* send to unlagged servers */ - { - if (feature_bool(FEAT_RELIABLE_CLOCK)) { - ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); - parv[1] = tbuf; - } + if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc, + parv) != HUNTED_ISME) + return 0; - for (lp = cli_serv(&me)->down; lp; lp = lp->next) - if (cptr != lp->value.cptr && MsgQLength(&(cli_sendQ(lp->value.cptr))) < 8000) - sendcmdto_prio_one(sptr, CMD_SETTIME, lp->value.cptr, "%s", parv[1]); + if (feature_bool(FEAT_RELIABLE_CLOCK)) + { + if ((dt > 600) || (dt < -600)) + sendcmdto_serv_butone(&me, CMD_DESYNCH, 0, ":Bad SETTIME from %s: %Tu " + "(delta %l)", cli_name(sptr), t, dt); + if (IsUser(sptr)) + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld seconds " + "%s: RELIABLE_CLOCK is defined", sptr, (dt < 0) ? -dt : dt, + (dt < 0) ? "forward" : "backward"); } else { - ircd_snprintf(0, tbuf, sizeof(tbuf), "%Tu", TStime()); - parv[1] = tbuf; - if (hunt_server_prio_cmd(sptr, CMD_SETTIME, cptr, 1, "%s %C", 2, parc, - parv) != HUNTED_ISME) - return 0; - } - - if (feature_bool(FEAT_RELIABLE_CLOCK)) { - if ((dt > 600) || (dt < -600)) - sendcmdto_serv_butone(&me, CMD_WALLOPS, 0, ":Bad SETTIME from %s: %Tu", - cli_name(sptr), t); - if (IsUser(sptr)) { - sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is not set %ld " - "seconds %s : RELIABLE_CLOCK is defined", sptr, - (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards"); - } - } else { sendto_opmask_butone(0, SNO_OLDSNO, "SETTIME from %s, clock is set %ld " "seconds %s", cli_name(sptr), (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards"); TSoffset -= dt; - if (IsUser(sptr)) { + if (IsUser(sptr)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :clock is set %ld seconds %s", sptr, (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards"); - } } return 0; diff --git a/ircd/m_squit.c b/ircd/m_squit.c index b71d28e..8611b21 100644 --- a/ircd/m_squit.c +++ b/ircd/m_squit.c @@ -60,7 +60,7 @@ int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char* server = parv[1]; struct Client *acptr; - time_t timestamp; + time_t timestamp = 0; char *comment = 0; if (parc < 2) @@ -84,19 +84,22 @@ int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } /* If they are squitting me, we reverse it */ - if (IsMe(acptr)) { + if (IsMe(acptr)) acptr = cptr; /* Bugfix by Prefect */ - } - - timestamp = atoi(parv[2]); + + if (parc > 2) + timestamp = atoi(parv[2]); + else + protocol_violation(cptr, "SQUIT with no timestamp/reason"); /* If atoi(parv[2]) == 0 we must indeed squit ! * It will be our neighbour. */ - if ( timestamp != 0 && timestamp != cli_serv(acptr)->timestamp) { + if ( timestamp != 0 && timestamp != cli_serv(acptr)->timestamp) + { protocol_violation(sptr, "Issued SQUIT for %C with wrong timestamp %Tu " - "(%Tu) (ignored)", acptr, timestamp, - cli_serv(acptr)->timestamp); + "(%Tu) (ignored)", acptr, timestamp, + cli_serv(acptr)->timestamp); Debug((DEBUG_NOTICE, "Ignoring SQUIT with the wrong timestamp")); return 0; } diff --git a/ircd/m_stats.c b/ircd/m_stats.c index 8bb8e67..aeb9995 100644 --- a/ircd/m_stats.c +++ b/ircd/m_stats.c @@ -81,955 +81,79 @@ */ #include "config.h" -#include "handlers.h" -/* - * XXX - ack!!! - */ -#include "s_stats.h" -#include "channel.h" -#include "class.h" #include "client.h" -#include "gline.h" -#include "hash.h" #include "ircd.h" -#include "ircd_alloc.h" -#include "ircd_chattr.h" -#include "ircd_events.h" #include "ircd_features.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_string.h" -#include "list.h" -#include "listener.h" -#include "match.h" -#include "motd.h" #include "msg.h" #include "numeric.h" -#include "numnicks.h" -#include "opercmds.h" -#include "s_bsd.h" -#include "s_conf.h" -#include "s_debug.h" -#include "s_misc.h" -#include "s_serv.h" +#include "s_stats.h" #include "s_user.h" #include "send.h" #include "struct.h" -#include "userload.h" #include #include #include - -int report_klines(struct Client* sptr, char* mask, int limit_query) -{ - int wilds = 0; - int count = 3; - char* user = 0; - char* host; - const struct DenyConf* conf; - - if (EmptyString(mask)) { - if (limit_query) - return need_more_params(sptr, "STATS K"); - else - report_deny_list(sptr); - return 1; - } - - if (!limit_query) { - wilds = string_has_wildcards(mask); - count = 1000; - } - - if ((host = strchr(mask, '@'))) { - user = mask; - *host++ = '\0'; - } - else { - host = mask; - } - - for (conf = conf_get_deny_list(); conf; conf = conf->next) { - if ((!wilds && ((user || conf->hostmask) && - !match(conf->hostmask, host) && - (!user || !match(conf->usermask, user)))) || - (wilds && !mmatch(host, conf->hostmask) && - (!user || !mmatch(user, conf->usermask)))) - { - send_reply(sptr, RPL_STATSKLINE, - (conf->flags & DENY_FLAGS_IP) ? 'k' : 'K', - conf->hostmask, conf->message, conf->usermask); - if (--count == 0) - return 1; - } - } - /* send_reply(sptr, RPL_ENDOFSTATS, stat); */ - return 1; -} - -static int report_servers_verbose(struct Client *sptr, char stat) -{ - struct Client *acptr; - - /* lowercase 'v' is for human-readable, - * uppercase 'V' is for machine-readable */ - if (stat == 'v') - send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, - "%-20s %-20s Burst Hops Numeric Lag Clients/Max Proto " - "%-10s :Info", "Servername", "Uplink", "LinkTS"); - - for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) - { - if (!IsServer(acptr) && !IsMe(acptr)) - continue; - send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ? - "%-20s %-20s %c%c %4i %s %-4i %5i %5i %5i P%-2i %Tu :%s" : - "%s %s %c%c %i %s %i %i %i %i P%i %Tu :%s", - cli_name(acptr), - cli_name(cli_serv(acptr)->up), - IsBurst(acptr) ? 'B' : '-', - IsBurstAck(acptr) ? 'A' : '-', - cli_hopcount(acptr), - NumServ(acptr), - base64toint(cli_yxx(acptr)), - cli_serv(acptr)->lag, - cli_serv(acptr)->clients, - cli_serv(acptr)->nn_mask, - cli_serv(acptr)->prot, - cli_serv(acptr)->timestamp, - cli_info(acptr)); - } - - return 0; -} - - /* * m_stats - generic message handler * * parv[0] = sender prefix - * parv[1] = statistics selector (defaults to Message frequency) + * parv[1] = statistics selector * parv[2] = target server (current server defaulted, if omitted) * And 'stats l' and 'stats' L: - * parv[3] = server mask ("*" defaulted, if omitted) + * parv[3] = server mask ("*" default, if omitted) * Or for stats p,P: * parv[3] = port mask (returns p-lines when its port is matched by this) * Or for stats k,K,i and I: - * parv[3] = [user@]host.name (returns which K/I-lines match this) - * or [user@]host.mask (returns which K/I-lines are mmatched by this) - * (defaults to old reply if ommitted, when local or Oper) + * parv[3] = [user@]host.name (returns which K/I-lines match this) + * or [user@]host.mask (returns which K/I-lines are mmatched by this) + * (defaults to old reply if omitted, when local or Oper) * A remote mask (something containing wildcards) is only * allowed for IRC Operators. - * Or for stats M: - * parv[3] = time param - * parv[4] = time param - * (see report_memleak_stats() in runmalloc.c for details) - * - * This function is getting really ugly. -Ghostwolf */ -int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +int +m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { - char stat = parc > 1 ? parv[1][0] : '\0'; - const char **infotext = statsinfo; - - if (hunt_stats(cptr, sptr, parc, parv, stat, HEAD_IN_SAND_REMOTE) - != HUNTED_ISME) - return 0; - - switch (stat) - { - case 'L': - case 'l': -#ifdef HEAD_IN_SAND_STATS_L - return m_not_oper(sptr,cptr,parc,parv); -#else - { - struct Client *acptr; - int i; - int doall = 0; - int wilds = 0; - char *name = "*"; - - if (parc > 3 && !EmptyString(parv[3])) { - name = parv[3]; - wilds = string_has_wildcards(name); - } - else - doall = 1; - /* - * Send info about connections which match, or all if the - * mask matches me.name. Only restrictions are on those who - * are invisible not being visible to 'foreigners' who use - * a wild card based search to list it. - */ - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ " - "SendM SendKBytes RcveM RcveKBytes :Open since"); - for (i = 0; i <= HighestFd; i++) - { - if (!(acptr = LocalClientArray[i])) - continue; - /* Don't return clients when this is a request for `all' */ - if (doall && IsUser(acptr)) - continue; - /* Don't show invisible people to non opers unless they know the nick */ - if (IsInvisible(acptr) && (doall || wilds) && !IsAnOper(acptr) && (acptr != sptr)) - continue; - /* Only show the ones that match the given mask - if any */ - if (!doall && wilds && match(name, cli_name(acptr))) - continue; - /* Skip all that do not match the specific query */ - if (!(doall || wilds) && 0 != ircd_strcmp(name, cli_name(acptr))) - continue; - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, - "%s %u %u %u %u %u :%Tu", (*(cli_name(acptr))) ? cli_name(acptr) : "", - (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr), - (int)cli_sendK(acptr), (int)cli_receiveM(acptr), - (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr)); - } - } -#endif - break; - - case 'C': - case 'c': -#ifdef HEAD_IN_SAND_STATS_C - return m_not_oper(sptr,cptr,parc,parv); -#else - report_configured_links(sptr, CONF_SERVER); -#endif - break; - - case 'E': - case 'e': /* report engine name */ -#ifdef HEAD_IN_SAND_STATS_E - return m_not_oper(sptr,cptr,parc,parv); -#else - send_reply(sptr, RPL_STATSENGINE, engine_name()); -#endif - break; - - case 'G': - case 'g': /* send glines */ -#ifdef HEAD_IN_SAND_STATS_G - return m_not_oper(sptr,cptr,parc,parv); -#else - gline_stats(sptr); -#endif - break; - - case 'H': - case 'h': -#ifdef HEAD_IN_SAND_STATS_H - return m_not_oper(sptr,cptr,parc,parv); -#else - report_configured_links(sptr, CONF_HUB | CONF_LEAF); -#endif - break; - - case 'K': - case 'k': /* display CONF_IPKILL as well as CONF_KILL -Kev */ -#ifdef HEAD_IN_SAND_STATS_K - /* Simple version - if you want to fix it - send in a patch */ - return m_not_oper(sptr,cptr,parc,parv); -#else - if (0 == report_klines(sptr, (parc == 4) ? parv[3] : 0, 0)) - return 0; -#endif - break; - case 'F': - case 'f': -#ifdef HEAD_IN_SAND_STATS_F - return m_not_oper(sptr,cptr,parc,parv); -#else - feature_report(sptr); -#endif - break; - - case 'I': - case 'i': -#ifdef HEAD_IN_SAND_STATS_I - /* Simple version - if you want to fix it - send in a patch */ - return m_not_oper(sptr,cptr,parc,parv); -#else - { - struct ConfItem *aconf; - int wilds = 0; - int count = 1000; - char* host; - - if (parc < 4) { - report_configured_links(sptr, CONF_CLIENT); - break; - } - if (EmptyString(parv[3])) - return need_more_params(sptr, "STATS I"); - - host = parv[3]; - wilds = string_has_wildcards(host); - - for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (CONF_CLIENT == aconf->status) { - if ((!wilds && (!match(aconf->host, host) || - !match(aconf->name, host))) || - (wilds && (!mmatch(host, aconf->host) || - !mmatch(host, aconf->name)))) - { - if (aconf->passwd && IsDigit(*aconf->passwd) && - (!aconf->passwd[1] || - (IsDigit(aconf->passwd[1]) && !aconf->passwd[2]))) - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->passwd, - aconf->name, aconf->port, get_conf_class(aconf)); - else - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, "*", - aconf->name, aconf->port, get_conf_class(aconf)); - - if (--count == 0) - break; - } - } - } - } -#endif - break; - - case 'M': -#ifdef HEAD_IN_SAND_STATS_M - return m_not_oper(sptr,cptr,parc,parv); -#else -#if defined(MDEBUG) - send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(), - fda_get_block_count()); -#endif -#endif - break; - - case 'm': -#ifdef HEAD_IN_SAND_STATS_m - return m_not_oper(sptr,cptr,parc,parv); -#else - { - struct Message *mptr; - - for (mptr = msgtab; mptr->cmd; mptr++) - if (mptr->count) - send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, - mptr->bytes); - } -#endif - break; - - case 'o': - case 'O': -#ifdef HEAD_IN_SAND_STATS_O - return m_not_oper(sptr,cptr,parc,parv); -#else - report_configured_links(sptr, CONF_OPS); -#endif - break; - - case 'p': - case 'P': - /* - * show listener ports - * show hidden ports to opers, if there are more than 3 parameters, - * interpret the fourth parameter as the port number. - */ -#ifdef HEAD_IN_SAND_STATS_P - return m_not_oper(sptr,cptr,parc,parv); -#else - show_ports(sptr, 0, (parc > 3) ? atoi(parv[3]) : 0, 100); -#endif - break; - - case 'R': - case 'r': -#ifdef HEAD_IN_SAND_STATS_R - return m_not_oper(sptr,cptr,parc,parv); -#else -#ifdef DEBUGMODE - send_usage(sptr, parv[0]); -#endif -#endif - break; - - case 'D': -#ifdef HEAD_IN_SAND_STATS_D - return m_not_oper(sptr,cptr,parc,parv); -#else - report_crule_list(sptr, CRULE_ALL); -#endif - break; - - case 'd': -#ifdef HEAD_IN_SAND_STATS_d - return m_not_oper(sptr,cptr,parc,parv); -#else - report_crule_list(sptr, CRULE_MASK); -#endif - break; - - case 't': -#ifdef HEAD_IN_SAND_STATS_t - return m_not_oper(sptr,cptr,parc,parv); -#else - tstats(sptr, parv[0]); -#endif - break; - - case 'T': -#ifdef HEAD_IN_SAND_STATS_T - return m_not_oper(sptr,cptr,parc,parv); -#else - motd_report(sptr); -#endif - break; - - case 'U': -#ifdef HEAD_IN_SAND_STATS_U - return m_not_oper(sptr,cptr,parc,parv); -#else - report_configured_links(sptr, CONF_UWORLD); -#endif - break; - - case 'u': -#ifdef HEAD_IN_SAND_STATS_u - return m_not_oper(sptr,cptr,parc,parv); -#else - { - time_t nowr; - - nowr = CurrentTime - cli_since(&me); - send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24, - (nowr / 60) % 60, nowr % 60); - send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count); - } -#endif - break; - - case 'W': - case 'w': -#ifdef HEAD_IN_SAND_STATS_W - return m_not_oper(sptr,cptr,parc,parv); -#else - calc_load(sptr); -#endif - break; - - case 'X': - case 'x': -#ifdef HEAD_IN_SAND_STATS_X - return m_not_oper(sptr,cptr,parc,parv); -#else -#ifdef DEBUGMODE - class_send_meminfo(sptr); - send_listinfo(sptr, parv[0]); -#endif -#endif - break; - - case 'Y': - case 'y': -#ifdef HEAD_IN_SAND_STATS_Y - return m_not_oper(sptr,cptr,parc,parv); -#else - report_classes(sptr); -#endif - break; - - case 'Z': - case 'z': -#ifdef HEAD_IN_SAND_STATS_Z - return m_not_oper(sptr,cptr,parc,parv); -#else - count_memory(sptr, parv[0]); -#endif - break; - - default: - stat = '*'; - while (*infotext) - sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, *infotext++); - break; + unsigned char stat = parc > 1 ? parv[1][0] : '\0'; + struct StatDesc *sd; + char *param = 0; + + /* If we didn't find a descriptor and this is my client, send them help */ + if (!(sd = statsmap[(int)stat])) { + stat = '*'; + sd = statsmap[(int)stat]; } - send_reply(sptr, RPL_ENDOFSTATS, stat); - return 0; -} -/* - * ms_stats - server message handler - * - * parv[0] = sender prefix - * parv[1] = statistics selector (defaults to Message frequency) - * parv[2] = target server (current server defaulted, if omitted) - * And 'stats l' and 'stats' L: - * parv[3] = server mask ("*" defaulted, if omitted) - * Or for stats p,P: - * parv[3] = port mask (returns p-lines when its port is matched by this) - * Or for stats k,K,i and I: - * parv[3] = [user@]host.name (returns which K/I-lines match this) - * or [user@]host.mask (returns which K/I-lines are mmatched by this) - * (defaults to old reply if ommitted, when local or Oper) - * A remote mask (something containing wildcards) is only - * allowed for IRC Operators. - * Or for stats M: - * parv[3] = time param - * parv[4] = time param - * (see report_memleak_stats() in runmalloc.c for details) - * - * This function is getting really ugly. -Ghostwolf - */ -int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) -{ - struct Message *mptr; - struct Client *acptr; - struct ConfItem *aconf; - char stat = parc > 1 ? parv[1][0] : '\0'; - int i; - - if (hunt_stats(cptr, sptr, parc, parv, stat, 0) != HUNTED_ISME) - return 0; - - switch (stat) - { - case 'L': - case 'l': - { - int doall = 0; - int wilds = 0; - char *name = "*"; + assert(sd != 0); - if (parc > 3 && !EmptyString(parv[3])) { - name = parv[3]; - wilds = string_has_wildcards(name); - } - else - doall = 1; - /* - * Send info about connections which match, or all if the - * mask matches me.name. Only restrictions are on those who - * are invisible not being visible to 'foreigners' who use - * a wild card based search to list it. - */ - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ " - "SendM SendKBytes RcveM RcveKBytes :Open since"); - for (i = 0; i <= HighestFd; i++) - { - if (!(acptr = LocalClientArray[i])) - continue; - /* Don't return clients when this is a request for `all' */ - if (doall && IsUser(acptr)) - continue; - /* Don't show invisible people to unauthorized people when using - * wildcards -- Is this still needed now /stats is oper only ? - * Not here, because ms_stats is specifically a remote command, - * thus the check was removed. -Ghostwolf */ - /* Only show the ones that match the given mask - if any */ - if (!doall && wilds && match(name, cli_name(acptr))) - continue; - /* Skip all that do not match the specific query */ - if (!(doall || wilds) && 0 != ircd_strcmp(name, cli_name(acptr))) - continue; - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, - "%s %u %u %u %u %u :%Tu", cli_name(acptr), - (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr), - (int)cli_sendK(acptr), (int)cli_receiveM(acptr), - (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr)); - } - break; - } - case 'C': - case 'c': - report_configured_links(sptr, CONF_SERVER); - break; - case 'E': - case 'e': /* report engine name */ - send_reply(sptr, RPL_STATSENGINE, engine_name()); - break; - case 'G': - case 'g': /* send glines */ - gline_stats(sptr); - break; - case 'H': - case 'h': - report_configured_links(sptr, CONF_HUB | CONF_LEAF); - break; - case 'K': - case 'k': /* display CONF_IPKILL as well as CONF_KILL -Kev */ - if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, !IsOper(sptr))) - return 0; - break; - case 'F': - case 'f': - feature_report(sptr); - break; - case 'I': - case 'i': - { - int wilds = 0; - int count = 3; - char* host; + /* Check whether the client can issue this command. If source is + * not privileged (server or an operator), then the STAT_FLAG_OPERONLY + * flag must not be set, and if the STAT_FLAG_OPERFEAT flag is set, + * then the feature given by sd->sd_control must be off. + */ + if (!IsPrivileged(cptr) && + ((sd->sd_flags & STAT_FLAG_OPERONLY) || + ((sd->sd_flags & STAT_FLAG_OPERFEAT) && feature_bool(sd->sd_control)))) + return send_reply(cptr, ERR_NOPRIVILEGES); - if (parc < 4 && IsOper(sptr)) { - report_configured_links(sptr, CONF_CLIENT); - break; - } - if (parc < 4 || EmptyString(parv[3])) - return need_more_params(sptr, "STATS I"); + /* Check for extra parameter */ + if ((sd->sd_flags & STAT_FLAG_VARPARAM) && parc > 3 && !EmptyString(parv[3])) + param = parv[3]; - if (IsOper(sptr)) { - wilds = string_has_wildcards(parv[3]); - count = 1000; - } + /* Ok, track down who's supposed to get this... */ + if (hunt_server_cmd(sptr, CMD_STATS, cptr, feature_int(FEAT_HIS_REMOTE), + param ? "%s %C :%s" : "%s :%C", 2, parc, parv) != + HUNTED_ISME) + return 0; /* Someone else--cool :) */ - host = parv[3]; + assert(sd->sd_func != 0); - for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (CONF_CLIENT == aconf->status) { - if ((!wilds && (!match(aconf->host, host) || - !match(aconf->name, host))) || - (wilds && (!mmatch(host, aconf->host) || - !mmatch(host, aconf->name)))) - { - if (aconf->passwd && IsDigit(*aconf->passwd) && - (!aconf->passwd[1] || - (IsDigit(aconf->passwd[1]) && !aconf->passwd[2]))) - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, - aconf->passwd, aconf->name, aconf->port, - get_conf_class(aconf)); - else - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, "*", - aconf->name, aconf->port, get_conf_class(aconf)); + /* Ok, dispatch the stats function */ + (*sd->sd_func)(sptr, sd, stat, param); - if (--count == 0) - break; - } - } - } - break; - } - case 'M': -#if defined(MDEBUG) - send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(), - fda_get_block_count()); -#endif - break; - case 'm': - for (mptr = msgtab; mptr->cmd; mptr++) - if (mptr->count) - send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, - mptr->bytes); - break; - case 'o': - case 'O': - report_configured_links(sptr, CONF_OPS); - break; - case 'p': - case 'P': - /* - * show listener ports - * show hidden ports to opers, if there are more than 3 parameters, - * interpret the fourth parameter as the port number, limit non-local - * or non-oper results to 8 ports. - */ - show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, IsOper(sptr) ? 100 : 8); - break; - case 'R': - case 'r': -#ifdef DEBUGMODE - send_usage(sptr, parv[0]); -#endif - break; - case 'D': - report_crule_list(sptr, CRULE_ALL); - break; - case 'd': - report_crule_list(sptr, CRULE_MASK); - break; - case 't': - tstats(sptr, parv[0]); - break; - case 'T': - motd_report(sptr); - break; - case 'U': - report_configured_links(sptr, CONF_UWORLD); - break; - case 'u': - { - time_t nowr; - - nowr = CurrentTime - cli_since(&me); - send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24, - (nowr / 60) % 60, nowr % 60); - send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count); - break; - } - case 'V': - case 'v': - report_servers_verbose(sptr, stat); - break; - case 'W': - case 'w': - calc_load(sptr); - break; - case 'X': - case 'x': -#ifdef DEBUGMODE - class_send_meminfo(sptr); - send_listinfo(sptr, parv[0]); -#endif - break; - case 'Y': - case 'y': - report_classes(sptr); - break; - case 'Z': - case 'z': - count_memory(sptr, parv[0]); - break; - default: - stat = '*'; - break; - } - send_reply(sptr, RPL_ENDOFSTATS, stat); - return 0; + /* Done sending them the stats */ + return send_reply(sptr, RPL_ENDOFSTATS, stat); } - -/* - * mo_stats - oper message handler - * - * parv[0] = sender prefix - * parv[1] = statistics selector (defaults to Message frequency) - * parv[2] = target server (current server defaulted, if omitted) - * And 'stats l' and 'stats' L: - * parv[3] = server mask ("*" defaulted, if omitted) - * Or for stats p,P: - * parv[3] = port mask (returns p-lines when its port is matched by this) - * Or for stats k,K,i and I: - * parv[3] = [user@]host.name (returns which K/I-lines match this) - * or [user@]host.mask (returns which K/I-lines are mmatched by this) - * (defaults to old reply if ommitted, when local or Oper) - * A remote mask (something containing wildcards) is only - * allowed for IRC Operators. - * Or for stats M: - * parv[3] = time param - * parv[4] = time param - * (see report_memleak_stats() in runmalloc.c for details) - * - * This function is getting really ugly. -Ghostwolf - */ -int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) -{ - struct Message* mptr; - struct Client* acptr; - struct ConfItem* aconf; - char stat = parc > 1 ? parv[1][0] : '\0'; - const char** infotext = statsinfo; - int i; - - if (hunt_stats(cptr, sptr, parc, parv, stat, HEAD_IN_SAND_REMOTE) - != HUNTED_ISME) - return 0; - - switch (stat) - { - case 'L': - case 'l': - { - int doall = 0, wilds = 0; - char* name = "*"; - if (parc > 3 && !EmptyString(parv[3])) { - name = parv[3]; - wilds = string_has_wildcards(name); - } - else - doall = 1; - /* - * Send info about connections which match, or all if the - * mask matches me.name. Only restrictions are on those who - * are invisible not being visible to 'foreigners' who use - * a wild card based search to list it. - */ - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ " - "SendM SendKBytes RcveM RcveKBytes :Open since"); - for (i = 0; i <= HighestFd; i++) - { - if (!(acptr = LocalClientArray[i])) - continue; - /* Don't return clients when this is a request for `all' */ - if (doall && IsUser(acptr)) - continue; - /* Only show the ones that match the given mask - if any */ - if (!doall && wilds && match(name, cli_name(acptr))) - continue; - /* Skip all that do not match the specific query */ - if (!(doall || wilds) && 0 != ircd_strcmp(name, cli_name(acptr))) - continue; - send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, - "%s %u %u %u %u %u :%Tu", cli_name(acptr), - (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr), - (int)cli_sendK(acptr), (int)cli_receiveM(acptr), - (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr)); - } - break; - } - case 'C': - case 'c': - report_configured_links(sptr, CONF_SERVER); - break; - case 'E': - case 'e': /* report engine name */ - send_reply(sptr, RPL_STATSENGINE, engine_name()); - break; - case 'G': - case 'g': /* send glines */ - gline_stats(sptr); - break; - case 'H': - case 'h': - report_configured_links(sptr, CONF_HUB | CONF_LEAF); - break; - case 'K': - case 'k': /* display CONF_IPKILL as well as CONF_KILL -Kev */ - if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, 0)) - return 0; - break; - case 'F': - case 'f': - feature_report(sptr); - break; - case 'I': - case 'i': - { - int wilds = 0; - int count = 1000; - char* host; - - if (parc < 4) { - report_configured_links(sptr, CONF_CLIENT); - break; - } - if (EmptyString(parv[3])) - return need_more_params(sptr, "STATS I"); - - host = parv[3]; - wilds = string_has_wildcards(host); - - for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (CONF_CLIENT == aconf->status) { - if ((!wilds && (!match(aconf->host, host) || - !match(aconf->name, host))) || - (wilds && (!mmatch(host, aconf->host) || - !mmatch(host, aconf->name)))) - { - if (aconf->passwd && IsDigit(*aconf->passwd) && - (!aconf->passwd[1] || - (IsDigit(aconf->passwd[1]) && !aconf->passwd[2]))) - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, - aconf->passwd, aconf->name, aconf->port, - get_conf_class(aconf)); - else - send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, "*", - aconf->name, aconf->port, get_conf_class(aconf)); - - if (--count == 0) - break; - } - } - } - } - break; - case 'M': -#if defined(MDEBUG) - send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(), - fda_get_block_count()); -#endif - break; - case 'm': - for (mptr = msgtab; mptr->cmd; mptr++) - if (mptr->count) - send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, - mptr->bytes); - break; - case 'o': - case 'O': - report_configured_links(sptr, CONF_OPS); - break; - case 'p': - case 'P': - /* - * show listener ports - * show hidden ports to opers, if there are more than 3 parameters, - * interpret the fourth parameter as the port number, limit non-local - * or non-oper results to 8 ports. - */ - show_ports(sptr, 1, (parc > 3) ? atoi(parv[3]) : 0, 100); - break; - case 'R': - case 'r': -#ifdef DEBUGMODE - send_usage(sptr, parv[0]); -#endif - break; - case 'D': - report_crule_list(sptr, CRULE_ALL); - break; - case 'd': - report_crule_list(sptr, CRULE_MASK); - break; - case 't': - tstats(sptr, parv[0]); - break; - case 'T': - motd_report(sptr); - break; - case 'U': - report_configured_links(sptr, CONF_UWORLD); - break; - case 'u': - { - time_t nowr; - - nowr = CurrentTime - cli_since(&me); - send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24, - (nowr / 60) % 60, nowr % 60); - send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count); - break; - } - case 'V': - case 'v': - report_servers_verbose(sptr, stat); - break; - case 'W': - case 'w': - calc_load(sptr); - break; - case 'X': - case 'x': -#ifdef DEBUGMODE - class_send_meminfo(sptr); - send_listinfo(sptr, parv[0]); -#endif - break; - case 'Y': - case 'y': - report_classes(sptr); - break; - case 'Z': - case 'z': - count_memory(sptr, parv[0]); - break; - - default: - stat = '*'; - while (*infotext) - sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, *infotext++); - break; - } - send_reply(sptr, RPL_ENDOFSTATS, stat); - return 0; -} - diff --git a/ircd/m_time.c b/ircd/m_time.c index 5d145c9..d216465 100644 --- a/ircd/m_time.c +++ b/ircd/m_time.c @@ -83,7 +83,7 @@ #include "client.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "msg.h" @@ -103,8 +103,9 @@ */ int m_time(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { - if (hunt_server_cmd(sptr, CMD_TIME, cptr, HEAD_IN_SAND_REMOTE, ":%C", 1, - parc, parv) != HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_TIME, cptr, feature_int(FEAT_HIS_REMOTE), ":%C", + 1, parc, parv) + != HUNTED_ISME) return 0; send_reply(sptr, RPL_TIME, cli_name(&me), TStime(), TSoffset, date((long)0)); diff --git a/ircd/m_topic.c b/ircd/m_topic.c index b8cfc82..a41745c 100644 --- a/ircd/m_topic.c +++ b/ircd/m_topic.c @@ -161,14 +161,9 @@ int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) send_reply(sptr, ERR_NOTONCHANNEL, chptr->chname); continue; } - /* Modeless Channels don't have topics */ - if (IsModelessChannel(name)) - { - send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); - continue; - } - if (!topic) /* only asking for topic */ + /* only asking for topic */ + if (!topic) { if (chptr->topic[0] == '\0') send_reply(sptr, RPL_NOTOPIC, chptr->chname); @@ -211,13 +206,6 @@ int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) send_reply(sptr,ERR_NOSUCHCHANNEL,name); continue; } - /* Modeless Channels don't have topics */ - if (IsModelessChannel(name)) - { - protocol_violation(sptr,"Attempted to topic modeless channel"); - send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname); - continue; - } /* Ignore requests for topics from remote servers */ if (IsLocalChannel(name) && !MyUser(sptr)) diff --git a/ircd/m_trace.c b/ircd/m_trace.c index 4fa9d8a..34547ee 100644 --- a/ircd/m_trace.c +++ b/ircd/m_trace.c @@ -85,6 +85,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -120,18 +121,25 @@ int m_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) int wilds; int dow; - if (parc < 2 || BadPtr(parv[1])) { + if (feature_bool(FEAT_HIS_TRACE)) + return send_reply(cptr, ERR_NOPRIVILEGES); + + if (parc < 2 || BadPtr(parv[1])) + { /* just "TRACE" without parameters. Must be from local client */ parc = 1; acptr = &me; tname = cli_name(&me); i = HUNTED_ISME; - } else if (parc < 3 || BadPtr(parv[2])) { + } + else if (parc < 3 || BadPtr(parv[2])) + { /* No target specified. Make one before propagating. */ parc = 2; tname = parv[1]; if ((acptr = find_match_server(parv[1])) || - ((acptr = FindClient(parv[1])) && !MyUser(acptr))) { + ((acptr = FindClient(parv[1])) && !MyUser(acptr))) + { if (IsUser(acptr)) parv[2] = cli_name(cli_user(acptr)->server); else @@ -141,7 +149,8 @@ int m_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, IsServer(acptr), "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH) return 0; - } else + } + else i = HUNTED_ISME; } else { /* Got "TRACE :" */ diff --git a/ircd/m_version.c b/ircd/m_version.c index 31dd236..a4d9c55 100644 --- a/ircd/m_version.c +++ b/ircd/m_version.c @@ -85,7 +85,6 @@ #include "hash.h" #include "ircd.h" #include "ircd_features.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -104,17 +103,19 @@ * m_version - generic message handler * * parv[0] = sender prefix - * parv[1] = remote server + * parv[1] = servername */ int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { - - if (parc > 1) + struct Client *acptr; + if (parc > 1 && (!(acptr = find_match_server(parv[1])) || !IsMe(acptr))) send_reply(sptr, ERR_NOPRIVILEGES); else + { send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), - debug_serveropts()); - + debug_serveropts()); + send_supported(sptr); + } return 0; } @@ -122,7 +123,7 @@ int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) * mo_version - generic message handler * * parv[0] = sender prefix - * parv[1] = remote server + * parv[1] = servername */ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { @@ -138,8 +139,10 @@ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) parv[1] = cli_name(acptr); } - if (hunt_server_cmd(sptr, CMD_VERSION, cptr, HEAD_IN_SAND_REMOTE, ":%C", 1, - parc, parv) == HUNTED_ISME) + if (hunt_server_cmd(sptr, CMD_VERSION, cptr, feature_int(FEAT_HIS_REMOTE), + ":%C", 1, + parc, parv) + == HUNTED_ISME) { send_reply(sptr, RPL_VERSION, version, debugmode, cli_name(&me), debug_serveropts()); @@ -153,7 +156,7 @@ int mo_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) * ms_version - server message handler * * parv[0] = sender prefix - * parv[1] = remote server + * parv[1] = servername */ int ms_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { diff --git a/ircd/m_wallchops.c b/ircd/m_wallchops.c index 9ff5a09..f05769b 100644 --- a/ircd/m_wallchops.c +++ b/ircd/m_wallchops.c @@ -105,7 +105,7 @@ int m_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[] assert(0 != cptr); assert(cptr == sptr); - cli_flags(sptr) &= ~FLAGS_TS8; + ClrFlag(sptr, FLAG_TS8); if (parc < 2 || EmptyString(parv[1])) return send_reply(sptr, ERR_NORECIPIENT, "WALLCHOPS"); @@ -120,7 +120,7 @@ int m_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[] return 0; sendcmdto_channel_butone(sptr, CMD_WALLCHOPS, chptr, cptr, SKIP_DEAF | SKIP_BURST | SKIP_NONOPS, - "%H :%s", chptr, parv[parc - 1]); + "%H :@ %s", chptr, parv[parc - 1]); } else send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]); diff --git a/ircd/m_wallvoices.c b/ircd/m_wallvoices.c new file mode 100644 index 0000000..4aa3d86 --- /dev/null +++ b/ircd/m_wallvoices.c @@ -0,0 +1,154 @@ +/* + * IRC - Internet Relay Chat, ircd/m_wallvoices.c + * Copyright (c) 2002 hikari + * + * See file AUTHORS in IRC package for additional names of + * the programmers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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$ + */ + +/* + * m_functions execute protocol messages on this server: + * + * cptr is always NON-NULL, pointing to a *LOCAL* client + * structure (with an open socket connected!). This + * identifies the physical socket where the message + * originated (or which caused the m_function to be + * executed--some m_functions may call others...). + * + * sptr is the source of the message, defined by the + * prefix part of the message if present. If not + * or prefix not found, then sptr==cptr. + * + * (!IsServer(cptr)) => (cptr == sptr), because + * prefixes are taken *only* from servers... + * + * (IsServer(cptr)) + * (sptr == cptr) => the message didn't + * have the prefix. + * + * (sptr != cptr && IsServer(sptr) means + * the prefix specified servername. (?) + * + * (sptr != cptr && !IsServer(sptr) means + * that message originated from a remote + * user (not local). + * + * combining + * + * (!IsServer(sptr)) means that, sptr can safely + * taken as defining the target structure of the + * message in this server. + * + * *Always* true (if 'parse' and others are working correct): + * + * 1) sptr->from == cptr (note: cptr->from == cptr) + * + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr + * *cannot* be a local connection, unless it's + * actually cptr!). [MyConnect(x) should probably + * be defined as (x == x->from) --msa ] + * + * parc number of variable parameter strings (if zero, + * parv is allowed to be NULL) + * + * parv a NULL terminated list of parameter pointers, + * + * parv[0], sender (prefix string), if not present + * this points to an empty string. + * parv[1]...parv[parc-1] + * pointers to additional parameters + * parv[parc] == NULL, *always* + * + * note: it is guaranteed that parv[0]..parv[parc-1] are all + * non-NULL pointers. + */ +#include "config.h" + +#include "channel.h" +#include "client.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_reply.h" +#include "ircd_string.h" +#include "msg.h" +#include "numeric.h" +#include "numnicks.h" +#include "s_user.h" +#include "send.h" + +#include + +/* + * m_wallvoices - local generic message handler + */ +int m_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + struct Channel *chptr; + + assert(0 != cptr); + assert(cptr == sptr); + + ClrFlag(sptr, FLAG_TS8); + + if (parc < 2 || EmptyString(parv[1])) + return send_reply(sptr, ERR_NORECIPIENT, "WALLVOICES"); + + if (parc < 3 || EmptyString(parv[parc - 1])) + return send_reply(sptr, ERR_NOTEXTTOSEND); + + if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) { + if (client_can_send_to_channel(sptr, chptr)) { + if ((chptr->mode.mode & MODE_NOPRIVMSGS) && + check_target_limit(sptr, chptr, chptr->chname, 0)) + return 0; + sendcmdto_channel_butone(sptr, CMD_WALLVOICES, chptr, cptr, + SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES, + "%H :+ %s", chptr, parv[parc - 1]); + } + else + send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]); + } + else + send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); + + return 0; +} + +/* + * ms_wallvoices - server message handler + */ +int ms_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) +{ + struct Channel *chptr; + assert(0 != cptr); + assert(0 != sptr); + + if (parc < 3 || !IsUser(sptr)) + return 0; + + if ((chptr = FindChannel(parv[1]))) { + if (client_can_send_to_channel(sptr, chptr)) { + sendcmdto_channel_butone(sptr, CMD_WALLVOICES, chptr, cptr, + SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES, + "%H :+ %s", chptr, parv[parc - 1]); + } else + send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]); + } + return 0; +} diff --git a/ircd/m_who.c b/ircd/m_who.c index cb8bf65..d66775b 100644 --- a/ircd/m_who.c +++ b/ircd/m_who.c @@ -86,8 +86,8 @@ #include "hash.h" #include "ircd.h" #include "ircd_chattr.h" +#include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -273,10 +273,8 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (!fields) counter = 7; -#ifdef HEAD_IN_SAND_WHO_SERVERNAME - if (!IsAnOper(sptr)) + if (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) matchsel &= ~WHO_FIELD_SER; -#endif if (qrt && (fields & WHO_FIELD_QTY)) { @@ -390,7 +388,7 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) - || (!(cli_flags(cli_user(acptr)->server) & FLAGS_MAP))) + || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP)))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) @@ -430,7 +428,7 @@ int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) && ((!(matchsel & WHO_FIELD_UID)) || matchexec(cli_user(acptr)->username, mymask, minlen)) && ((!(matchsel & WHO_FIELD_SER)) - || (!(cli_flags(cli_user(acptr)->server) & FLAGS_MAP))) + || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP)))) && ((!(matchsel & WHO_FIELD_HOS)) || matchexec(cli_user(acptr)->host, mymask, minlen)) && ((!(matchsel & WHO_FIELD_HOS)) diff --git a/ircd/m_whois.c b/ircd/m_whois.c index 0855164..71a2b77 100644 --- a/ircd/m_whois.c +++ b/ircd/m_whois.c @@ -85,7 +85,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "match.h" @@ -183,12 +183,11 @@ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) send_reply(sptr, RPL_WHOISCHANNELS, name, buf); } -#ifdef HEAD_IN_SAND_WHOIS_SERVERNAME - if (!IsAnOper(sptr) && sptr != acptr) - send_reply(sptr, RPL_WHOISSERVER, name, HEAD_IN_SAND_SERVERNAME, - HEAD_IN_SAND_SERVERINFO); + if (feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr) && + sptr != acptr) + send_reply(sptr, RPL_WHOISSERVER, name, feature_str(FEAT_HIS_SERVERNAME), + feature_str(FEAT_HIS_SERVERNAME)); else -#endif send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr), cli_info(a2cptr)); @@ -204,19 +203,16 @@ static void do_whois(struct Client* sptr, struct Client *acptr, int parc) if (IsAccount(acptr)) send_reply(sptr, RPL_WHOISACCOUNT, name, user->account); - if (HasHiddenHost(acptr) && IsAnOper(sptr)) + if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr)) send_reply(sptr, RPL_WHOISACTUALLY, name, user->username, - user->realhost, ircd_ntoa((const char*) &(cli_ip(acptr)))); - + user->realhost, ircd_ntoa((const char*) &(cli_ip(acptr)))); + /* Hint: if your looking to add more flags to a user, eg +h, here's * probably a good place to add them :) */ - if (MyConnect(acptr) -#ifdef HEAD_IN_SAND_WHOIS_IDLETIME - && (sptr == acptr || IsAnOper(sptr) || parc >= 3) -#endif - ) + if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) || + (sptr == acptr || IsAnOper(sptr) || parc >= 3))) send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last, cli_firsttime(acptr)); } @@ -361,21 +357,22 @@ int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) * it with the correct servername - as is needed by hunt_server(). * This is the secret behind the /whois nick nick trick. */ -#if HEAD_IN_SAND_REMOTE - /* If remote queries are disabled, then use the *second* parameter of - * of whois, so /whois nick nick still works. - */ - if (!IsAnOper(sptr)) + if (feature_int(FEAT_HIS_REMOTE)) { - if (!FindUser(parv[2])) + /* If remote queries are disabled, then use the *second* parameter of + * of whois, so /whois nick nick still works. + */ + if (!IsAnOper(sptr)) { - send_reply(sptr, ERR_NOSUCHNICK, parv[2]); - send_reply(sptr, RPL_ENDOFWHOIS, parv[2]); - return 0; + if (!FindUser(parv[2])) + { + send_reply(sptr, ERR_NOSUCHNICK, parv[2]); + send_reply(sptr, RPL_ENDOFWHOIS, parv[2]); + return 0; + } + parv[1] = parv[2]; } - parv[1] = parv[2]; } -#endif if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) != HUNTED_ISME) diff --git a/ircd/m_whowas.c b/ircd/m_whowas.c index adcaaea..f6a4cdf 100644 --- a/ircd/m_whowas.c +++ b/ircd/m_whowas.c @@ -84,7 +84,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_string.h" #include "msg.h" @@ -138,14 +138,11 @@ int m_whowas(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) send_reply(sptr, RPL_WHOWASUSER, temp->name, temp->username, (IsAnOper(sptr) && temp->realhost) ? temp->realhost : temp->hostname, temp->realname); -#ifdef HEAD_IN_SAND_WHOIS_SERVERNAME - if (!IsOper(sptr)) - send_reply(sptr, RPL_WHOISSERVER, temp->name, - HEAD_IN_SAND_SERVERNAME, myctime(temp->logoff)); - else -#endif - send_reply(sptr, RPL_WHOISSERVER, temp->name, temp->servername, - myctime(temp->logoff)); + send_reply(sptr, RPL_WHOISSERVER, temp->name, + (feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsOper(sptr)) ? + feature_str(FEAT_HIS_SERVERNAME) : + temp->servername, + myctime(temp->logoff)); if (temp->away) send_reply(sptr, RPL_AWAY, temp->name, temp->away); cur++; diff --git a/ircd/map.c b/ircd/map.c index 77119ff..0a67438 100644 --- a/ircd/map.c +++ b/ircd/map.c @@ -237,15 +237,15 @@ void map_dump(struct Client *cptr, struct Client *server, char *mask, int prompt strcpy(p, "|-"); for (lp = cli_serv(server)->down; lp; lp = lp->next) if (match(mask, cli_name(lp->value.cptr))) - cli_flags(lp->value.cptr) &= ~FLAGS_MAP; + ClrFlag(lp->value.cptr, FLAG_MAP); else { - cli_flags(lp->value.cptr) |= FLAGS_MAP; + SetFlag(lp->value.cptr, FLAG_MAP); cnt++; } for (lp = cli_serv(server)->down; lp; lp = lp->next) { - if ((cli_flags(lp->value.cptr) & FLAGS_MAP) == 0) + if (!HasFlag(lp->value.cptr, FLAG_MAP)) continue; if (--cnt == 0) *p = '`'; diff --git a/ircd/motd.c b/ircd/motd.c index 393d1ee..a2634b9 100644 --- a/ircd/motd.c +++ b/ircd/motd.c @@ -41,6 +41,7 @@ #include "s_conf.h" #include "s_debug.h" #include "s_user.h" +#include "s_stats.h" #include "send.h" #include @@ -63,6 +64,7 @@ motd_create(const char *hostmask, const char *path, int maxcount) { struct Motd* tmp; int type = MOTD_UNIVERSAL; + const char *s; assert(0 != path); @@ -371,7 +373,7 @@ motd_clear(void) /* This is called to report T-lines */ void -motd_report(struct Client *to) +motd_report(struct Client *to, struct StatDesc *sd, int stat, char *param) { struct Motd *ptr; @@ -379,3 +381,49 @@ motd_report(struct Client *to) send_reply(to, SND_EXPLICIT | RPL_STATSTLINE, "T %s %s", ptr->hostmask, ptr->path); } + +void +motd_memory_count(struct Client *cptr) +{ + struct Motd *ptr; + struct MotdCache *cache; + unsigned int mt = 0, /* motd count */ + mtm = 0, /* memory consumed by motd */ + mtc = 0, /* motd cache count */ + mtcm = 0, /* memory consumed by motd cache */ + mtf = 0; /* motd free list count */ + if (MotdList.local) + { + mt++; + mtm += sizeof(struct Motd); + mtm += MotdList.local->path ? (strlen(MotdList.local->path) + 1) : 0; + } + + if (MotdList.remote) + { + mt++; + mtm += sizeof(struct Motd); + mtm += MotdList.remote->path ? (strlen(MotdList.remote->path) + 1) : 0; + } + + for (ptr = MotdList.other; ptr; ptr = ptr->next) + { + mt++; + mtm += sizeof(struct Motd); + mtm += ptr->path ? (strlen(ptr->path) + 1) : 0; + } + + for (cache = MotdList.cachelist; cache; cache = cache->next) + { + mtc++; + mtcm += sizeof(struct MotdCache) + (MOTD_LINESIZE * (cache->count - 1)); + } + + if (MotdList.freelist) + for (ptr = MotdList.freelist; ptr; ptr = ptr->next) + mtf++; + + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":Motds %d(%zu) Cache %d(%zu) Free %d(%zu)", + mt, mtm, mtc, mtcm, mtf, (mtf * sizeof(struct Motd))); +} diff --git a/ircd/msgq.c b/ircd/msgq.c index e6ad9e4..043c859 100644 --- a/ircd/msgq.c +++ b/ircd/msgq.c @@ -21,38 +21,64 @@ #include "config.h" #include "msgq.h" +#include "ircd.h" #include "ircd_alloc.h" #include "ircd_defs.h" +#include "ircd_features.h" +#include "ircd_reply.h" #include "ircd_snprintf.h" +#include "numeric.h" +#include "send.h" #include "s_debug.h" +#include "s_stats.h" #include #include +#include #include #include /* struct iovec */ +#define MB_BASE_SHIFT 5 +#define MB_MAX_SHIFT 9 + struct MsgBuf { struct MsgBuf *next; /* next msg in global queue */ struct MsgBuf **prev_p; /* what points to us in linked list */ + struct MsgBuf *real; /* the actual MsgBuf we're attaching */ unsigned int ref; /* reference count */ unsigned int length; /* length of message */ - char msg[BUFSIZE + 1]; /* the message */ + unsigned int power; /* size of buffer (power of 2) */ + char msg[1]; /* the message */ }; +#define bufsize(buf) (1 << (buf)->power) + struct Msg { struct Msg *next; /* next msg */ unsigned int sent; /* bytes in msg that have already been sent */ struct MsgBuf *msg; /* actual message in queue */ }; -static struct { - struct MsgBuf *msgs; - struct MsgBuf *free_mbs; - struct Msg *free_msgs; -} MQData = { 0, 0, 0 }; +struct MsgSizes { + unsigned int msgs; /* total number of messages */ + unsigned int sizes[BUFSIZE]; /* histogram of message sizes */ +}; -struct MsgCounts msgBufCounts = { 0, 0 }; -struct MsgCounts msgCounts = { 0, 0 }; +static struct { + struct MsgBuf *msglist; /* list of in-use MsgBuf's */ + struct { + unsigned int alloc; /* number of Msg's allocated */ + unsigned int used; /* number of Msg's in use */ + struct Msg *free; /* freelist of Msg's */ + } msgs; + size_t tot_bufsize; /* total amount of memory in buffers */ + struct { + unsigned int alloc; /* total MsgBuf's of this size */ + unsigned int used; /* number of MsgBuf's of this size in use */ + struct MsgBuf *free; /* list of free MsgBuf's */ + } msgBufs[MB_MAX_SHIFT - MB_BASE_SHIFT + 1]; + struct MsgSizes sizes; /* histogram of message sizes */ +} MQData; /* * This routine is used to remove a certain amount of data from a given @@ -86,10 +112,10 @@ msgq_delmsg(struct MsgQ *mq, struct MsgQList *qlist, unsigned int *length_p) else qlist->head = m->next; /* just shift the list down some */ - msgCounts.used--; /* struct Msg is not in use anymore */ + MQData.msgs.used--; /* struct Msg is not in use anymore */ - m->next = MQData.free_msgs; /* throw it onto the free list */ - MQData.free_msgs = m; + m->next = MQData.msgs.free; /* throw it onto the free list */ + MQData.msgs.free = m; } else { mq->length -= *length_p; /* decrement queue length */ m->sent += *length_p; /* this much of the message has been sent */ @@ -205,6 +231,76 @@ msgq_mapiov(const struct MsgQ *mq, struct iovec *iov, int count, return i; } +/* + * This is a helper routine to allocate a buffer + */ +static struct MsgBuf * +msgq_alloc(struct MsgBuf *in_mb, int length) +{ + struct MsgBuf *mb; + int power; + + /* Find the power of two size that will accomodate the message */ + for (power = MB_BASE_SHIFT; power < MB_MAX_SHIFT + 1; power++) + if ((length - 1) >> power == 0) + break; + assert((1 << power) >= length); + assert((1 << power) <= 512); + length = 1 << power; /* reset the length */ + + /* If the message needs a buffer of exactly the existing size, just use it */ + if (in_mb && in_mb->power == power) { + in_mb->real = in_mb; /* real buffer is this buffer */ + return in_mb; + } + + /* Try popping one off the freelist first */ + if ((mb = MQData.msgBufs[power - MB_BASE_SHIFT].free)) { + MQData.msgBufs[power - MB_BASE_SHIFT].free = mb->next; + } else if (MQData.tot_bufsize < feature_int(FEAT_BUFFERPOOL)) { + /* Allocate another if we won't bust the BUFFERPOOL */ + Debug((DEBUG_MALLOC, "Allocating MsgBuf of length %d (total size %zu)", + length, sizeof(struct MsgBuf) + length)); + mb = (struct MsgBuf *)MyMalloc(sizeof(struct MsgBuf) + length); + MQData.msgBufs[power - MB_BASE_SHIFT].alloc++; + mb->power = power; /* remember size */ + MQData.tot_bufsize += length; + } + + if (mb) { + MQData.msgBufs[power - MB_BASE_SHIFT].used++; /* how many are we using? */ + + mb->real = 0; /* essential initializations */ + mb->ref = 1; + + if (in_mb) /* remember who's the *real* buffer */ + in_mb->real = mb; + } else if (in_mb) /* just use the input buffer */ + mb = in_mb->real = in_mb; + + return mb; /* return the buffer */ +} + +/* + * This routine simply empties the free list + */ +static void +msgq_clear_freembs(void) +{ + struct MsgBuf *mb; + int i; + + /* Walk through the various size classes */ + for (i = MB_BASE_SHIFT; i < MB_MAX_SHIFT + 1; i++) + /* walk down the free list */ + while ((mb = MQData.msgBufs[i - MB_BASE_SHIFT].free)) { + MQData.msgBufs[i - MB_BASE_SHIFT].free = mb->next; /* shift free list */ + MQData.msgBufs[i - MB_BASE_SHIFT].alloc--; /* reduce allocation count */ + MQData.tot_bufsize -= 1 << i; /* reduce total buffer allocation count */ + MyFree(mb); /* and free the buffer */ + } +} + /* * This routine builds a struct MsgBuf with the appropriate contents * and returns it; this saves us from having to worry about the contents @@ -217,33 +313,62 @@ msgq_vmake(struct Client *dest, const char *format, va_list vl) assert(0 != format); - if (!(mb = MQData.free_mbs)) { /* do I need to allocate one? */ - mb = (struct MsgBuf *)MyMalloc(sizeof(struct MsgBuf)); - msgBufCounts.alloc++; /* we allocated another */ - } else /* shift the free list */ - MQData.free_mbs = MQData.free_mbs->next; - - msgBufCounts.used++; /* we're using another */ + if (!(mb = msgq_alloc(0, BUFSIZE))) { + if (feature_bool(FEAT_HAS_FERGUSON_FLUSHER)) { + /* + * from "Married With Children" episode were Al bought a REAL toilet + * on the black market because he was tired of the wimpy water + * conserving toilets they make these days --Bleep + */ + /* + * Apparently this doesn't work, the server _has_ to + * dump a few clients to handle the load. A fully loaded + * server cannot handle a net break without dumping some + * clients. If we flush the connections here under a full + * load we may end up starving the kernel for mbufs and + * crash the machine + */ + /* + * attempt to recover from buffer starvation before + * bailing this may help servers running out of memory + */ + flush_connections(0); + mb = msgq_alloc(0, BUFSIZE); + } + if (!mb) { /* OK, try clearing the buffer free list */ + msgq_clear_freembs(); + mb = msgq_alloc(0, BUFSIZE); + } + if (!mb) { /* OK, try killing a client */ + kill_highest_sendq(0); /* Don't kill any server connections */ + mb = msgq_alloc(0, BUFSIZE); + } + if (!mb) { /* hmmm... */ + kill_highest_sendq(1); /* Try killing a server connection now */ + mb = msgq_alloc(0, BUFSIZE); + } + if (!mb) /* AIEEEE! */ + server_panic("Unable to allocate buffers!"); + } - mb->next = MQData.msgs; /* initialize the msgbuf */ - mb->prev_p = &MQData.msgs; - mb->ref = 1; + mb->next = MQData.msglist; /* initialize the msgbuf */ + mb->prev_p = &MQData.msglist; /* fill the buffer */ - mb->length = ircd_vsnprintf(dest, mb->msg, sizeof(mb->msg) - 2, format, vl); + mb->length = ircd_vsnprintf(dest, mb->msg, bufsize(mb) - 1, format, vl); - if (mb->length > sizeof(mb->msg) - 3) - mb->length = sizeof(mb->msg) - 3; + if (mb->length > bufsize(mb) - 2) + mb->length = bufsize(mb) - 2; mb->msg[mb->length++] = '\r'; /* add \r\n to buffer */ mb->msg[mb->length++] = '\n'; mb->msg[mb->length] = '\0'; /* not strictly necessary */ - assert(mb->length < sizeof(mb->msg)); + assert(mb->length <= bufsize(mb)); - if (MQData.msgs) /* link it into the list */ - MQData.msgs->prev_p = &mb->next; - MQData.msgs = mb; + if (MQData.msglist) /* link it into the list */ + MQData.msglist->prev_p = &mb->next; + MQData.msglist = mb; return mb; } @@ -271,25 +396,26 @@ msgq_append(struct Client *dest, struct MsgBuf *mb, const char *format, ...) assert(0 != mb); assert(0 != format); + assert(0 == mb->real); assert(2 < mb->length); - assert(sizeof(mb->msg) > mb->length); + assert(bufsize(mb) >= mb->length); mb->length -= 2; /* back up to before \r\n */ va_start(vl, format); /* append to the buffer */ mb->length += ircd_vsnprintf(dest, mb->msg + mb->length, - sizeof(mb->msg) - 2 - mb->length, format, vl); + bufsize(mb) - mb->length - 1, format, vl); va_end(vl); - if (mb->length > sizeof(mb->msg) - 3) - mb->length = sizeof(mb->msg) - 3; + if (mb->length > bufsize(mb) - 2) + mb->length = bufsize(mb) - 2; mb->msg[mb->length++] = '\r'; /* add \r\n to buffer */ mb->msg[mb->length++] = '\n'; mb->msg[mb->length] = '\0'; /* not strictly necessary */ - assert(mb->length < sizeof(mb->msg)); + assert(mb->length <= bufsize(mb)); } /* @@ -301,19 +427,22 @@ msgq_clean(struct MsgBuf *mb) { assert(0 != mb); assert(0 < mb->ref); - assert(0 != mb->prev_p); if (!--mb->ref) { /* deallocate the message */ - *mb->prev_p = mb->next; /* clip it out of active MsgBuf's list */ - if (mb->next) - mb->next->prev_p = mb->prev_p; + if (mb->prev_p) { + *mb->prev_p = mb->next; /* clip it out of active MsgBuf's list */ + if (mb->next) + mb->next->prev_p = mb->prev_p; + } - mb->next = MQData.free_mbs; /* add it to free list */ - MQData.free_mbs = mb; + if (mb->real && mb->real != mb) /* clean up the real buffer */ + msgq_clean(mb->real); - mb->prev_p = 0; + mb->next = MQData.msgBufs[mb->power - MB_BASE_SHIFT].free; + MQData.msgBufs[mb->power - MB_BASE_SHIFT].free = mb; + MQData.msgBufs[mb->power - MB_BASE_SHIFT].used--; - msgBufCounts.used--; /* decrement the usage count */ + mb->prev_p = 0; } } @@ -329,26 +458,56 @@ msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio) assert(0 != mq); assert(0 != mb); assert(0 < mb->ref); + assert(0 < mb->length); - Debug((DEBUG_SEND, "Adding buffer %p [%.*s] to %s queue", mb, - mb->length - 2, mb->msg, prio ? "priority" : "normal")); + Debug((DEBUG_SEND, "Adding buffer %p [%.*s] length %u to %s queue", mb, + mb->length - 2, mb->msg, mb->length, prio ? "priority" : "normal")); qlist = prio ? &mq->prio : &mq->queue; - if (!(msg = MQData.free_msgs)) { /* do I need to allocate one? */ + if (!(msg = MQData.msgs.free)) { /* do I need to allocate one? */ msg = (struct Msg *)MyMalloc(sizeof(struct Msg)); - msgCounts.alloc++; /* we allocated another */ + MQData.msgs.alloc++; /* we allocated another */ } else /* shift the free list */ - MQData.free_msgs = MQData.free_msgs->next; + MQData.msgs.free = MQData.msgs.free->next; - msgCounts.used++; /* we're using another */ + MQData.msgs.used++; /* we're using another */ msg->next = 0; /* initialize the msg */ msg->sent = 0; - msg->msg = mb; + /* Get the real buffer, allocating one if necessary */ + if (!mb->real) { + struct MsgBuf *tmp; + + MQData.sizes.msgs++; /* update histogram counts */ + MQData.sizes.sizes[mb->length - 1]++; + + tmp = msgq_alloc(mb, mb->length); /* allocate a close-fitting buffer */ + + if (tmp != mb) { /* OK, prepare the new "real" buffer */ + Debug((DEBUG_SEND, "Copying old buffer %p [%.*s] length %u into new " + "buffer %p size %u", mb, mb->length - 2, mb->msg, mb->length, + tmp, bufsize(tmp))); + memcpy(tmp->msg, mb->msg, mb->length + 1); /* copy string over */ + tmp->length = mb->length; + + tmp->next = mb->next; /* replace it in the list, now */ + if (tmp->next) + tmp->next->prev_p = &tmp->next; + tmp->prev_p = mb->prev_p; + *tmp->prev_p = tmp; + + mb->next = 0; /* this one's no longer in the list */ + mb->prev_p = 0; + } + } + + mb = mb->real; /* work with the real buffer */ mb->ref++; /* increment the ref count on the buffer */ + msg->msg = mb; /* point at the real message buffer now */ + if (!qlist->head) /* queue list was empty; head and tail point to msg */ qlist->head = qlist->tail = msg; else { @@ -366,18 +525,39 @@ msgq_add(struct MsgQ *mq, struct MsgBuf *mb, int prio) * This is for reporting memory usage by the msgq system. */ void -msgq_count_memory(size_t *msg_alloc, size_t *msg_used, size_t *msgbuf_alloc, - size_t *msgbuf_used) +msgq_count_memory(struct Client *cptr, size_t *msg_alloc, size_t *msgbuf_alloc) { + int i; + size_t total = 0, size; + + assert(0 != cptr); assert(0 != msg_alloc); - assert(0 != msg_used); assert(0 != msgbuf_alloc); - assert(0 != msgbuf_used); - *msg_alloc = msgCounts.alloc * sizeof(struct Msg); - *msg_used = msgCounts.used * sizeof(struct Msg); - *msgbuf_alloc = msgCounts.alloc * sizeof(struct MsgBuf); - *msgbuf_used = msgCounts.used * sizeof(struct MsgBuf); + /* Data for Msg's is simple, so just send it */ + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":Msgs allocated %d(%zu) used %d(%zu)", MQData.msgs.alloc, + MQData.msgs.alloc * sizeof(struct Msg), MQData.msgs.used, + MQData.msgs.used * sizeof(struct Msg)); + /* count_memory() wants to know the total */ + *msg_alloc = MQData.msgs.alloc * sizeof(struct Msg); + + /* Ok, now walk through each size class */ + for (i = MB_BASE_SHIFT; i < MB_MAX_SHIFT + 1; i++) { + size = sizeof(struct MsgBuf) + (1 << i); /* total size of a buffer */ + + /* Send information for this buffer size class */ + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":MsgBufs of size %zu allocated %d(%zu) used %d(%zu)", 1 << i, + MQData.msgBufs[i - MB_BASE_SHIFT].alloc, + MQData.msgBufs[i - MB_BASE_SHIFT].alloc * size, + MQData.msgBufs[i - MB_BASE_SHIFT].used, + MQData.msgBufs[i - MB_BASE_SHIFT].used * size); + + /* count_memory() wants to know the total */ + total += MQData.msgBufs[i - MB_BASE_SHIFT].alloc * size; + } + *msgbuf_alloc = total; } /* @@ -388,5 +568,28 @@ msgq_bufleft(struct MsgBuf *mb) { assert(0 != mb); - return sizeof(mb->msg) - mb->length - 1; /* \r\n counted in mb->length */ + return bufsize(mb) - mb->length; /* \r\n counted in mb->length */ +} + +/* + * This just generates and sends a histogram of message lengths to the + * requesting client + */ +void +msgq_histogram(struct Client *cptr, struct StatDesc *sd, int stat, char *param) +{ + struct MsgSizes tmp = MQData.sizes; /* All hail structure copy! */ + int i; + + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":Histogram of message lengths (%lu messages)", tmp.msgs); + for (i = 0; i + 16 <= BUFSIZE; i += 16) + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":% 4d: %lu %lu %lu %lu " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", i + 1, + tmp.sizes[i + 0], tmp.sizes[i + 1], tmp.sizes[i + 2], + tmp.sizes[i + 3], tmp.sizes[i + 4], tmp.sizes[i + 5], + tmp.sizes[i + 6], tmp.sizes[i + 7], tmp.sizes[i + 8], + tmp.sizes[i + 9], tmp.sizes[i + 10], tmp.sizes[i + 11], + tmp.sizes[i + 12], tmp.sizes[i + 13], tmp.sizes[i + 14], + tmp.sizes[i + 15]); } diff --git a/ircd/numnicks.c b/ircd/numnicks.c index cbba746..8574fe7 100644 --- a/ircd/numnicks.c +++ b/ircd/numnicks.c @@ -340,11 +340,13 @@ int markMatchexServer(const char *cmask, int minlen) struct Client *acptr; for (i = 0; i < lastNNServer; i++) { - if ((acptr = server_list[i])) { + if ((acptr = server_list[i])) + { if (matchexec(cli_name(acptr), cmask, minlen)) - cli_flags(acptr) &= ~FLAGS_MAP; - else { - cli_flags(acptr) |= FLAGS_MAP; + ClrFlag(acptr, FLAG_MAP); + else + { + SetFlag(acptr, FLAG_MAP); cnt++; } } diff --git a/ircd/opercmds.c b/ircd/opercmds.c index 22016f1..0cc35a4 100644 --- a/ircd/opercmds.c +++ b/ircd/opercmds.c @@ -42,6 +42,7 @@ #include #include +#include #include char *militime(char* sec, char* usec) @@ -58,3 +59,25 @@ char *militime(char* sec, char* usec) return timebuf; } +char *militime_float(char* start) +{ + struct timeval tv; + static char timebuf[18]; + char *p; + + gettimeofday(&tv, NULL); + if (start) + { + if ((p = strchr(start, '.'))) + { + p++; + sprintf(timebuf, "%ld", + (tv.tv_sec - atoi(start)) * 1000 + (tv.tv_usec - atoi(p)) / 1000); + } + else + strcpy(timebuf, "0"); + } + else + sprintf(timebuf, "%ld.%ld", tv.tv_sec, tv.tv_usec); + return timebuf; +} diff --git a/ircd/parse.c b/ircd/parse.c index d5cd49d..4a1d7f6 100644 --- a/ircd/parse.c +++ b/ircd/parse.c @@ -30,7 +30,6 @@ #include "ircd_alloc.h" #include "ircd_chattr.h" #include "ircd_features.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_string.h" #include "msg.h" @@ -93,6 +92,13 @@ struct Message msgtab[] = { /* UNREG, CLIENT, SERVER, OPER, SERVICE */ { m_unregistered, m_wallchops, ms_wallchops, m_wallchops, m_ignore } }, + { + MSG_WALLVOICES, + TOK_WALLVOICES, + 0, MAXPARA, MFLG_SLOW, 0, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_unregistered, m_wallvoices, ms_wallvoices, m_wallvoices, m_ignore } + }, { MSG_CPRIVMSG, TOK_CPRIVMSG, @@ -315,11 +321,7 @@ struct Message msgtab[] = { TOK_TRACE, 0, MAXPARA, MFLG_SLOW, 0, /* UNREG, CLIENT, SERVER, OPER, SERVICE */ -#ifdef HEAD_IN_SAND_TRACE - { m_unregistered, m_not_oper, ms_trace, mo_trace, m_ignore } -#else { m_unregistered, m_trace, ms_trace, mo_trace, m_ignore } -#endif }, { MSG_PASS, @@ -382,7 +384,7 @@ struct Message msgtab[] = { TOK_MAP, 0, MAXPARA, MFLG_SLOW, 0, /* UNREG, CLIENT, SERVER, OPER, SERVICE */ - { m_unregistered, m_map, m_ignore, mo_map, m_ignore } + { m_unregistered, m_map, m_ignore, m_map, m_ignore } }, { MSG_VERSION, @@ -396,18 +398,14 @@ struct Message msgtab[] = { TOK_STATS, 0, MAXPARA, MFLG_SLOW, 0, /* UNREG, CLIENT, SERVER, OPER, SERVICE */ - { m_unregistered, m_stats, ms_stats, mo_stats, m_ignore } + { m_unregistered, m_stats, m_stats, m_stats, m_ignore } }, { MSG_LINKS, TOK_LINKS, 0, MAXPARA, MFLG_SLOW, 0, /* UNREG, CLIENT, SERVER, OPER, SERVICE */ -#ifdef HEAD_IN_SAND_LINKS - { m_unregistered, m_links_redirect, m_links, m_links, m_ignore } -#else - { m_unregistered, m_links, m_links, m_links, m_ignore } -#endif + { m_unregistered, m_links, ms_links, m_links, m_ignore } }, { MSG_ADMIN, @@ -577,6 +575,13 @@ struct Message msgtab[] = { /* UNREG, CLIENT, SERVER, OPER, SERVICE */ { m_ignore, m_ignore, ms_account, m_ignore, m_ignore } }, + { + MSG_ASLL, + TOK_ASLL, + 0, MAXPARA, MFLG_SLOW, 0, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_ignore, m_not_oper, ms_asll, mo_asll, m_ignore } + }, /* This command is an alias for QUIT during the unregistered part of * of the server. This is because someone jumping via a broken web * proxy will send a 'POST' as their first command - which we will diff --git a/ircd/random.c b/ircd/random.c index e85b228..7170167 100644 --- a/ircd/random.c +++ b/ircd/random.c @@ -82,7 +82,7 @@ memxor(void *dest, void *src, int n) unsigned char *d = (unsigned char *)dest; unsigned char *s = (unsigned char *)src; - while (--n) + while (n--) d[n] ^= s[n]; } diff --git a/ircd/s_auth.c b/ircd/s_auth.c index 17dce05..b9019ec 100644 --- a/ircd/s_auth.c +++ b/ircd/s_auth.c @@ -80,8 +80,9 @@ static struct { { "NOTICE AUTH :*** Checking Ident\r\n", 33 }, { "NOTICE AUTH :*** Got ident response\r\n", 37 }, { "NOTICE AUTH :*** No ident response\r\n", 36 }, - { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " \ - "ignoring hostname.\r\n", 80 } + { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " + "ignoring hostname.\r\n", 80 }, + {"NOTICE AUTH :*** Invalid hostname\r\n", 35 } }; typedef enum { @@ -92,7 +93,8 @@ typedef enum { REPORT_DO_ID, REPORT_FIN_ID, REPORT_FAIL_ID, - REPORT_IP_MISMATCH + REPORT_IP_MISMATCH, + REPORT_INVAL_DNS } ReportType; #define sendheader(c, r) \ @@ -108,6 +110,24 @@ static void unlink_auth_request(struct AuthRequest* request, struct AuthRequest** list); void free_auth_request(struct AuthRequest* auth); +/* auth_verify_hostname - verify that a hostname is valid, i.e., only + * contains characters valid for a hostname and that a hostname is not + * too long. + */ +static int +auth_verify_hostname(char *host, int maxlen) +{ + int i; + + /* Walk through the host name */ + for (i = 0; host[i]; i++) + /* If it's not a hostname character or if it's too long, return false */ + if (!IsHostChar(host[i]) || i >= maxlen) + return 0; + + return 1; /* it's a valid hostname */ +} + /* * auth_timeout - timeout a given auth request */ @@ -353,7 +373,13 @@ static void auth_dns_callback(void* vptr, struct DNSReply* reply) return; } } - else { + else if (!auth_verify_hostname(hp->h_name, HOSTLEN)) + { + if (IsUserPort(auth->client)) + sendheader(auth->client, REPORT_INVAL_DNS); + } + else + { ++reply->ref_count; cli_dns_reply(auth->client) = reply; ircd_strncpy(cli_sockhost(auth->client), hp->h_name, HOSTLEN); diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 0b5324b..282bb5e 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -358,7 +358,7 @@ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { case IO_SUCCESS: - cli_flags(cptr) &= ~FLAGS_BLOCKED; + ClrFlag(cptr, FLAG_BLOCKED); cli_sendB(cptr) += bytes_written; cli_sendB(&me) += bytes_written; @@ -375,14 +375,14 @@ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) * say it was blocked */ if (bytes_written < bytes_count) - cli_flags(cptr) |= FLAGS_BLOCKED; + SetFlag(cptr, FLAG_BLOCKED); break; case IO_BLOCKED: - cli_flags(cptr) |= FLAGS_BLOCKED; + SetFlag(cptr, FLAG_BLOCKED); break; case IO_FAILURE: cli_error(cptr) = errno; - cli_flags(cptr) |= FLAGS_DEADSOCKET; + SetFlag(cptr, FLAG_DEADSOCKET); break; } return bytes_written; @@ -460,7 +460,7 @@ static int completed_connection(struct Client* cptr) * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; - cli_flags(cptr) |= FLAGS_PINGSENT; + SetFlag(cptr, FLAG_PINGSENT); sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, @@ -540,7 +540,7 @@ void close_connection(struct Client *cptr) socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; } - cli_flags(cptr) |= FLAGS_DEADSOCKET; + SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); @@ -704,18 +704,21 @@ static int read_packet(struct Client *cptr, int socket_ready) DBufLength(&(cli_recvQ(cptr))) > feature_int(FEAT_CLIENT_FLOOD))) { switch (os_recv_nonb(cli_fd(cptr), readbuf, sizeof(readbuf), &length)) { case IO_SUCCESS: - if (length) { - cli_lasttime(cptr) = CurrentTime; + if (length) + { + if (!IsServer(cptr)) + cli_lasttime(cptr) = CurrentTime; if (cli_lasttime(cptr) > cli_since(cptr)) cli_since(cptr) = cli_lasttime(cptr); - cli_flags(cptr) &= ~(FLAGS_PINGSENT | FLAGS_NONL); + ClrFlag(cptr, FLAG_PINGSENT); + ClrFlag(cptr, FLAG_NONL); } break; case IO_BLOCKED: break; case IO_FAILURE: cli_error(cptr) = errno; - /* cptr->flags |= FLAGS_DEADSOCKET; */ + /* SetFlag(cpt, FLAG_DEADSOCKET); */ return 0; } } @@ -754,10 +757,10 @@ static int read_packet(struct Client *cptr, int socket_ready) * deletes the rest of the buffer contents. * -avalon */ - if (dolen = 0) + if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) - cli_flags(cptr) |= FLAGS_NONL; + SetFlag(cptr, FLAG_NONL); else DBufClear(&(cli_recvQ(cptr))); } @@ -769,15 +772,15 @@ static int read_packet(struct Client *cptr, int socket_ready) */ if (IsHandshake(cptr) || IsServer(cptr)) { - while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr)) + while (-1) { dolen = dbuf_get(&(cli_recvQ(cptr)), readbuf, sizeof(readbuf)); - if (dolen < 0) + if (dolen <= 0) return 1; else if (dolen == 0) { if (DBufLength(&(cli_recvQ(cptr))) < 510) - cli_flags(cptr) |= FLAGS_NONL; + SetFlag(cptr, FLAG_NONL); else DBufClear(&(cli_recvQ(cptr))); } @@ -1022,7 +1025,7 @@ static void client_sock_callback(struct Event* ev) case ET_EOF: /* end of file on socket */ Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d", cli_fd(cptr), cli_error(cptr))); - cli_flags(cptr) |= FLAGS_DEADSOCKET; + SetFlag(cptr, FLAG_DEADSOCKET); if ((IsServer(cptr) || IsHandshake(cptr)) && cli_error(cptr) == 0) { exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)", cli_name(cptr), cli_serv(cptr)->last_error_msg); @@ -1034,7 +1037,7 @@ static void client_sock_callback(struct Event* ev) break; case ET_WRITE: /* socket is writable */ - cli_flags(cptr) &= ~FLAGS_BLOCKED; + ClrFlag(cptr, FLAG_BLOCKED); if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048) list_next_channels(cptr, 64); Debug((DEBUG_SEND, "Sending queued data to %C", cptr)); diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 21fa6ac..d09dfd8 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -59,18 +59,19 @@ #include #include #include +#include #include #include #include #include -#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif -struct ConfItem* GlobalConfList = 0; +struct ConfItem *GlobalConfList = 0; int GlobalConfCount = 0; +struct qline *GlobalQuarantineList = 0; void yyparse(void); int conf_fd, lineno; @@ -238,7 +239,8 @@ static struct DNSReply* conf_dns_lookup(struct ConfItem* aconf) * Do (start) DNS lookups of all hostnames in the conf line and convert * an IP addresses in a.b.c.d number for to IP#s. */ -void lookup_confhost(struct ConfItem *aconf) +void +lookup_confhost(struct ConfItem *aconf) { struct DNSReply* reply; @@ -399,7 +401,7 @@ enum AuthorizationCheckResult attach_iline(struct Client* cptr) uhost[sizeof(uhost) - 1] = 0; if (0 == match(aconf->name, uhost)) { if (strchr(uhost, '@')) - cli_flags(cptr) |= FLAGS_DOID; + SetFlag(cptr, FLAG_DOID); return check_limit_and_attach(cptr, aconf); } } @@ -416,7 +418,7 @@ enum AuthorizationCheckResult attach_iline(struct Client* cptr) if (match(aconf->host, uhost)) continue; if (strchr(uhost, '@')) - cli_flags(cptr) |= FLAGS_DOID; + SetFlag(cptr, FLAG_DOID); return check_limit_and_attach(cptr, aconf); } @@ -922,6 +924,43 @@ const struct DenyConf* conf_get_deny_list(void) return denyConfList; } +#if 0 +void conf_add_quarantine(const char *chname, const char *reason) +{ + struct qline *qline; + + qline = (struct qline *) MyMalloc(sizeof(struct qline)); + DupString(qline->chname, chname); + DupString(qline->reason, reason); + qline->next = GlobalQuarantineList; + GlobalQuarantineList = qline; +} +#endif + +const char* +find_quarantine(const char *chname) +{ + struct qline *qline; + + for (qline = GlobalQuarantineList; qline; qline = qline->next) + if (!ircd_strcmp(qline->chname, chname)) + return qline->reason; + return NULL; +} + +void clear_quarantines(void) +{ + struct qline *qline; + while ((qline = GlobalQuarantineList)) + { + GlobalQuarantineList = qline->next; + MyFree(qline->reason); + MyFree(qline->chname); + MyFree(qline); + } +} + + /* * read_configuration_file * diff --git a/ircd/s_debug.c b/ircd/s_debug.c index c45a532..a227454 100644 --- a/ircd/s_debug.c +++ b/ircd/s_debug.c @@ -205,7 +205,8 @@ static void debug_enumerator(struct Client* cptr, const char* msg) * different field names for "struct rusage". * -avalon */ -void send_usage(struct Client *cptr, char *nick) +void send_usage(struct Client *cptr, struct StatDesc *sd, int stat, + char *param) { os_get_rusage(cptr, CurrentTime - cli_since(&me), debug_enumerator); @@ -214,7 +215,8 @@ void send_usage(struct Client *cptr, char *nick) } #endif /* DEBUGMODE */ -void count_memory(struct Client *cptr, char *nick) +void count_memory(struct Client *cptr, struct StatDesc *sd, int stat, + char *param) { struct Client *acptr; struct SLink *link; @@ -223,7 +225,8 @@ void count_memory(struct Client *cptr, char *nick) const struct ConnectionClass* cltmp; struct Membership* member; - int c = 0, /* clients */ + int acc = 0, /* accounts */ + c = 0, /* clients */ cn = 0, /* connections */ ch = 0, /* channels */ lcc = 0, /* local client conf links */ @@ -237,7 +240,9 @@ void count_memory(struct Client *cptr, char *nick) int usi = 0, /* users invited */ aw = 0, /* aways set */ - wwa = 0; /* whowas aways */ + wwa = 0, /* whowas aways */ + gl = 0, /* glines */ + ju = 0; /* jupes */ size_t chm = 0, /* memory used by channels */ chbm = 0, /* memory used by channel bans */ @@ -246,13 +251,13 @@ void count_memory(struct Client *cptr, char *nick) awm = 0, /* memory used by aways */ wwam = 0, /* whowas away memory used */ wwm = 0, /* whowas array memory used */ + glm = 0, /* memory used by glines */ + jum = 0, /* memory used by jupes */ com = 0, /* memory used by conf lines */ dbufs_allocated = 0, /* memory used by dbufs */ dbufs_used = 0, /* memory used by dbufs */ msg_allocated = 0, /* memory used by struct Msg */ - msg_used = 0, /* memory used by struct Msg */ msgbuf_allocated = 0, /* memory used by struct MsgBuf */ - msgbuf_used = 0, /* memory used by struct MsgBuf */ rm = 0, /* res memory used */ totcl = 0, totch = 0, totww = 0, tot = 0; @@ -282,6 +287,9 @@ void count_memory(struct Client *cptr, char *nick) awm += (strlen(cli_user(acptr)->away) + 1); } } + + if (IsAccount(acptr)) + acc++; } cm = c * sizeof(struct Client); cnm = cn * sizeof(struct Connection); @@ -314,7 +322,8 @@ void count_memory(struct Client *cptr, char *nick) send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Clients %d(%zu) Connections %d(%zu)", c, cm, cn, cnm); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, - ":Users %d(%zu) Invites %d(%zu)", us, us * sizeof(struct User), + ":Users %d(%zu) Accounts %d(%zu) Invites %d(%zu)", + us, us * sizeof(struct User), acc, acc * (ACCOUNTLEN + 1), usi, usi * sizeof(struct SLink)); send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":User channels %d(%zu) Aways %d(%zu)", memberships, @@ -365,14 +374,7 @@ void count_memory(struct Client *cptr, char *nick) ":DBufs allocated %d(%zu) used %d(%zu)", DBufAllocCount, dbufs_allocated, DBufUsedCount, dbufs_used); - msgq_count_memory(&msg_allocated, &msg_used, &msgbuf_allocated, - &msgbuf_used); - send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, - ":Msgs allocated %d(%zu) used %d(%zu)", msgCounts.alloc, - msg_allocated, msgCounts.used, msg_used); - send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, - ":MsgBufs allocated %d(%zu) used %d(%zu)", msgBufCounts.alloc, - msgbuf_allocated, msgBufCounts.used, msgbuf_used); + msgq_count_memory(cptr, &msg_allocated, &msgbuf_allocated); rm = cres_mem(cptr); diff --git a/ircd/s_err.c b/ircd/s_err.c index 807047b..c2cbdd4 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -30,7 +30,7 @@ static Numeric replyTable[] = { /* 000 */ { 0 }, /* 001 */ - { RPL_WELCOME, ":Welcome to the Internet Relay Network %s", "001" }, + { RPL_WELCOME, ":Welcome to the Internet Relay Network%s%s, %s", "001" }, /* 002 */ { RPL_YOURHOST, ":Your host is %s, running version %s", "002" }, /* 003 */ @@ -708,7 +708,7 @@ static Numeric replyTable[] = { /* 337 */ { 0 }, /* 338 */ - { RPL_WHOISACTUALLY, ":%s is actually %s@%s [%s]", "338" }, + { RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", "338" }, /* 339 */ { 0 }, /* 340 */ @@ -1080,7 +1080,7 @@ static Numeric replyTable[] = { /* 523 */ { 0 }, /* 524 */ - { 0 }, + { ERR_QUARANTINED, "%s :Channel is quarantined : %s", "524" }, /* 525 */ { 0 }, /* 526 */ diff --git a/ircd/s_misc.c b/ircd/s_misc.c index 2760cad..cafbd57 100644 --- a/ircd/s_misc.c +++ b/ircd/s_misc.c @@ -37,6 +37,7 @@ #include "ircd_snprintf.h" #include "ircd_string.h" #include "list.h" +#include "map.h" #include "match.h" #include "msg.h" #include "numeric.h" @@ -47,6 +48,7 @@ #include "s_bsd.h" #include "s_conf.h" #include "s_debug.h" +#include "s_stats.h" #include "s_user.h" #include "send.h" #include "struct.h" @@ -54,7 +56,6 @@ #include "sys.h" #include "uping.h" #include "userload.h" -#include "map.h" #include #include @@ -170,7 +171,8 @@ const char* get_client_name(const struct Client* sptr, int showip) if (MyConnect(sptr)) { if (showip) ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr), - cli_user(sptr)->username, cli_sock_ip(sptr)); + IsIdented(sptr) ? cli_username(sptr) : "unknown", + cli_sock_ip(sptr)); else return cli_name(sptr); return nbuf; @@ -390,8 +392,16 @@ int exit_client(struct Client *cptr, /* Connection being handled by char comment1[HOSTLEN + HOSTLEN + 2]; assert(killer); - if (MyConnect(victim)) { - cli_flags(victim) |= FLAGS_CLOSING; + if (MyConnect(victim)) + { + SetFlag(victim, FLAG_CLOSING); + + if (feature_bool(FEAT_CONNEXIT_NOTICES) && IsUser(victim)) + sendto_opmask_butone(0, SNO_CONNEXIT, + "Client exiting: %s (%s@%s) [%s] [%s]", + cli_name(victim), cli_user(victim)->username, + cli_user(victim)->host, comment, + ircd_ntoa((const char*) &(cli_ip(victim)))); update_load(); on_for = CurrentTime - cli_firsttime(victim); @@ -456,13 +466,15 @@ int exit_client(struct Client *cptr, /* Connection being handled by if (IsServer(victim)) { -#ifdef HEAD_IN_SAND_NETSPLIT - strcpy(comment1, "*.net *.split"); -#else - strcpy(comment1, cli_name(cli_serv(victim)->up)); - strcat(comment1, " "); - strcat(comment1, cli_name(victim)); -#endif + if (feature_bool(FEAT_HIS_NETSPLIT)) + strcpy(comment1, "*.net *.split"); + else + { + strcpy(comment1, cli_name(cli_serv(victim)->up)); + strcat(comment1, " "); + strcat(comment1, cli_name(victim)); + } + if (IsUser(killer)) sendto_opmask_butone(killer, SNO_OLDSNO, "%s SQUIT by %s [%s]:", (cli_user(killer)->server == victim || @@ -477,9 +489,8 @@ int exit_client(struct Client *cptr, /* Connection being handled by sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)", cli_serv(victim)->up, victim, comment); -#if defined(HEAD_IN_SAND_MAP) || defined(HEAD_IN_SAND_LINKS) - map_update(victim); -#endif + if (feature_bool(FEAT_HIS_MAP) || feature_bool(FEAT_HIS_LINKS)) + map_update(victim); } /* @@ -487,11 +498,12 @@ int exit_client(struct Client *cptr, /* Connection being handled by * except the source: */ for (dlp = cli_serv(&me)->down; dlp; dlp = dlp->next) { - if (dlp->value.cptr != cli_from(killer) && dlp->value.cptr != victim) { + if (dlp->value.cptr != cli_from(killer) && dlp->value.cptr != victim) + { if (IsServer(victim)) sendcmdto_one(killer, CMD_SQUIT, dlp->value.cptr, "%s %Tu :%s", cli_name(victim), cli_serv(victim)->timestamp, comment); - else if (IsUser(victim) && 0 == (cli_flags(victim) & FLAGS_KILLED)) + else if (IsUser(victim) && !HasFlag(victim, FLAG_KILLED)) sendcmdto_one(victim, CMD_QUIT, dlp->value.cptr, ":%s", comment); } } @@ -536,7 +548,7 @@ void initstats(void) memset(&ircst, 0, sizeof(ircst)); } -void tstats(struct Client *cptr, char *name) +void tstats(struct Client *cptr, struct StatDesc *sd, int stat, char *param) { struct Client *acptr; int i; diff --git a/ircd/s_numeric.c b/ircd/s_numeric.c index 8d9602b..07e41ab 100644 --- a/ircd/s_numeric.c +++ b/ircd/s_numeric.c @@ -27,7 +27,7 @@ #include "client.h" #include "hash.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_snprintf.h" #include "numnicks.h" #include "send.h" @@ -79,28 +79,17 @@ int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr, ircd_snprintf(0, num, sizeof(num), "%03d", numeric); -#ifdef HEAD_IN_SAND_REWRITE /* Since 2.10.10.pl14 we rewrite numerics from remote servers to appear to * come from the local server */ - if (IsOper(acptr)) { -#endif - if (acptr) - sendcmdto_one(sptr, num, num, acptr, "%C %s", acptr, parv[2]); - else - sendcmdto_channel_butone(sptr, num, num, achptr, cptr, - SKIP_DEAF | SKIP_BURST, "%H %s", achptr, - parv[2]); -#ifdef HEAD_IN_SAND_REWRITE - } else { - if (acptr) - sendcmdto_one(&me, num, num, acptr, "%C %s", acptr, parv[2]); - else - sendcmdto_channel_butone(&me, num, num, achptr, cptr, - SKIP_DEAF | SKIP_BURST, "%H %s", achptr, - parv[2]); - } -#endif - + if (acptr) + sendcmdto_one((feature_bool(FEAT_HIS_REWRITE) && !IsOper(acptr)) ? + &me : sptr, + num, num, acptr, "%C %s", acptr, parv[2]); + else + sendcmdto_channel_butone((feature_bool(FEAT_HIS_REWRITE) && !IsOper(acptr)) ? + &me : sptr, + num, num, achptr, cptr, SKIP_DEAF | SKIP_BURST, + "%H %s", achptr, parv[2]); return 0; } diff --git a/ircd/s_stats.c b/ircd/s_stats.c index 4ea5094..d169a69 100644 --- a/ircd/s_stats.c +++ b/ircd/s_stats.c @@ -23,26 +23,38 @@ */ #include "config.h" -#include "s_stats.h" #include "class.h" #include "client.h" +#include "gline.h" #include "ircd.h" #include "ircd_chattr.h" +#include "ircd_events.h" +#include "ircd_features.h" #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" #include "listener.h" +#include "list.h" #include "match.h" +#include "motd.h" #include "msg.h" +#include "msgq.h" #include "numeric.h" #include "numnicks.h" +#include "s_bsd.h" #include "s_conf.h" +#include "s_debug.h" +#include "s_misc.h" +#include "s_serv.h" +#include "s_stats.h" #include "s_user.h" #include "send.h" #include "struct.h" +#include "userload.h" #include #include +#include #include @@ -56,36 +68,6 @@ * it--not reversed as in ircd.conf! */ -/* - * Help info displayed when user provides no stats parameter. --Gte - */ -const char *statsinfo[] = { - "The following statistics are available:", - "U - Service server & nick jupes information.", - "u - Current uptime & highest connection count.", - "p - Listening ports.", - "i - Connection authorisation lines.", - "y - Connection classes.", - "c - Remote server connection lines.", - "h - Hubs information.", - "d - Dynamic routing configuration.", - "l - Current connections information.", - "g - Global bans (G-lines).", - "k - Local bans (K-Lines).", - "o - Operator information.", - "e - Report server event loop engine.", - "f - Feature settings.", - "m - Message usage information.", - "t - Local connection statistics (Total SND/RCV, etc).", - "v - Server list with verbose information.", - "w - Userload statistics.", - "M - Memory allocation & leak monitoring.", - "z - Memory/Structure allocation information.", - "r - System resource usage (Debug only).", - "x - List usage information (Debug only).", - 0, -}; - static unsigned int report_array[17][3] = { {CONF_SERVER, RPL_STATSCLINE, 'C'}, {CONF_CLIENT, RPL_STATSILINE, 'I'}, @@ -97,14 +79,18 @@ static unsigned int report_array[17][3] = { {0, 0} }; -void report_configured_links(struct Client *sptr, int mask) +static void +stats_configured_links(struct Client *sptr, struct StatDesc* sd, int stat, + char* param) { static char null[] = ""; struct ConfItem *tmp; + int mask; unsigned int *p; unsigned short int port; char c, *host, *pass, *name; + mask = sd->sd_funcdata; for (tmp = GlobalConfList; tmp; tmp = tmp->next) { @@ -143,36 +129,72 @@ void report_configured_links(struct Client *sptr, int mask) } } -/* - * {CONF_TLINES, RPL_STATSTLINE, 'T'}, - * - * see now motd_report() in motd.c - */ -/* void report_motd_list(struct Client* to) */ -/* { */ -/* const struct MotdConf* conf = conf_get_motd_list(); */ -/* for ( ; conf; conf = conf->next) */ -/* send_reply(to, RPL_STATSTLINE, 'T', conf->hostmask, conf->path); */ -/* } */ - /* * {CONF_CRULEALL, RPL_STATSDLINE, 'D'}, * {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'}, */ -void report_crule_list(struct Client* to, int mask) +static void +stats_crule_list(struct Client* to, struct StatDesc *sd, int stat, + char *param) { + int mask; const struct CRuleConf* p = conf_get_crule_list(); - for ( ; p; p = p->next) { - if (0 != (p->type & mask)) - send_reply(to, RPL_STATSDLINE, (CRULE_ALL == p->type) ? 'D' : 'd', p->hostmask, p->rule); + + mask = (stat == 'D') ? CRULE_ALL : CRULE_MASK; + + for ( ; p; p = p->next) + { + if (p->type & mask) + send_reply(to, RPL_STATSDLINE, stat, p->hostmask, p->rule); + } +} + +static void +stats_engine(struct Client *to, struct StatDesc *sd, int stat, char *param) +{ + send_reply(to, RPL_STATSENGINE, engine_name()); +} + +static void +stats_access(struct Client *to, struct StatDesc *sd, int stat, char *param) +{ + struct ConfItem *aconf; + int wilds = 0; + int count = 1000; + + if (!param) + { + stats_configured_links(to, sd, stat, param); + return; + } + + wilds = string_has_wildcards(param); + + for (aconf = GlobalConfList; aconf; aconf = aconf->next) + { + if (aconf->status != CONF_CLIENT) + continue; + if ((!wilds && (!match(aconf->host, param) || + !match(aconf->name, param))) || + (wilds && (!mmatch(param, aconf->host) || + !mmatch(param, aconf->name)))) + { + send_reply(to, RPL_STATSILINE, 'I', aconf->host, aconf->name, + aconf->port, get_conf_class(aconf)); + if (--count == 0) + break; + } } } + + /* * {CONF_KILL, RPL_STATSKLINE, 'K'}, * {CONF_IPKILL, RPL_STATSKLINE, 'k'}, */ -void report_deny_list(struct Client* to) +static void +report_deny_list(struct Client* to) { const struct DenyConf* p = conf_get_deny_list(); for ( ; p; p = p->next) @@ -180,67 +202,322 @@ void report_deny_list(struct Client* to) p->hostmask, p->message, p->usermask); } -/* m_stats is so obnoxiously full of special cases that the different - * hunt_server() possiblites were becoming very messy. It now uses a - * switch() so as to be easier to read and update as params change. - * -Ghostwolf - * - * 2.10.11: Don't check for the oper limitation if it's not our local server. - * thusly once all the hubs have upgraded local opers will be able - * to remote stats anywhere on the network. - */ -int hunt_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[], char stat, int MustBeOper) +static void +stats_klines(struct Client *sptr, struct StatDesc *sd, int stat, char *mask) { - switch (stat) + int wilds = 0; + int count = 3; + int limit_query = 0; + char *user = 0; + char *host; + const struct DenyConf* conf; + + if (!IsAnOper(sptr)) + limit_query = 1; + + if (!mask) + { + if (limit_query) + need_more_params(sptr, "STATS K"); + else + report_deny_list(sptr); + return; + } + + if (!limit_query) + { + wilds = string_has_wildcards(mask); + count = 1000; + } + if ((host = strchr(mask, '@'))) { - /* open to all, standard # of params */ - case 'U': - case 'u': - case 'F': - case 'f': - return hunt_server_cmd(sptr, CMD_STATS, cptr, MustBeOper, "%s :%C", 2, - parc, parv); - - /* open to all, varying # of params */ - case 'k': - case 'K': - case 'i': - case 'I': - case 'p': - case 'P': + user = mask; + *host++ = '\0'; + } + else + host = mask; + + for (conf = conf_get_deny_list(); conf; conf = conf->next) + { + if ((!wilds && ((user || conf->hostmask) && + !match(conf->hostmask, host) && + (!user || !match(conf->usermask, user)))) || + (wilds && !mmatch(host, conf->hostmask) && + (!user || !mmatch(user, conf->usermask)))) { - if (parc > 3) - return hunt_server_cmd(sptr, CMD_STATS, cptr, MustBeOper, "%s %C :%s", - 2, parc, parv); - else - return hunt_server_cmd(sptr, CMD_STATS, cptr, MustBeOper, "%s :%C", 2, - parc, parv); + send_reply(sptr, RPL_STATSKLINE, + (conf->flags & DENY_FLAGS_IP) ? 'k' : 'K', + conf->hostmask, conf->message, conf->usermask); + if (--count == 0) + return; } + } +} + +static void +stats_links(struct Client* sptr, struct StatDesc* sd, int stat, char* name) +{ + struct Client *acptr; + int i; + int wilds = 0; - /* oper only, varying # of params */ - case 'l': - case 'L': - case 'M': + if (name) + wilds = string_has_wildcards(name); + + /* + * Send info about connections which match, or all if the + * mask matches me.name. Only restrictions are on those who + * are invisible not being visible to 'foreigners' who use + * a wild card based search to list it. + */ + send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ " + "SendM SendKBytes RcveM RcveKBytes :Open since"); + for (i = 0; i <= HighestFd; i++) { - if (parc == 4) - return hunt_server_cmd(sptr, CMD_STATS, cptr, - MyUser(sptr) ? 1 : MustBeOper, "%s %C :%s", 2, - parc, parv); - else if (parc > 4) - return hunt_server_cmd(sptr, CMD_STATS, cptr, - MyUser(sptr) ? 1 : MustBeOper, "%s %C %s :%s", - 2, parc, parv); - else - return hunt_server_cmd(sptr, CMD_STATS, cptr, - MyUser(sptr) ? 1 : MustBeOper, "%s :%C", 2, - parc, parv); + if (!(acptr = LocalClientArray[i])) + continue; + /* Don't return clients when this is a request for `all' */ + if (!name && IsUser(acptr)) + continue; + /* Don't show invisible people to non opers unless they know the nick */ + if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) && + (acptr != sptr)) + continue; + /* Only show the ones that match the given mask - if any */ + if (name && wilds && match(name, cli_name(acptr))) + continue; + /* Skip all that do not match the specific query */ + if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr))) + continue; + send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, + "%s %u %u %u %u %u :%Tu", + (*(cli_name(acptr))) ? cli_name(acptr) : "", + (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr), + (int)cli_sendK(acptr), (int)cli_receiveM(acptr), + (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr)); } +} + +static void +stats_commands(struct Client* to, struct StatDesc* sd, int stat, char* param) +{ + struct Message *mptr; + + for (mptr = msgtab; mptr->cmd; mptr++) + if (mptr->count) + send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes); +} + +static void +stats_quarantine(struct Client* to, struct StatDesc* sd, int stat, char* param) +{ + struct qline *qline; + + for (qline = GlobalQuarantineList; qline; qline = qline->next) + { + if (param && match(param, qline->chname)) /* narrow search */ + continue; + send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason); + } + } + +static void +stats_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param) +{ + time_t nowr; + + nowr = CurrentTime - cli_since(&me); + send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24, + (nowr / 60) % 60, nowr % 60); + send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count); +} + +static void +stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat, + char* param) +{ + struct Client *acptr; + + /* + * lowercase 'v' is for human-readable, + * uppercase 'V' is for machine-readable + */ + if (stat == 'v') + send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, + "%-20s %-20s Flags Hops Numeric Lag RTT Up Down " + "Clients/Max Proto %-10s :Info", "Servername", "Uplink", + "LinkTS"); - /* oper only, standard # of params */ - default: - return hunt_server_cmd(sptr, CMD_STATS, cptr, - MyUser(sptr) ? 1 : MustBeOper, "%s :%C", 2, parc, - parv); + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) + { + if (!IsServer(acptr) && !IsMe(acptr)) + continue; + /* narrow search */ + if (param && match(param, cli_name(acptr))) + continue; + send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ? + "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i " + "P%-2i %Tu :%s" : + "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s", + cli_name(acptr), + cli_name(cli_serv(acptr)->up), + IsBurst(acptr) ? 'B' : '-', + IsBurstAck(acptr) ? 'A' : '-', + IsHub(acptr) ? 'H' : '-', + IsService(acptr) ? 'S' : '-', + cli_hopcount(acptr), + NumServ(acptr), + base64toint(cli_yxx(acptr)), + cli_serv(acptr)->lag, + cli_serv(acptr)->asll_rtt, + cli_serv(acptr)->asll_to, + cli_serv(acptr)->asll_from, + cli_serv(acptr)->clients, + cli_serv(acptr)->nn_mask, + cli_serv(acptr)->prot, + cli_serv(acptr)->timestamp, + cli_info(acptr)); } } +#ifdef DEBUGMODE +static void +stats_meminfo(struct Client* to, struct StatDesc* sd, int stat, char* param) +{ + class_send_meminfo(to); + send_listinfo(to, 0); +} +#endif + +static void +stats_help(struct Client* to, struct StatDesc* sd, int stat, char* param) +{ + struct StatDesc *asd; + + /* only if it's my user */ + if (MyUser(to)) + for (asd = statsinfo; asd->sd_c; asd++) + if (asd->sd_c != sd->sd_c) /* don't send the help for us */ + sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c - %s", to, asd->sd_c, + asd->sd_desc); +} + +/* This array of structures contains information about all single-character + * stats. Struct StatDesc is defined in s_stats.h. + */ +struct StatDesc statsinfo[] = { + { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c, + stats_configured_links, CONF_SERVER, + "Remote server connection lines." }, + { 'd', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_d, + stats_crule_list, 0, + "Dynamic routing configuration." }, + { 'e', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e, + stats_engine, 0, + "Report server event loop engine." }, + { 'f', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f, + feature_report, 0, + "Feature settings." }, + { 'g', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g, + gline_stats, 0, + "Global bans (G-lines)." }, + { 'h', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_h, + stats_configured_links, (CONF_HUB | CONF_LEAF), + "Hubs information." }, + { 'i', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i, + stats_access, CONF_CLIENT, + "Connection authorization lines." }, + { 'j', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_j, + msgq_histogram, 0, + "Message length histogram." }, + { 'k', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k, + stats_klines, 0, + "Local bans (K-Lines)." }, + { 'l', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_l, + stats_links, 0, + "Current connections information." }, +#if 0 + { 'M', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_M, + stats_memtotal, 0, + "Memory allocation & leak monitoring." }, +#endif + { 'm', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m, + stats_commands, 0, + "Message usage information." }, + { 'o', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o, + stats_configured_links, CONF_OPS, + "Operator information." }, + { 'p', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p, + show_ports, 0, + "Listening ports." }, + { 'q', (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q, + stats_quarantine, 0, + "Quarantined channels list." }, +#ifdef DEBUGMODE + { 'r', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_r, + send_usage, 0, + "System resource usage (Debug only)." }, +#endif + { 'T', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T, + motd_report, 0, + "Configured Message Of The Day files." }, + { 't', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t, + tstats, 0, + "Local connection statistics (Total SND/RCV, etc)." }, + { 'U', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U, + stats_configured_links, CONF_UWORLD, + "Service server & nick jupes information." }, + { 'u', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u, + stats_uptime, 0, + "Current uptime & highest connection count." }, + { 'v', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_v, + stats_servers_verbose, 0, + "Verbose server information." }, + { 'w', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w, + calc_load, 0, + "Userload statistics." }, +#ifdef DEBUGMODE + { 'x', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x, + stats_meminfo, 0, + "List usage information (Debug only)." }, +#endif + { 'y', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y, + report_classes, 0, + "Connection classes." }, + { 'z', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z, + count_memory, 0, + "Memory/Structure allocation information." }, + { '*', (STAT_FLAG_CASESENS | STAT_FLAG_VARPARAM), FEAT_LAST_F, + stats_help, 0, + "Send help for stats." }, + { '\0', 0, FEAT_LAST_F, 0, 0, 0 } +}; + +/* This array is for mapping from characters to statistics descriptors */ +struct StatDesc *statsmap[256]; + +/* Function to build the statsmap from the statsinfo array */ +void +stats_init(void) +{ + struct StatDesc *sd; + int i; + + /* Make darn sure the statsmap array is initialized to all zeros */ + for (i = 1; i < 256; i++) + statsmap[i] = 0; + + /* Build the mapping */ + for (sd = statsinfo; sd->sd_c; sd++) + { + if (sd->sd_flags & STAT_FLAG_CASESENS) + /* case sensitive character... */ + statsmap[(int)sd->sd_c] = sd; + else + { + /* case insensitive--make sure to put in two entries */ + statsmap[(int)ToLower((int)sd->sd_c)] = sd; + statsmap[(int)ToUpper((int)sd->sd_c)] = sd; + } + } +} diff --git a/ircd/s_user.c b/ircd/s_user.c index dd6b51b..9ad2b2e 100644 --- a/ircd/s_user.c +++ b/ircd/s_user.c @@ -35,7 +35,6 @@ #include "ircd_chattr.h" #include "ircd_features.h" #include "ircd_log.h" -#include "ircd_policy.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -229,7 +228,7 @@ int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok, return HUNTED_NOSUCH; } - assert(!IsServer(from)); + /* assert(!IsServer(from)); */ parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */ @@ -287,37 +286,6 @@ int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok, return (HUNTED_PASS); } -/* - * 'do_nick_name' ensures that the given parameter (nick) is really a proper - * string for a nickname (note, the 'nick' may be modified in the process...) - * - * RETURNS the length of the final NICKNAME (0, if nickname is invalid) - * - * Nickname characters are in range 'A'..'}', '_', '-', '0'..'9' - * anything outside the above set will terminate nickname. - * In addition, the first character cannot be '-' or a Digit. - * - * Note: - * The '~'-character should be allowed, but a change should be global, - * some confusion would result if only few servers allowed it... - */ -int do_nick_name(char* nick) -{ - char* ch = nick; - char* end = ch + NICKLEN; - assert(0 != ch); - - if (*ch == '-' || IsDigit(*ch)) /* first character in [0..9-] */ - return 0; - - for ( ; (ch < end) && *ch; ++ch) - if (!IsNickChar(*ch)) - break; - - *ch = '\0'; - - return (ch - nick); -} /* * clean_user_id @@ -394,6 +362,7 @@ int register_user(struct Client *cptr, struct Client *sptr, short badid = 0; short digitgroups = 0; struct User* user = cli_user(sptr); + struct Flags flag; char ip_base64[8]; user->last = CurrentTime; @@ -452,8 +421,8 @@ int register_user(struct Client *cptr, struct Client *sptr, aconf = cli_confs(sptr)->value.aconf; clean_user_id(user->username, - (cli_flags(sptr) & FLAGS_GOTID) ? cli_username(sptr) : username, - (cli_flags(sptr) & FLAGS_DOID) && !(cli_flags(sptr) & FLAGS_GOTID)); + HasFlag(sptr, FLAG_GOTID) ? cli_username(sptr) : username, + HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID)); if ((user->username[0] == '\0') || ((user->username[0] == '~') && (user->username[1] == '\000'))) @@ -541,7 +510,7 @@ int register_user(struct Client *cptr, struct Client *sptr, else if ((!lower && !upper) || !IsAlnum(c)) badid = 1; } - if (badid && (!(cli_flags(sptr) & FLAGS_GOTID) || + if (badid && (!HasFlag(sptr, FLAG_GOTID) || strcmp(cli_username(sptr), username) != 0)) { ServerStats->is_ref++; @@ -572,7 +541,11 @@ int register_user(struct Client *cptr, struct Client *sptr, cli_handler(sptr) = CLIENT_HANDLER; release_dns_reply(sptr); - send_reply(sptr, RPL_WELCOME, nick); + send_reply(sptr, + RPL_WELCOME, + feature_str(FEAT_PROVIDER) ? " via " : "", + feature_str(FEAT_PROVIDER) ? feature_str(FEAT_PROVIDER) : "", + nick); /* * This is a duplicate of the NOTICE but see below... */ @@ -586,6 +559,12 @@ int register_user(struct Client *cptr, struct Client *sptr, /* nextping = CurrentTime; */ if (cli_snomask(sptr) & SNO_NOISY) set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD); + if (feature_bool(FEAT_CONNEXIT_NOTICES)) + sendto_opmask_butone(0, SNO_CONNEXIT, + "Client connecting: %s (%s@%s) [%s] {%d}", + cli_name(sptr), user->username, user->host, + cli_sock_ip(sptr), get_client_class(sptr)); + IPcheck_connect_succeeded(sptr); } else @@ -599,11 +578,11 @@ int register_user(struct Client *cptr, struct Client *sptr, sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])", sptr, cli_name(&me), cli_name(user->server), cli_name(cli_from(acptr)), cli_sockhost(cli_from(acptr))); - cli_flags(sptr) |= FLAGS_KILLED; + SetFlag(sptr, FLAG_KILLED); return exit_client(cptr, sptr, &me, "NICK server wrong direction"); } - else - cli_flags(sptr) |= (cli_flags(acptr) & FLAGS_TS8); + else if (HasFlag(acptr, FLAG_TS8)) + SetFlag(sptr, FLAG_TS8); /* * Check to see if this user is being propogated @@ -611,11 +590,13 @@ int register_user(struct Client *cptr, struct Client *sptr, * FIXME: This can be speeded up - its stupid to check it for * every NICK message in a burst again --Run. */ - for (acptr = user->server; acptr != &me; acptr = cli_serv(acptr)->up) { + for (acptr = user->server; acptr != &me; acptr = cli_serv(acptr)->up) + { if (IsBurst(acptr) || Protocol(acptr) < 10) break; } - if (!IPcheck_remote_connect(sptr, (acptr != &me))) { + if (!IPcheck_remote_connect(sptr, (acptr != &me))) + { /* * We ran out of bits to count this */ @@ -636,8 +617,8 @@ int register_user(struct Client *cptr, struct Client *sptr, /* Send umode to client */ if (MyUser(sptr)) { - send_umode(cptr, sptr, 0, ALL_UMODES); - if (cli_snomask(sptr) != SNO_DEFAULT && (cli_flags(sptr) & FLAGS_SERVNOTICE)) + send_umode(cptr, sptr, &flag, ALL_UMODES); + if (cli_snomask(sptr) != SNO_DEFAULT && HasFlag(sptr, FLAG_SERVNOTICE)) send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr)); } @@ -649,16 +630,16 @@ static const struct UserMode { unsigned int flag; char c; } userModeList[] = { - { FLAGS_OPER, 'o' }, - { FLAGS_LOCOP, 'O' }, - { FLAGS_INVISIBLE, 'i' }, - { FLAGS_WALLOP, 'w' }, - { FLAGS_SERVNOTICE, 's' }, - { FLAGS_DEAF, 'd' }, - { FLAGS_CHSERV, 'k' }, - { FLAGS_DEBUG, 'g' }, - { FLAGS_ACCOUNT, 'r' }, - { FLAGS_HIDDENHOST, 'x' } + { FLAG_OPER, 'o' }, + { FLAG_LOCOP, 'O' }, + { FLAG_INVISIBLE, 'i' }, + { FLAG_WALLOP, 'w' }, + { FLAG_SERVNOTICE, 's' }, + { FLAG_DEAF, 'd' }, + { FLAG_CHSERV, 'k' }, + { FLAG_DEBUG, 'g' }, + { FLAG_ACCOUNT, 'r' }, + { FLAG_HIDDENHOST, 'x' } }; #define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode) @@ -684,12 +665,16 @@ int set_nick_name(struct Client* cptr, struct Client* sptr, cli_hopcount(new_client) = atoi(parv[2]); cli_lastnick(new_client) = atoi(parv[3]); - if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+') { - for (p = parv[6] + 1; *p; p++) { - for (i = 0; i < USERMODELIST_SIZE; ++i) { - if (userModeList[i].c == *p) { - cli_flags(new_client) |= userModeList[i].flag; - if (userModeList[i].flag & FLAGS_ACCOUNT) + if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+') + { + for (p = parv[6] + 1; *p; p++) + { + for (i = 0; i < USERMODELIST_SIZE; ++i) + { + if (userModeList[i].c == *p) + { + SetFlag(new_client, userModeList[i].flag); + if (userModeList[i].flag == FLAG_ACCOUNT) account = parv[7]; break; } @@ -747,7 +732,8 @@ int set_nick_name(struct Client* cptr, struct Client* sptr, * however, allow to do two nick changes immediately after another * before limiting the nick flood. -Run */ - if (CurrentTime < cli_nextnick(cptr)) { + if (CurrentTime < cli_nextnick(cptr)) + { cli_nextnick(cptr) += 2; send_reply(cptr, ERR_NICKTOOFAST, parv[1], cli_nextnick(cptr) - CurrentTime); @@ -840,7 +826,8 @@ static unsigned char hash_target(unsigned int target) * * Cannonifies target for client `sptr'. */ -void add_target(struct Client *sptr, void *target) +void +add_target(struct Client *sptr, void *target) { /* Ok, this shouldn't work esp on alpha */ @@ -851,6 +838,9 @@ void add_target(struct Client *sptr, void *target) assert(cli_local(sptr)); targets = cli_targets(sptr); + + if (IsChannelName(cli_name(sptr)) && IsInvited(sptr, target)) + return; /* * Already in table? */ @@ -1000,15 +990,16 @@ int whisper(struct Client* source, const char* nick, const char* channel, /* * added Sat Jul 25 07:30:42 EST 1992 */ -void send_umode_out(struct Client *cptr, struct Client *sptr, int old, - int prop) +void send_umode_out(struct Client *cptr, struct Client *sptr, + struct Flags *old, int prop) { int i; struct Client *acptr; - send_umode(NULL, sptr, old, SEND_UMODES & ~(prop ? 0 : FLAGS_OPER)); + send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER); - for (i = HighestFd; i >= 0; i--) { + for (i = HighestFd; i >= 0; i--) + { if ((acptr = LocalClientArray[i]) && IsServer(acptr) && (acptr != cptr) && (acptr != sptr) && *umodeBuf) sendcmdto_one(sptr, CMD_MODE, acptr, "%s :%s", cli_name(sptr), umodeBuf); @@ -1058,45 +1049,42 @@ void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt * set, its hostmask is changed. */ #define FLAGS_HOST_HIDDEN (FLAGS_ACCOUNT|FLAGS_HIDDENHOST) -int hide_hostmask(struct Client *cptr, unsigned int flags) +int +hide_hostmask(struct Client *cptr, unsigned int flag) { struct Membership *chan; - int newflags; - - if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING)) - flags &= ~FLAGS_HIDDENHOST; - - newflags = cli_flags(cptr) | flags; - if ((newflags & FLAGS_HOST_HIDDEN) != FLAGS_HOST_HIDDEN) { - /* The user doesn't have both flags, don't change the hostmask */ - cli_flags(cptr) |= flags; + + if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING) && + flag == FLAG_HIDDENHOST) + return 0; + + SetFlag(cptr, flag); + if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT)) return 0; - } sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered"); ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s", - cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST)); - cli_flags(cptr) |= flags; + cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST)); /* * Go through all channels the client was on, rejoin him * and set the modes, if any */ - for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) { + for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) + { sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, - "%H", chan->channel); - if (IsChanOp(chan) && HasVoice(chan)) { + "%H", chan->channel); + if (IsChanOp(chan) && HasVoice(chan)) sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, - "%H +ov %C %C", chan->channel, cptr, cptr); - } else if (IsChanOp(chan) || HasVoice(chan)) { + "%H +ov %C %C", chan->channel, cptr, + cptr); + else if (IsChanOp(chan) || HasVoice(chan)) sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr); - } } return 0; } - /* * set_user_mode() added 15/10/91 By Darren Reed. * @@ -1111,7 +1099,7 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv struct Client *acptr; int what; int i; - int setflags; + struct Flags setflags; unsigned int tmpmask = 0; int snomask_given = 0; char buf[BUFSIZE]; @@ -1145,14 +1133,15 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv { m = buf; *m++ = '+'; - for (i = 0; i < USERMODELIST_SIZE; ++i) { - if ((userModeList[i].flag & cli_flags(sptr)) && - !(userModeList[i].flag & FLAGS_ACCOUNT)) + for (i = 0; i < USERMODELIST_SIZE; i++) + { + if (HasFlag(sptr, userModeList[i].flag) && + userModeList[i].flag != FLAG_ACCOUNT) *m++ = userModeList[i].c; } *m = '\0'; send_reply(sptr, RPL_UMODEIS, buf); - if ((cli_flags(sptr) & FLAGS_SERVNOTICE) && MyConnect(sptr) + if (HasFlag(sptr, FLAG_SERVNOTICE) && MyConnect(sptr) && cli_snomask(sptr) != (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT)) send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr)); @@ -1204,8 +1193,10 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv if (what == MODE_ADD) SetOper(sptr); else { - cli_flags(sptr) &= ~(FLAGS_OPER | FLAGS_LOCOP); - if (MyConnect(sptr)) { + ClrFlag(sptr, FLAG_OPER); + ClrFlag(sptr, FLAG_LOCOP); + if (MyConnect(sptr)) + { tmpmask = cli_snomask(sptr) & ~SNO_OPER; cli_handler(sptr) = CLIENT_HANDLER; } @@ -1214,9 +1205,12 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv case 'O': if (what == MODE_ADD) SetLocOp(sptr); - else { - cli_flags(sptr) &= ~(FLAGS_OPER | FLAGS_LOCOP); - if (MyConnect(sptr)) { + else + { + ClrFlag(sptr, FLAG_OPER); + ClrFlag(sptr, FLAG_LOCOP); + if (MyConnect(sptr)) + { tmpmask = cli_snomask(sptr) & ~SNO_OPER; cli_handler(sptr) = CLIENT_HANDLER; } @@ -1259,67 +1253,75 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv * Evaluate rules for new user mode * Stop users making themselves operators too easily: */ - if (!IsServer(cptr)) { - if (!(setflags & FLAGS_OPER) && IsOper(sptr)) + if (!IsServer(cptr)) + { + if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) ClearOper(sptr); - if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr)) + if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr)) ClearLocOp(sptr); /* * new umode; servers can set it, local users cannot; * prevents users from /kick'ing or /mode -o'ing */ - if (!(setflags & FLAGS_CHSERV)) + if (!FlagHas(&setflags, FLAG_CHSERV)) ClearChannelService(sptr); /* * only send wallops to opers */ if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(sptr) && - !(setflags & FLAGS_WALLOP)) + !FlagHas(&setflags, FLAG_WALLOP)) ClearWallops(sptr); -#ifdef SERVNOTICE_OPER_ONLY - if (MyConnect(sptr) && !IsAnOper(sptr) && !(setflags & FLAGS_SERVNOTICE)) { + if (feature_bool(FEAT_HIS_SNOTICES_OPER_ONLY) && MyConnect(sptr) && + !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_SERVNOTICE)) + { ClearServNotice(sptr); set_snomask(sptr, 0, SNO_SET); } -#endif -#ifdef DEBUG_OPER_ONLY - if (!IsAnOper(sptr) && !(setflags & FLAGS_DEBUG)) + if (feature_bool(FEAT_HIS_DEBUG_OPER_ONLY) && + !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_DEBUG)) ClearDebug(sptr); -#endif } - if (MyConnect(sptr)) { - if ((setflags & (FLAGS_OPER | FLAGS_LOCOP)) && !IsAnOper(sptr)) + if (MyConnect(sptr)) + { + if (FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPS); - if (SendServNotice(sptr)) { + if (SendServNotice(sptr)) + { if (tmpmask != cli_snomask(sptr)) set_snomask(sptr, tmpmask, SNO_SET); if (cli_snomask(sptr) && snomask_given) send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr)); - } else + } + else set_snomask(sptr, 0, SNO_SET); } /* * Compare new flags with old flags and send string which * will cause servers to update correctly. */ - if (!(setflags & FLAGS_OPER) && IsOper(sptr)) { /* user now oper */ + if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) + { + /* user now oper */ ++UserStats.opers; client_set_privs(sptr, NULL); } - if (HasPriv(sptr, PRIV_PROPAGATE)) /* remember propagate privilege setting */ + /* remember propagate privilege setting */ + if (HasPriv(sptr, PRIV_PROPAGATE)) prop = 1; - if ((setflags & FLAGS_OPER) && !IsOper(sptr)) { /* user no longer oper */ + if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) + { + /* user no longer oper */ --UserStats.opers; client_set_privs(sptr, NULL); /* will clear propagate privilege */ } - if ((setflags & FLAGS_INVISIBLE) && !IsInvisible(sptr)) + if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) --UserStats.inv_clients; - if (!(setflags & FLAGS_INVISIBLE) && IsInvisible(sptr)) + if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) ++UserStats.inv_clients; - if (!(setflags & FLAGS_HIDDENHOST) && do_host_hiding) - hide_hostmask(sptr, FLAGS_HIDDENHOST); - send_umode_out(cptr, sptr, setflags, prop); + if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding) + hide_hostmask(sptr, FLAG_HIDDENHOST); + send_umode_out(cptr, sptr, &setflags, prop); return 0; } @@ -1330,22 +1332,25 @@ int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv */ char *umode_str(struct Client *cptr) { - char* m = umodeBuf; /* Maximum string size: "owidg\0" */ - int i; - int c_flags; + /* Maximum string size: "owidgrx\0" */ + char *m = umodeBuf; + int i; + struct Flags c_flags; - c_flags = cli_flags(cptr) & SEND_UMODES; /* cleaning up the original code */ if (HasPriv(cptr, PRIV_PROPAGATE)) - c_flags |= FLAGS_OPER; + FlagSet(&c_flags, FLAG_OPER); else - c_flags &= ~FLAGS_OPER; + FlagClr(&c_flags, FLAG_OPER); - for (i = 0; i < USERMODELIST_SIZE; ++i) { - if ( (c_flags & userModeList[i].flag)) + for (i = 0; i < USERMODELIST_SIZE; ++i) + { + if (FlagHas(&c_flags, userModeList[i].flag) && + userModeList[i].flag >= FLAG_GLOBAL_UMODES) *m++ = userModeList[i].c; } - if (IsAccount(cptr)) { + if (IsAccount(cptr)) + { char* t = cli_user(cptr)->account; *m++ = ' '; @@ -1363,7 +1368,8 @@ char *umode_str(struct Client *cptr) * Send the MODE string for user (user) to connection cptr * -avalon */ -void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask) +void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old, + int sendset) { int i; int flag; @@ -1372,15 +1378,31 @@ void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask) /* * Build a string in umodeBuf to represent the change in the user's - * mode between the new (sptr->flag) and 'old'. + * mode between the new (cli_flags(sptr)) and 'old', but skipping + * the modes indicated by sendset. */ m = umodeBuf; *m = '\0'; - for (i = 0; i < USERMODELIST_SIZE; ++i) { + for (i = 0; i < USERMODELIST_SIZE; ++i) + { flag = userModeList[i].flag; - if (MyUser(sptr) && !(flag & sendmask)) + if (FlagHas(old, flag) + == HasFlag(sptr, flag)) continue; - if ( (flag & old) && !(cli_flags(sptr) & flag)) + switch (sendset) + { + case ALL_UMODES: + break; + case SEND_UMODES_BUT_OPER: + if (flag == FLAG_OPER) + continue; + /* and fall through */ + case SEND_UMODES: + if (flag < FLAG_GLOBAL_UMODES) + continue; + break; + } + if (FlagHas(old, flag)) { if (what == MODE_DEL) *m++ = userModeList[i].c; @@ -1391,7 +1413,7 @@ void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask) *m++ = userModeList[i].c; } } - else if (!(flag & old) && (cli_flags(sptr) & flag)) + else /* !FlagHas(old, flag) */ { if (what == MODE_ADD) *m++ = userModeList[i].c; diff --git a/ircd/send.c b/ircd/send.c index 2ba06e4..4d562b7 100644 --- a/ircd/send.c +++ b/ircd/send.c @@ -26,7 +26,7 @@ #include "class.h" #include "client.h" #include "ircd.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_snprintf.h" #include "ircd_string.h" #include "list.h" @@ -57,7 +57,7 @@ static struct Connection *send_queues = 0; * * An error has been detected. The link *must* be closed, * but *cannot* call ExitClient (m_bye) from here. - * Instead, mark it with FLAGS_DEADSOCKET. This should + * Instead, mark it with FLAG_DEADSOCKET. This should * generate ExitClient from the main loop. * * If 'notice' is not NULL, it is assumed to be a format @@ -71,7 +71,7 @@ static struct Connection *send_queues = 0; static void dead_link(struct Client *to, char *notice) { - cli_flags(to) |= FLAGS_DEADSOCKET; + SetFlag(to, FLAG_DEADSOCKET); /* * If because of BUFFERPOOL problem then clean dbuf's now so that * notices don't hurt operators below. @@ -85,7 +85,7 @@ static void dead_link(struct Client *to, char *notice) */ ircd_strncpy(cli_info(to), notice, REALLEN); - if (!IsUser(to) && !IsUnknown(to) && !(cli_flags(to) & FLAGS_CLOSING)) + if (!IsUser(to) && !IsUnknown(to) && !HasFlag(to, FLAG_CLOSING)) sendto_opmask_butone(0, SNO_OLDSNO, "%s for %s", cli_info(to), cli_name(to)); Debug((DEBUG_ERROR, cli_info(to))); } @@ -96,6 +96,33 @@ static int can_send(struct Client* to) return (IsDead(to) || IsMe(to) || -1 == cli_fd(to)) ? 0 : 1; } +/* This helper routine kills the connection with the highest sendq, to + * try to free up some buffer memory. + */ +void +kill_highest_sendq(int servers_too) +{ + int i; + unsigned int highest_sendq = 0; + struct Client *highest_client = 0; + + for (i = HighestFd; i >= 0; i--) + { + if (!LocalClientArray[i] || (!servers_too && cli_serv(LocalClientArray[i]))) + continue; /* skip servers */ + + /* If this sendq is higher than one we last saw, remember it */ + if (MsgQLength(&(cli_sendQ(LocalClientArray[i]))) > highest_sendq) + { + highest_client = LocalClientArray[i]; + highest_sendq = MsgQLength(&(cli_sendQ(highest_client))); + } + } + + if (highest_client) + dead_link(highest_client, "Buffer allocation error"); +} + /* * flush_connections * @@ -456,8 +483,8 @@ void sendcmdto_channel_butone(struct Client *from, const char *cmd, /* Build buffer to send to users */ va_start(vd.vd_args, pattern); - user_mb = msgq_make(0, skip & SKIP_NONOPS ? "%:#C %s @%v" : "%:#C %s %v", - from, skip & SKIP_NONOPS ? MSG_NOTICE : cmd, &vd); + user_mb = msgq_make(0, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? "%:#C %s @%v" : "%:#C %s %v", + from, skip & (SKIP_NONOPS | SKIP_NONVOICES) ? MSG_NOTICE : cmd, &vd); va_end(vd.vd_args); /* Build buffer to send to servers */ @@ -470,11 +497,12 @@ void sendcmdto_channel_butone(struct Client *from, const char *cmd, for (member = to->members; member; member = member->next_member) { /* skip one, zombies, and deaf users... */ if (cli_from(member->user) == one || IsZombie(member) || - (skip & SKIP_DEAF && IsDeaf(member->user)) || - (skip & SKIP_NONOPS && !IsChanOp(member)) || - (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || - cli_fd(cli_from(member->user)) < 0 || - sentalong[cli_fd(cli_from(member->user))] == sentalong_marker) + (skip & SKIP_DEAF && IsDeaf(member->user)) || + (skip & SKIP_NONOPS && !IsChanOp(member)) || + (skip & SKIP_NONVOICES && !IsChanOp(member) && !HasVoice(member)) || + (skip & SKIP_BURST && IsBurstOrBurstAck(cli_from(member->user))) || + cli_fd(cli_from(member->user)) < 0 || + sentalong[cli_fd(cli_from(member->user))] == sentalong_marker) continue; sentalong[cli_fd(cli_from(member->user))] = sentalong_marker; @@ -527,17 +555,15 @@ void sendwallto_group_butone(struct Client *from, int type, struct Client *one, va_end(vd.vd_args); /* send buffer along! */ - for (i = 0; i <= HighestFd; i++) { + for (i = 0; i <= HighestFd; i++) + { if (!(cptr = LocalClientArray[i]) || (cli_fd(cli_from(cptr)) < 0) || - (type == WALL_DESYNCH && !(cli_flags(cptr) & FLAGS_DEBUG)) || -#ifdef HEAD_IN_SAND_WALLOPS - (type == WALL_WALLOPS && (!(cli_flags(cptr) & FLAGS_WALLOP) || - !IsAnOper(cptr))) || -#else - (type == WALL_WALLOPS && !(cli_flags(cptr) & FLAGS_WALLOP)) || -#endif - (type == WALL_WALLUSERS && !(cli_flags(cptr) & FLAGS_WALLOP))) + (type == WALL_DESYNCH && !HasFlag(cptr, FLAG_DEBUG)) || + (type == WALL_WALLOPS && + (!HasFlag(cptr, FLAG_WALLOP) || (feature_bool(FEAT_HIS_WALLOPS) && + !IsAnOper(cptr)))) || + (type == WALL_WALLUSERS && !HasFlag(cptr, FLAG_WALLOP))) continue; /* skip it */ send_buffer(cptr, mb, 1); } @@ -680,7 +706,8 @@ void vsendto_opmask_butone(struct Client *one, unsigned int mask, &vd); for (; opslist; opslist = opslist->next) - send_buffer(opslist->value.cptr, mb, 0); + if (opslist->value.cptr != one) + send_buffer(opslist->value.cptr, mb, 0); msgq_clean(mb); } diff --git a/ircd/userload.c b/ircd/userload.c index 84d6a9c..ae05bf2 100644 --- a/ircd/userload.c +++ b/ircd/userload.c @@ -34,6 +34,7 @@ #include "numnicks.h" #include "querycmds.h" #include "s_misc.h" +#include "s_stats.h" #include "send.h" #include "struct.h" #include "sys.h" @@ -200,7 +201,8 @@ void update_load(void) last = CurrentTime; } -void calc_load(struct Client *sptr) +void +calc_load(struct Client *sptr, struct StatDesc *sd, int stat, char *param) { /* *INDENT-OFF* */ static const char *header = diff --git a/ircd/whocmds.c b/ircd/whocmds.c index fa8def4..e90ec21 100644 --- a/ircd/whocmds.c +++ b/ircd/whocmds.c @@ -30,7 +30,7 @@ #include "hash.h" #include "ircd.h" #include "ircd_chattr.h" -#include "ircd_policy.h" +#include "ircd_features.h" #include "ircd_reply.h" #include "ircd_snprintf.h" #include "ircd_string.h" @@ -138,15 +138,9 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan, if (!fields || (fields & WHO_FIELD_SER)) { - char *p2; -#ifdef HEAD_IN_SAND_WHO_SERVERNAME - if (IsAnOper(sptr)) -#endif - p2 = cli_name(cli_user(acptr)->server); -#ifdef HEAD_IN_SAND_WHO_SERVERNAME - else - p2 = HEAD_IN_SAND_SERVERNAME; -#endif + const char *p2 = (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) ? + feature_str(FEAT_HIS_SERVERNAME) : + cli_name(cli_user(acptr)->server); *(p1++) = ' '; while ((*p2) && (*(p1++) = *(p2++))); } @@ -208,24 +202,31 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan, *p1++ = ' '; if (!fields) *p1++ = ':'; /* Place colon here for default reply */ -#ifdef HEAD_IN_SAND_WHO_HOPCOUNT - *p1++ = (sptr == acptr) ? '0' : '3'; -#else - /* three digit hopcount maximum */ - p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr)); -#endif + if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr)) + *p1++ = (sptr == acptr) ? '0' : '3'; + else + /* three digit hopcount maximum */ + p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr)); } if (fields & WHO_FIELD_IDL) { *p1++ = ' '; - if (MyUser(acptr)) { - p1 += ircd_snprintf(0, p1, 11, "%d", - CurrentTime - cli_user(acptr)->last); - } - else { - *p1++ = '0'; - } + if (MyUser(acptr)) + p1 += ircd_snprintf(0, p1, 11, "%d", + CurrentTime - cli_user(acptr)->last); + else + *p1++ = '0'; + } + + if (fields & WHO_FIELD_ACC) + { + char *p2 = cli_user(acptr)->account; + *(p1++) = ' '; + if (*p2) + while ((*p2) && (*(p1++) = *(p2++))); + else + *(p1++) = '0'; } if (!fields || (fields & WHO_FIELD_REN)) -- 2.20.1