1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-30 23:06:39 +02:00
Files
unrealircd/src/s_serv.c
T
2000-07-16 20:37:15 +00:00

4827 lines
115 KiB
C

/*
* Unreal Internet Relay Chat Daemon, src/s_serv.c
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Computing Center
*
* 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.
*/
#ifndef lint
static char sccsid[] =
"@(#)s_serv.c 2.55 2/7/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "userload.h"
#include "version.h"
#if defined(PCS) || defined(AIX) || defined(SVR3)
#include <time.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>
#ifndef _WIN32
#include <utmp.h>
#else
#include <io.h>
#endif
#include <time.h>
#include "h.h"
ID_CVS("$Id$");
static char buf[BUFSIZE];
int max_connection_count = 1, max_client_count = 1;
extern ircstats IRCstats;
extern int do_garbage_collect;
/* We need all these for cached MOTDs -- codemastr */
aMotd *opermotd;
aMotd *rules;
aMotd *motd;
aMotd *svsmotd;
aMotd *botmotd;
aTrecord *tdata;
struct tm *motd_tm;
aMotd *read_opermotd(char *filename);
aMotd *read_motd(char *filename);
aMotd *read_rules(char *filename);
aMotd *read_svsmotd(char *filename);
aMotd *read_botmotd(char *filename);
void read_tlines(void);
/*
** 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.
*/
#ifndef NO_FDLIST
extern fdlist serv_fdlist;
#endif
/*
** m_version
** parv[0] = sender prefix
** parv[1] = remote server
*/
int m_version(cptr, sptr, parc, parv)
aClient *sptr, *cptr;
int parc;
char *parv[];
{
extern char serveropts[];
char *x;
if (TRUEHUB == 1)
x = "(H)";
else
x = "";
if (hunt_server(cptr, sptr, ":%s VERSION :%s", 1, parc,
parv) == HUNTED_ISME)
sendto_one(sptr, rpl_str(RPL_VERSION), me.name,
parv[0], version, ircnetwork, debugmode, me.name,
serveropts,
(IsAnOper(sptr) ? MYOSNAME : "*"), UnrealProtocol, x);
return 0;
}
/*int IsMe (acptr)
aClient *acptr, server;
{
if (memcmp (acptr, server, sizeof(aClient)) == 0)
return 1;
return 0;
}*/
/*
** m_squit
** parv[0] = sender prefix
** parv[1] = server name
** parv[parc-1] = comment
*/
int m_squit(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aConfItem *aconf;
char *server;
aClient *acptr;
char *comment = (parc > 2 && parv[parc - 1]) ?
parv[parc - 1] : cptr->name;
if (!IsPrivileged(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc > 1)
{
server = parv[1];
/*
** To accomodate host masking, a squit for a masked server
** name is expanded if the incoming mask is the same as
** the server name for that link to the name of link.
*/
while ((*server == '*') && IsServer(cptr))
{
aconf = cptr->serv->nline;
if (!aconf)
break;
if (!mycmp(server, my_name_for_link(me.name, aconf)))
server = cptr->name;
break; /* WARNING is normal here */
}
/*
** The following allows wild cards in SQUIT. Only usefull
** when the command is issued by an oper.
*/
for (acptr = client; (acptr = next_client(acptr, server));
acptr = acptr->next)
if (IsServer(acptr) || IsMe(acptr))
break;
if (acptr && IsMe(acptr))
{
acptr = cptr;
server = cptr->sockhost;
}
}
else
{
/*
** This is actually protocol error. But, well, closing
** the link is very proper answer to that...
*/
server = cptr->sockhost;
acptr = cptr;
}
/*
** SQUIT semantics is tricky, be careful...
**
** The old (irc2.2PL1 and earlier) code just cleans away the
** server client from the links (because it is never true
** "cptr == acptr".
**
** This logic here works the same way until "SQUIT host" hits
** the server having the target "host" as local link. Then it
** will do a real cleanup spewing SQUIT's and QUIT's to all
** directions, also to the link from which the orinal SQUIT
** came, generating one unnecessary "SQUIT host" back to that
** link.
**
** One may think that this could be implemented like
** "hunt_server" (e.g. just pass on "SQUIT" without doing
** nothing until the server having the link as local is
** reached). Unfortunately this wouldn't work in the real life,
** because either target may be unreachable or may not comply
** with the request. In either case it would leave target in
** links--no command to clear it away. So, it's better just
** clean out while going forward, just to be sure.
**
** ...of course, even better cleanout would be to QUIT/SQUIT
** dependant users/servers already on the way out, but
** currently there is not enough information about remote
** clients to do this... --msa
*/
if (!acptr)
{
sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
me.name, parv[0], server);
return 0;
}
if (MyClient(sptr) && ((!OPCanGRoute(sptr) && !MyConnect(acptr)) ||
(!OPCanLRoute(sptr) && MyConnect(acptr))))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
/*
** Notify all opers, if my local link is remotely squitted
*/
if (MyConnect(acptr) && !IsAnOper(cptr))
{
sendto_locfailops("Received SQUIT %s from %s (%s)",
acptr->name, get_client_name(sptr, FALSE), comment);
sendto_serv_butone(&me,
":%s GLOBOPS :Received SQUIT %s from %s (%s)", me.name,
server, get_client_name(sptr, FALSE), comment);
#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
syslog(LOG_DEBUG, "SQUIT From %s : %s (%s)",
parv[0], server, comment);
#endif
}
else if (MyConnect(acptr))
{
if (acptr->user)
{
sendto_one(sptr,
":%s NOTICE :*** Cannot do fake kill by SQUIT !!!",
me.name);
sendto_ops
("%s tried to do a fake kill using SQUIT (%s (%s))",
sptr->name, acptr->name, comment);
sendto_serv_butone(&me,
":%s GLOBOPS :%s tried to fake kill using SQUIT (%s (%s))",
me.name, sptr->name, acptr->name, comment);
return 0;
}
sendto_locfailops("Received SQUIT %s from %s (%s)",
acptr->name, get_client_name(sptr, FALSE), comment);
sendto_serv_butone(&me,
":%s GLOBOPS :Received SQUIT %s from %s (%s)", me.name,
acptr->name, get_client_name(sptr, FALSE), comment);
}
if (IsAnOper(sptr))
{
/*
* It was manually /squit'ed by a human being(we hope),
* there is a very good chance they don't want us to
* reconnect right away. -Cabal95
*/
acptr->flags |= FLAGS_SQUIT;
}
return exit_client(cptr, acptr, sptr, comment);
}
/*
* m_protoctl
* parv[0] = Sender prefix
* parv[1+] = Options
*/
int m_protoctl(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int i;
#ifndef PROTOCTL_MADNESS
int remove = 0;
#endif
char proto[128], *s;
/* static char *dummyblank = ""; Yes, it is kind of ugly */
#ifdef PROTOCTL_MADNESS
if (GotProtoctl(sptr))
{
/*
* But we already GOT a protoctl msg!
*/
if (!IsServer(sptr))
sendto_one(cptr,
"ERROR :Already got a PROTOCTL from you.");
return 0;
}
#endif
cptr->flags |= FLAGS_PROTOCTL;
/* parv[parc - 1] */
for (i = 1; i < parc; i++)
{
strncpy(proto, parv[i], 127);
proto[127] = '\0'; /* Just to be safe... */
s = proto;
#ifndef PROTOCTL_MADNESS
if (*s == '-') {
s++;
remove = 1;
}
else
remove = 0;
#endif
/* equal = (char *)index(proto, '=');
if (equal == NULL)
options = dummyblank;
else
{
options = &equal[1];
equal[0] = '\0';
}
*/
if (strcmp(s, "NOQUIT") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearNoQuit(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetNoQuit(cptr);
}
else if (strcmp(s, "TOKEN") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearToken(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetToken(cptr);
}
else if (strcmp(s, "HCN") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearHybNotice(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetHybNotice(cptr);
}
else if (strcmp(s, "SJOIN") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearSJOIN(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetSJOIN(cptr);
}
else if (strcmp(s, "SJOIN2") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearSJOIN2(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetSJOIN2(cptr);
}
else if (strcmp(s, "NICKv2") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearNICKv2(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR, "Chose protocol %s for link %s",
proto, cptr->name));
SetNICKv2(cptr);
}
else if (strcmp(s, "UMODE2") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearUMODE2(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR,
"Chose protocol %s for link %s",
proto, cptr->name));
SetUMODE2(cptr);
}
else if (strcmp(s, "ALN") == 0)
{
#ifdef PROTOCTL_MADNESS
if (remove) {
ClearALN(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR,
"Chose protocol %s for link %s",
proto, cptr->name));
SetALN(cptr);
}
else if (strcmp(s, "VL") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearVL(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR,
"Chose protocol %s for link %s",
proto, cptr->name));
SetVL(cptr);
}
else if (strcmp(s, "VHP") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearVHP(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR,
"Chose protocol %s for link %s",
proto, cptr->name));
SetVHP(cptr);
}
else if (strcmp(s, "SJ3") == 0)
{
#ifndef PROTOCTL_MADNESS
if (remove) {
ClearSJ3(cptr);
continue;
}
#endif
Debug((DEBUG_ERROR,
"Chose protocol %s for link %s",
proto, cptr->name));
SetSJ3(cptr);
}
/*
* Add other protocol extensions here, with proto
* containing the base option, and options containing
* what it equals, if anything.
*
* DO NOT error or warn on unknown proto; we just don't
* support it.
*/
}
return 0;
}
/*
** m_server
** parv[0] = sender prefix
** parv[1] = servername
** parv[2] = serverinfo/hopcount
** parv[3] = serverinfo
*/
int m_server(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *ch;
int i;
char info[REALLEN + 1], *inpath, *host, *encr, *f;
char pp[512];
aClient *acptr, *bcptr;
aConfItem *aconf, *cconf;
int hop, ts = 0;
char *parvaln, *flags, *protocol, *inf;
info[0] = '\0';
inpath = get_client_name(cptr, FALSE);
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(cptr, "ERROR :No servername");
return 0;
}
hop = 0;
host = parv[1];
if (parc > 4)
{
ts = atoi(parv[3]);
hop = atoi(parv[2]);
(void)strncpy(info, parv[4], REALLEN);
info[REALLEN] = '\0';
}
else if (parc > 3 && atoi(parv[2]))
{
hop = atoi(parv[2]);
(void)strncpy(info, parv[3], REALLEN);
info[REALLEN] = '\0';
}
else if (parc > 2)
{
(void)strncpy(info, parv[2], REALLEN);
if (parc > 3 && ((i = strlen(info)) < (REALLEN - 2)))
{
(void)strcat(info, " ");
(void)strncat(info, parv[3], REALLEN - i - 2);
info[REALLEN] = '\0';
}
}
/*
** Check for "FRENCH " infection ;-) (actually this should
** be replaced with routine to check the hostname syntax in
** general). [ This check is still needed, even after the parse
** is fixed, because someone can send "SERVER :foo bar " ].
** Also, changed to check other "difficult" characters, now
** that parse lets all through... --msa
*/
if (strlen(host) > HOSTLEN)
host[HOSTLEN] = '\0';
for (ch = host; *ch; ch++)
if (*ch <= ' ' || *ch > '~')
break;
if (*ch || !index(host, '.'))
{
sendto_one(sptr, "ERROR :Bogus server name (%s)",
sptr->name, host);
sendto_ops
("WARNING: Bogus server name (%s) from %s (maybe just a fishy client)",
host, get_client_name(cptr, TRUE));
sptr->since += 7;
return 0;
}
if (IsPerson(cptr))
{
/*
** A local link that has been identified as a USER
** tries something fishy... ;-)
*/
sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
me.name, parv[0]);
sendto_one(cptr,
":%s NOTICE %s :Sorry, but your IRC program doesn't appear to support changing servers.",
me.name, cptr->name);
/* sendto_ops("User %s trying to become a server %s",
get_client_name(cptr, TRUE),host);
*/
sptr->since += 7;
return 0;
}
/* *WHEN* can it be that "cptr != sptr" ????? --msa */
/* When SERVER command (like now) has prefix. -avalon */
/* take a prepeek at the password.. */
if (IsUnknown(cptr))
{
aconf = find_conf_servern(host);
if (!aconf)
{
sendto_one(cptr,"ERROR :No Access (No matching N:line) %s",
inpath);
sendto_locfailops("Access denied (No matching N:line) %s",
inpath);
return exit_client(cptr, cptr, cptr, "No matching N:line");
}
#ifdef CRYPT_LINK_PASSWORD
/* use first two chars of the password they send in as salt */
/* passwd may be NULL. Head it off at the pass... */
if (*cptr->passwd)
{
char salt[3];
extern char *crypt();
salt[0] = aconf->passwd[0];
salt[1] = aconf->passwd[1];
salt[2] = '\0';
encr = crypt(cptr->passwd, salt);
}
else
encr = "";
#else
encr = cptr->passwd;
#endif /* CRYPT_LINK_PASSWORD */
if (*aconf->passwd && !StrEq(aconf->passwd, encr))
{
sendto_one(cptr,
"ERROR :No Access (passwd mismatch) %s", inpath);
sendto_locfailops("Access denied (passwd mismatch) %s",
inpath);
return exit_client(cptr, cptr, cptr, "Bad Password");
}
/* bzero(cptr->passwd, sizeof(cptr->passwd)); */
}
f = (char *) does_servername_collide(parv[1]);
if (f)
{
ircsprintf(pp, "Servername %s collides with servername %s (similar hash). Change servername in some way (maybe change case)",
parv[1], f);
sendto_realops("Link %s cancelled - %s", inpath, pp);
return exit_client(cptr, cptr, cptr, pp);
}
if ((acptr = find_name(host, NULL)))
{
aClient *ocptr;
/*
* This link is trying feed me a server that I already have
* access through another path -- multiple paths not accepted
* currently, kill this link immeatedly!!
*
* Rather than KILL the link which introduced it, KILL the
* youngest of the two links. -avalon
*/
acptr = acptr->from;
ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr;
acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr;
sendto_one(acptr, "ERROR :Server %s already exists from %s",
host, (ocptr->from ? ocptr->from->name : "<nobody>"));
sendto_ops
("Link %s cancelled, server %s already exists from %s",
get_client_name(acptr, TRUE), host,
(ocptr->from ? ocptr->from->name : "<nobody>"));
return exit_client(acptr, acptr, acptr, "Server Exists");
}
if ((acptr = find_client(host, NULL)))
{
/*
** Server trying to use the same name as a person. Would
** cause a fair bit of confusion. Enough to make it hellish
** for a while and servers to send stuff to the wrong place.
*/
sendto_one(cptr, "ERROR :Nickname %s already exists!", host);
sendto_locfailops
("Link %s cancelled: Server/nick collision on %s", inpath,
host);
sendto_serv_butone(&me,
":%s GLOBOPS : Link %s cancelled: Server/nick collision on %s",
parv[0], inpath, host);
return exit_client(cptr, cptr, cptr, "Nick as Server");
}
if (IsServer(cptr))
{
/*
** Server is informing about a new server behind
** this link. Create REMOTE server structure,
** add it to list and propagate word to my other
** server links...
*/
if (parc == 1 || info[0] == '\0')
{
sendto_one(cptr,
"ERROR :No server info specified for %s", host);
return 0;
}
/*
** See if the newly found server is behind a guaranteed
** leaf (L-line). If so, close the link.
*/
if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
(!aconf->port || (hop > aconf->port)))
{
sendto_ops("Leaf-only link %s->%s - Closing",
get_client_name(cptr, TRUE),
aconf->host ? aconf->host : "*");
sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
return exit_client(cptr, cptr, cptr,
"Leaf Only (You are L:lined)");
}
/*
**
*/
if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
(aconf->port && (hop > aconf->port)))
{
sendto_ops("Non-Hub link %s introduced %s(%s).",
get_client_name(cptr, TRUE), host,
aconf ? (aconf->host ? aconf->host : "*") : "!");
return exit_client(cptr, cptr, cptr,
"Too many servers (Missing H:Line)");
}
/*
** See if the newly found server has a Q line for it in
** our conf. If it does, lose the link that brought it
** into our network. Format:
**
** Q:<unused>:<reason>:<servername>
**
** Example: Q:*:for the hell of it:eris.Berkeley.EDU
*/
if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
{
sendto_ops_butone(NULL, &me,
":%s WALLOPS * :%s brought in %s, %s %s",
me.name, get_client_name(cptr, FALSE),
host, "closing link because",
BadPtr(aconf->passwd) ? "reason unspecified" :
aconf->passwd);
sendto_one(cptr,
"ERROR :%s is not welcome: %s. %s",
host, BadPtr(aconf->passwd) ?
"reason unspecified" : aconf->passwd,
"Try another network");
return exit_client(cptr, cptr, cptr, "Q-Lined Server");
}
acptr = make_client(cptr, find_server(parv[0], NULL));
(void)make_server(acptr);
acptr->hopcount = hop;
strncpyzt(acptr->name, host, sizeof(acptr->name));
strncpyzt(acptr->info, info, sizeof(acptr->info));
acptr->serv->up = find_or_add(parv[0]);
SetServer(acptr);
/* Taken from bahamut makes it so all servers behind a U:lined
* server are also U:lined, very helpful if HIDE_ULINES is on
*/
if (IsULine(sptr,sptr) || (find_uline(cptr->confs, acptr->name)))
acptr->flags |= FLAGS_ULINE;
IRCstats.servers++;
(void)find_or_add(acptr->name);
acptr->flags |= FLAGS_TS8;
add_client_to_list(acptr);
(void)add_to_client_hash_table(acptr->name, acptr);
/*
** Old sendto_serv_but_one() call removed because we now
** need to send different names to different servers
** (domain name matching)
*/
parvaln = (char *)find_server_aln(parv[0]);
for (i = 0; i <= highest_fd; i++)
{
if (!(bcptr = local[i]) || !IsServer(bcptr) ||
bcptr == cptr || IsMe(bcptr))
continue;
if (!(aconf = bcptr->serv->nline))
{
sendto_ops("Lost N-line for %s on %s. Closing",
get_client_name(cptr, TRUE), host);
return exit_client(cptr, cptr, cptr,
"Lost N line");
}
if (match(my_name_for_link(me.name, aconf),
acptr->name) == 0)
continue;
if (ts)
sendto_one(bcptr, "%c%s %s %s %d %d :%s",
SupportALN(bcptr) ? '@' : ':',
SupportALN(bcptr) ? parvaln : parv[0],
IsToken(bcptr) ? TOK_SERVER : MSG_SERVER,
acptr->name, hop + 1, ts, acptr->info);
else
sendto_one(bcptr, "%c%s %s %s %d :%s",
SupportALN(bcptr) ? '@' : ':',
SupportALN(bcptr) ? parvaln : parv[0],
IsToken(bcptr) ? TOK_SERVER : MSG_SERVER,
acptr->name, hop + 1, acptr->info);
}
return 0;
}
if (!IsUnknown(cptr) && !IsHandshake(cptr))
return 0;
/*
** A local link that is still in undefined state wants
** to be a SERVER. Check if this is allowed and change
** status accordingly...
*/
strncpyzt(cptr->name, host, sizeof(cptr->name));
/* For now, just strip the VL stuff if it's there */
if (SupportVL(cptr)) {
/* we also have a fail safe incase they say they are sending
* VL stuff and don't -- codemastr
*/
aConfItem *vlines = NULL;
inf = NULL;
protocol = NULL;
flags = NULL;
protocol = (char *)strtok((char *)info, "-");
if (protocol)
flags = (char *)strtok((char *)NULL, " ");
if (flags)
inf = (char *)strtok((char *)NULL, "");
if (inf) {
strncpyzt(cptr->info, *inf ? inf : me.name, sizeof(cptr->info));
for (vlines = conf; vlines; vlines = vlines->next) {
if ((vlines->status & CONF_VERSION) && !match(vlines->name,cptr->name))
break;
}
if (vlines) {
char *proto = vlines->host;
char *vflags = vlines->passwd;
int result = 0;
int i;
protocol++;
/* check the protocol */
switch(*proto) {
case '<':
proto++;
if (atoi(protocol) < atoi(proto))
result = 1;
else
result = 0;
break;
case '>':
proto++;
if (atoi(protocol) > atoi(proto))
result = 1;
else
result = 0;
break;
case '=':
proto++;
if (atoi(protocol) == atoi(proto))
result = 1;
else
result = 0;
break;
case '!':
proto++;
if (atoi(protocol) != atoi(proto))
result = 1;
else
result = 0;
break;
/* default to = if anything else */
default:
if (atoi(protocol) == atoi(proto))
result = 1;
else
result = 0;
break;
} /* switch(*proto) */
/* For Services */
if (atoi(protocol) == 0)
result = 0;
/* if the proto in the V:line is * let it pass */
if (*proto == '*')
result = 0;
if (result)
return exit_client(cptr, cptr, cptr, "Denied by V:line");
/* If it passed the protocol check, check the flags */
for(i = 0; vflags[i]; i++) {
if (vflags[i] == '!') {
i++;
if (strchr(flags, (int)vflags[i])) {
result = 1;
break;
}
}
if (!strchr(flags, (int)vflags[i])) {
result = 1;
break;
}
} /* for(i = 0; vflags[i]; i++) */
if (*vflags == '*')
result = 0;
/* for services */
if (!strcmp(flags, "0"))
result = 0;
if (result)
return exit_client(cptr, cptr, cptr, "Denied by V:line");
} /* if (vlines) */
} /* if (flags) */
else
strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info));
}
else
strncpyzt(cptr->info, info[0] ? info : me.name, sizeof(cptr->info));
cptr->hopcount = hop;
/* check connection rules */
for (cconf = conf; cconf; cconf = cconf->next)
if ((cconf->status == CONF_CRULEALL) &&
(match(cconf->host, host) == 0))
if (crule_eval(cconf->passwd))
{
ircstp->is_ref++;
sendto_ops("Refused connection from %s.",
get_client_host(cptr));
return exit_client(cptr, cptr, cptr,
"Disallowed by connection rule");
}
switch (check_server_init(cptr))
{
case 0:
return m_server_estab(cptr);
case 1:
sendto_ops("Access check for %s in progress",
get_client_name(cptr, TRUE));
return 1;
default:
ircstp->is_ref++;
sendto_ops("Received unauthorized connection from %s.",
get_client_host(cptr));
sendto_serv_butone(&me,
":%s GLOBOPS :Recieved unauthorized connection from %s.",
parv[0], get_client_host(cptr));
return exit_client(cptr, cptr, cptr, "No C/N conf lines");
}
}
int m_server_estab(cptr)
aClient *cptr;
{
aClient *acptr;
aConfItem *aconf, *bconf;
char *inpath, *host, *s, *encr;
int split, i;
char *myaln = find_server_aln(me.name);
extern char serveropts[];
inpath = get_client_name(cptr, TRUE); /* "refresh" inpath with host */
split = mycmp(cptr->name, cptr->sockhost);
host = cptr->name;
current_load_data.conn_count++;
update_load();
if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
{
ircstp->is_ref++;
sendto_one(cptr,
"ERROR :Access denied. No N:line for server %s", inpath);
sendto_ops("Access denied. No N:line for server %s", inpath);
return exit_client(cptr, cptr, cptr, "No N line for server");
}
if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
inpath);
sendto_ops("Only N (no C) field for server %s", inpath);
return exit_client(cptr, cptr, cptr, "No C line for server");
}
#ifdef CRYPT_LINK_PASSWORD
/* use first two chars of the password they send in as salt */
/* passwd may be NULL. Head it off at the pass... */
if (*cptr->passwd)
{
char salt[3];
extern char *crypt();
salt[0] = aconf->passwd[0];
salt[1] = aconf->passwd[1];
salt[2] = '\0';
encr = crypt(cptr->passwd, salt);
}
else
encr = "";
#else
encr = cptr->passwd;
#endif /* CRYPT_LINK_PASSWORD */
if (*aconf->passwd && !StrEq(aconf->passwd, encr))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
inpath);
sendto_ops("Access denied (passwd mismatch) %s", inpath);
return exit_client(cptr, cptr, cptr, "Bad Password");
}
bzero(cptr->passwd, sizeof(cptr->passwd));
#ifndef HUB
for (i = 0; i <= highest_fd; i++)
if (local[i] && IsServer(local[i]))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :I'm a leaf not a hub");
return exit_client(cptr, cptr, cptr, "I'm a leaf");
}
#endif
if (IsUnknown(cptr))
{
sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
if (bconf->passwd[0])
sendto_one(cptr, "PASS :%s", bconf->passwd);
/*
** Pass my info to the new server
*/
/* modified so we send out the Uproto and flags */
sendto_one(cptr, "SERVER %s 1 :U%d-%s %s",
my_name_for_link(me.name, aconf), UnrealProtocol, serveropts,
(me.info[0]) ? (me.info) : "IRCers United");
}
else
{
s = (char *)index(aconf->host, '@');
*s = '\0'; /* should never be NULL */
Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
aconf->host, cptr->username));
if (match(aconf->host, cptr->username))
{
*s = '@';
ircstp->is_ref++;
sendto_ops("Username mismatch [%s]v[%s] : %s",
aconf->host, cptr->username,
get_client_name(cptr, TRUE));
sendto_one(cptr, "ERROR :No Username Match");
return exit_client(cptr, cptr, cptr, "Bad User");
}
*s = '@';
sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
}
det_confs_butmask(cptr,
CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD);
/*
** *WARNING*
** In the following code in place of plain server's
** name we send what is returned by get_client_name
** which may add the "sockhost" after the name. It's
** *very* *important* that there is a SPACE between
** the name and sockhost (if present). The receiving
** server will start the information field from this
** first blank and thus puts the sockhost into info.
** ...a bit tricky, but you have been warned, besides
** code is more neat this way... --msa
*/
SetServer(cptr);
IRCstats.me_servers++;
IRCstats.servers++;
IRCstats.unknown--;
#ifndef NO_FDLIST
addto_fdlist(cptr->fd, &serv_fdlist);
#endif
if ((find_uline(cptr->confs, cptr->name)))
cptr->flags |= FLAGS_ULINE;
cptr->flags |= FLAGS_TS8;
nextping = TStime();
(void)find_or_add(cptr->name);
if (TRUEHUB == 1)
sendto_serv_butone(&me,
":%s GLOBOPS :Link with %s established.", me.name, inpath);
sendto_locfailops("Link with %s established.", inpath);
/* Insert here */
(void)add_to_client_hash_table(cptr->name, cptr);
/* doesnt duplicate cptr->serv if allocted this struct already */
(void)make_server(cptr);
cptr->serv->up = me.name;
cptr->srvptr = &me;
cptr->serv->nline = aconf;
/*
** Old sendto_serv_but_one() call removed because we now
** need to send different names to different servers
** (domain name matching) Send new server to other servers.
*/
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]) || !IsServer(acptr) ||
acptr == cptr || IsMe(acptr))
continue;
if ((aconf = acptr->serv->nline) &&
!match(my_name_for_link(me.name, aconf), cptr->name))
continue;
if (split)
sendto_one(acptr, "%c%s %s %s 2 :%s",
(SupportALN(acptr) ? '@' : ':'),
(SupportALN(acptr) ? myaln : me.name),
(IsToken(acptr) ? TOK_SERVER : MSG_SERVER),
cptr->name, cptr->info);
else
sendto_one(acptr, "%c%s %s %s 2 :%s",
(SupportALN(acptr) ? '@' : ':'),
(SupportALN(acptr) ? myaln : me.name),
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
cptr->name, cptr->info);
}
/*
** Pass on my client information to the new server
**
** First, pass only servers (idea is that if the link gets
** cancelled beacause the server was already there,
** there are no NICK's to be cancelled...). Of course,
** if cancellation occurs, all this info is sent anyway,
** and I guess the link dies when a read is attempted...? --msa
**
** Note: Link cancellation to occur at this point means
** that at least two servers from my fragment are building
** up connection this other fragment at the same time, it's
** a race condition, not the normal way of operation...
**
** ALSO NOTE: using the get_client_name for server names--
** see previous *WARNING*!!! (Also, original inpath
** is destroyed...)
*/
aconf = cptr->serv->nline;
for (acptr = &me; acptr; acptr = acptr->prev)
{
/* acptr->from == acptr for acptr == cptr */
if (acptr->from == cptr)
continue;
if (IsServer(acptr))
{
if (match(my_name_for_link(me.name, aconf),
acptr->name) == 0)
continue;
split = (MyConnect(acptr) &&
mycmp(acptr->name, acptr->sockhost));
if (split)
sendto_one(cptr, "%c%s %s %s %d :%s",
(SupportALN(cptr) ? '@' : ':'),
(SupportALN(cptr) ?
find_server_aln(acptr->serv->up) : acptr->
serv->up),
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
acptr->name, acptr->hopcount + 1,
acptr->info);
else
sendto_one(cptr, "%c%s %s %s %d :%s",
(SupportALN(cptr) ? '@' : ':'),
(SupportALN(cptr) ?
find_server_aln(acptr->serv->up) : acptr->
serv->up),
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
acptr->name, acptr->hopcount + 1,
acptr->info);
}
}
for (acptr = &me; acptr; acptr = acptr->prev)
{
/* acptr->from == acptr for acptr == cptr */
if (acptr->from == cptr)
continue;
if (IsPerson(acptr))
{
/*
** IsPerson(x) is true only when IsClient(x) is true.
** These are only true when *BOTH* NICK and USER have
** been received. -avalon
** Apparently USER command was forgotten... -Donwulff
*/
if (!SupportNICKv2(cptr))
{
sendto_one(cptr, "%s %s %d %d %s %s %s %lu :%s",
(IsToken(cptr) ? TOK_NICK : MSG_NICK),
acptr->name, acptr->hopcount + 1,
acptr->lastnick, acptr->user->username,
acptr->user->realhost, acptr->user->server,
acptr->user->servicestamp, acptr->info);
send_umode(cptr, acptr, 0, SEND_UMODES, buf);
if (IsHidden(acptr) && acptr->user->virthost)
sendto_one(cptr, ":%s %s %s",
acptr->name,
(IsToken(cptr) ? TOK_SETHOST :
MSG_SETHOST),
acptr->user->virthost);
}
else
{
send_umode(NULL, acptr, 0, SEND_UMODES, buf);
if (!SupportVHP(cptr))
sendto_one(cptr,
"%s %s %d %d %s %s %s %lu %s %s :%s",
(IsToken(cptr) ? TOK_NICK : MSG_NICK),
acptr->name, acptr->hopcount + 1,
acptr->lastnick, acptr->user->username,
acptr->user->realhost,
(SupportALN(cptr) ?
find_server_aln(acptr->user->
server) : acptr->user->server),
acptr->user->servicestamp, (!buf
|| *buf == '\0' ? "+" : buf),
((IsHidden(acptr)
&& (acptr->umodes & UMODE_SETHOST)) ?
acptr->user->virthost : "*"), acptr->info);
else
sendto_one(cptr,
"%s %s %d %d %s %s %s %lu %s %s :%s",
(IsToken(cptr) ? TOK_NICK : MSG_NICK),
acptr->name, acptr->hopcount + 1,
acptr->lastnick, acptr->user->username,
acptr->user->realhost,
(SupportALN(cptr) ?
find_server_aln(acptr->user->
server) : acptr->user->server),
acptr->user->servicestamp, (!buf
|| *buf == '\0' ? "+" : buf),
IsHidden(acptr) ? acptr->user->virthost
: acptr->user->realhost, acptr->info);
}
if (acptr->user->away)
sendto_one(cptr, ":%s %s :%s", acptr->name,
(IsToken(cptr) ? TOK_AWAY : MSG_AWAY),
acptr->user->away);
if (acptr->user->swhois)
if (*acptr->user->swhois != '\0')
sendto_one(cptr, "%s %s :%s",
(IsToken(cptr) ? TOK_SWHOIS :
MSG_SWHOIS), acptr->name,
acptr->user->swhois);
if (!SupportSJOIN(cptr))
send_user_joins(cptr, acptr);
}
}
/*
** Last, pass all channels plus statuses
*/
{
aChannel *chptr;
for (chptr = channel; chptr; chptr = chptr->nextch)
{
if (!SupportSJOIN(cptr))
send_channel_modes(cptr, chptr);
else
if (SupportSJOIN(cptr) && !SupportSJ3(cptr))
{
send_channel_modes_sjoin(cptr, chptr);
}
else
send_channel_modes_sjoin3(cptr, chptr);
if (chptr->topic_time)
sendto_one(cptr, "%s %s %s %lu :%s",
(IsToken(cptr) ? TOK_TOPIC : MSG_TOPIC),
chptr->chname, chptr->topic_nick,
chptr->topic_time, chptr->topic);
}
}
/* pass on TKLs */
tkl_synch(cptr);
/* send out SVSFLINEs */
dcc_sync(cptr);
/*
** Pass on all services based q-lines
*/
{
aSqlineItem *tmp;
for (tmp = sqline; tmp; tmp = tmp->next)
{
if (tmp->status != CONF_ILLEGAL)
if (tmp->reason)
sendto_one(cptr, "%c%s %s %s :%s",
SupportALN(cptr) ? '@' : ':',
SupportALN(cptr) ? myaln : me.name,
(IsToken(cptr) ? TOK_SQLINE :
MSG_SQLINE), tmp->sqline,
tmp->reason);
else
sendto_one(cptr, ":%s %s %s", me.name,
(IsToken(cptr) ? TOK_SQLINE :
MSG_SQLINE), tmp->sqline);
}
}
sendto_one(cptr, "%s %li %li %li 0 0 0 0 :%s",
(IsToken(cptr) ? TOK_NETINFO : MSG_NETINFO),
IRCstats.global_max, TStime(), UnrealProtocol, ircnetwork);
return 0;
}
/*
** m_links
** parv[0] = sender prefix
** parv[1] = servername mask
** or
** parv[0] = sender prefix
** parv[1] = server to query
** parv[2] = servername mask
*/
int m_links(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *mask;
aClient *acptr;
if (parc > 2 && IsOper(cptr))
{
if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv)
!= HUNTED_ISME)
return 0;
mask = parv[2];
}
else
mask = parc < 2 ? NULL : parv[1];
for (acptr = client, (void)collapse(mask); acptr; acptr = acptr->next)
{
if (!IsServer(acptr) && !IsMe(acptr))
continue;
if (!BadPtr(mask) && match(mask, acptr->name))
continue;
if (HIDE_ULINES == 1)
{
if (IsULine(acptr, acptr) && !IsAnOper(sptr))
continue;
}
sendto_one(sptr, rpl_str(RPL_LINKS),
me.name, parv[0], acptr->name, acptr->serv->up,
acptr->hopcount, (acptr->info[0] ? acptr->info :
"(Unknown Location)"));
}
sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
BadPtr(mask) ? "*" : mask);
return 0;
}
/*
** m_netinfo
** by Stskeeps
** parv[0] = sender prefix
** parv[1] = max global count
** parv[2] = time of end sync
** parv[3] = unreal protocol using (numeric)
** parv[4] = free(for unrealprotocol > 2100)
** parv[5] = free(**)
** parv[6] = free(**)
** parv[7] = free(**)
** parv[8] = ircnet
**/
int m_netinfo(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
long lmax;
time_t xx;
long endsync, protocol;
if (IsPerson(sptr))
return 0;
if (!IsServer(cptr))
return 0;
if (parc < 3)
{
/* Talking to a UnProtocol 2090 */
sendto_realops
("Link %s is using a too old UnProtocol - (parc < 3)",
cptr->name);
if (KILLDIFF == 1)
{
sendto_realops
("Dropped link %s - unProtocol 2090 is not compatible with unProtocol %li",
cptr->name, UnrealProtocol);
sendto_one(cptr,
"ERROR :unProtocol 2090 is not compatible with unProtocol %li",
UnrealProtocol);
exit_client(cptr, cptr, cptr,
"Link using unProtocol 2090");
}
return 0;
}
if (parc < 9)
{
return 0;
}
if (GotNetInfo(cptr))
{
sendto_realops("Already got NETINFO from Link %s", cptr->name);
return 0;
}
/* is a long therefore not ATOI */
lmax = atol(parv[1]);
endsync = atol(parv[2]);
protocol = atol(parv[3]);
/* max global count != max_global_count --sts */
if (lmax > IRCstats.global_max)
{
IRCstats.global_max = lmax;
sendto_realops("Max Global Count is now %li (set by link %s)",
lmax, cptr->name);
}
xx = TStime();
if ((xx - endsync) < 0)
{
sendto_realops
("Possible negative TS split at link %s (%li - %li = %li)",
cptr->name, (xx), (endsync), (xx - endsync));
sendto_serv_butone(&me,
":%s SMO o :\2(sync)\2 Possible negative TS split at link %s (%li - %li = %li)",
me.name, cptr->name, (xx), (endsync), (xx - endsync));
}
sendto_realops
("Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
cptr->name, me.name, (TStime() - endsync), sptr->receiveK,
sptr->receiveB, sptr->sendK, sptr->sendB);
sendto_serv_butone(&me,
":%s SMO o :\2(sync)\2 Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
me.name, cptr->name, me.name, (TStime() - endsync), sptr->receiveK,
sptr->receiveB, sptr->sendK, sptr->sendB);
if (!(strcmp(ircnetwork, parv[8]) == 0))
{
sendto_realops("Network name mismatch from link %s (%s != %s)",
cptr->name, parv[8], ircnetwork);
sendto_serv_butone(&me,
":%s SMO o :\2(sync)\2 Network name mismatch from link %s (%s != %s)",
me.name, cptr->name, parv[8], ircnetwork);
}
if ((protocol != UnrealProtocol) && (protocol != 0))
{
sendto_realops
("Link %s is running Protocol u%li while we are running %li!",
cptr->name, protocol, UnrealProtocol);
sendto_serv_butone(&me,
":%s SMO o :\2(sync)\2 Link %s is running u%li while %s is running %li!",
me.name, cptr->name, protocol, me.name, UnrealProtocol);
}
SetNetInfo(cptr);
}
#ifndef IRCDTOTALVERSION
#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
#endif
/*
* sends m_info into to sptr
*/
void m_info_send(sptr)
aClient *sptr;
{
sendto_one(sptr, ":%s %d %s :=-=-=-= %s =-=-=-=",
me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION);
sendto_one(sptr, ":%s %d %s :| Brought to you by the following people:",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| * Stskeeps <stskeeps@tspre.org>",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| * codemastr <codemastr@tspre.org>",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| * DrBin <drbin@tspre.org>",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| Credits - Type /Credits",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| DALnet Credits - Type /DalInfo",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| This is an UnrealIRCD-style server",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| If you find any bugs, please mail",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| unreal-dev@lists.sourceforge.net",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr,
":%s %d %s :| UnrealIRCd Homepage: http://unreal.tspre.org",
me.name, RPL_INFO, sptr->name);
#ifdef _WIN32
#ifdef WIN32_SPECIFY
sendto_one(sptr, ":%s %d %s :| wIRCd porter: | %s",
me.name, RPL_INFO, sptr->name, WIN32_PORTER);
sendto_one(sptr, ":%s %d %s :| >>URL: | %s",
me.name, RPL_INFO, sptr->name, WIN32_URL);
#endif
#endif
sendto_one(sptr,
":%s %d %s :-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", me.name,
RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name,
RPL_INFO, sptr->name, creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO,
sptr->name, myctime(me.firsttime));
sendto_one(sptr, ":%s %d %s :ReleaseID (%s)", me.name, RPL_INFO,
sptr->name, RELEASEID);
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, sptr->name);
}
/*
** m_info
** parv[0] = sender prefix
** parv[1] = servername
** Modified for hardcode by Stskeeps
*/
int m_info(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
if (hunt_server(cptr, sptr, ":%s INFO :%s", 1, parc,
parv) == HUNTED_ISME)
{
m_info_send(sptr);
}
return 0;
}
/*
** m_dalinfo
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_dalinfo(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = dalinfotext;
if (hunt_server(cptr, sptr, ":%s DALINFO :%s", 1, parc,
parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr,
":%s %d %s :Birth Date: %s, compile # %s",
me.name, RPL_INFO, parv[0], creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s",
me.name, RPL_INFO, parv[0], myctime(me.firsttime));
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
** m_license
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_license(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = gnulicense;
if (hunt_server(cptr, sptr, ":%s LICENSE :%s", 1, parc,
parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
** m_credits
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_credits(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = unrealcredits;
if (hunt_server(cptr, sptr, ":%s CREDITS :%s", 1, parc,
parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr,
":%s %d %s :Birth Date: %s, compile # %s",
me.name, RPL_INFO, parv[0], creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s",
me.name, RPL_INFO, parv[0], myctime(me.firsttime));
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
* RPL_NOWON - Online at the moment (Succesfully added to WATCH-list)
* RPL_NOWOFF - Offline at the moement (Succesfully added to WATCH-list)
* RPL_WATCHOFF - Succesfully removed from WATCH-list.
* ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries.
*/
static void show_watch(cptr, name, rpl1, rpl2)
aClient *cptr;
char *name;
int rpl1, rpl2;
{
aClient *acptr;
if ((acptr = find_person(name, NULL)))
{
sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name,
acptr->name, acptr->user->username,
IsHidden(acptr) ? acptr->user->virthost : acptr->
user->realhost, acptr->lastnick);
}
else
sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name,
name, "*", "*", 0);
}
/*
* m_watch
*/
int m_watch(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
char *s, **pav = parv, *user;
char *p = NULL, *def = "l";
if (parc < 2)
{
/*
* Default to 'l' - list who's currently online
*/
parc = 2;
parv[1] = def;
}
for (s = (char *)strtoken(&p, *++pav, " "); s;
s = (char *)strtoken(&p, NULL, " "))
{
if ((user = (char *)index(s, '!')))
*user++ = '\0'; /* Not used */
/*
* Prefix of "+", they want to add a name to their WATCH
* list.
*/
if (*s == '+')
{
if (do_nick_name(s + 1))
{
if (sptr->notifies >= MAXWATCH)
{
sendto_one(sptr,
err_str(ERR_TOOMANYWATCH), me.name,
cptr->name, s + 1);
continue;
}
add_to_notify_hash_table(s + 1, sptr);
}
show_watch(sptr, s + 1, RPL_NOWON, RPL_NOWOFF);
continue;
}
/*
* Prefix of "-", coward wants to remove somebody from their
* WATCH list. So do it. :-)
*/
if (*s == '-')
{
del_from_notify_hash_table(s + 1, sptr);
show_watch(sptr, s + 1, RPL_WATCHOFF, RPL_WATCHOFF);
continue;
}
/*
* Fancy "C" or "c", they want to nuke their WATCH list and start
* over, so be it.
*/
if (*s == 'C' || *s == 'c')
{
hash_del_notify_list(sptr);
continue;
}
/*
* Now comes the fun stuff, "S" or "s" returns a status report of
* their WATCH list. I imagine this could be CPU intensive if its
* done alot, perhaps an auto-lag on this?
*/
if (*s == 'S' || *s == 's')
{
Link *lp;
aNotify *anptr;
int count = 0;
/*
* Send a list of how many users they have on their WATCH list
* and how many WATCH lists they are on.
*/
anptr = hash_get_notify(sptr->name);
if (anptr)
for (lp = anptr->notify, count = 1;
(lp = lp->next); count++)
;
sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name,
parv[0], sptr->notifies, count);
/*
* Send a list of everybody in their WATCH list. Be careful
* not to buffer overflow.
*/
if ((lp = sptr->notify) == NULL)
{
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST),
me.name, parv[0], *s);
continue;
}
*buf = '\0';
strcpy(buf, lp->value.nptr->nick);
count =
strlen(parv[0]) + strlen(me.name) + 10 +
strlen(buf);
while ((lp = lp->next))
{
if (count + strlen(lp->value.nptr->nick) + 1 >
BUFSIZE - 2)
{
sendto_one(sptr, rpl_str(RPL_WATCHLIST),
me.name, parv[0], buf);
*buf = '\0';
count =
strlen(parv[0]) + strlen(me.name) +
10;
}
strcat(buf, " ");
strcat(buf, lp->value.nptr->nick);
count += (strlen(lp->value.nptr->nick) + 1);
}
sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name,
parv[0], buf);
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name,
parv[0], *s);
continue;
}
/*
* Well that was fun, NOT. Now they want a list of everybody in
* their WATCH list AND if they are online or offline? Sheesh,
* greedy arn't we?
*/
if (*s == 'L' || *s == 'l')
{
Link *lp = sptr->notify;
while (lp)
{
if ((acptr =
find_person(lp->value.nptr->nick, NULL)))
{
sendto_one(sptr, rpl_str(RPL_NOWON),
me.name, parv[0], acptr->name,
acptr->user->username,
IsHidden(acptr) ? acptr->
user->virthost : acptr->user->
realhost, acptr->lastnick);
}
/*
* But actually, only show them offline if its a capital
* 'L' (full list wanted).
*/
else if (isupper(*s))
sendto_one(sptr, rpl_str(RPL_NOWOFF),
me.name, parv[0],
lp->value.nptr->nick, "*", "*",
lp->value.nptr->lasttime);
lp = lp->next;
}
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name,
parv[0], *s);
continue;
}
/*
* Hmm.. unknown prefix character.. Ignore it. :-)
*/
}
return 0;
}
/*
** m_summon should be redefined to ":prefix SUMMON host user" so
** that "hunt_server"-function could be used for this too!!! --msa
** As of 2.7.1e, this was the case. -avalon
**
** parv[0] = sender prefix
** parv[1] = user
** parv[2] = server
** parv[3] = channel (optional)
*/
int m_summon(cptr, sptr, parc, parv)
aClient *sptr, *cptr;
int parc;
char *parv[];
{
char *host, *user, *chname;
#ifdef ENABLE_SUMMON
char hostbuf[17], namebuf[10], linebuf[10];
# ifdef LEAST_IDLE
char linetmp[10], ttyname[15]; /* Ack */
struct stat stb;
time_t ltime = (time_t) 0;
# endif
int fd, flag = 0;
#endif
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NORECIPIENT),
me.name, parv[0], "SUMMON");
return 0;
}
user = parv[1];
host = (parc < 3 || BadPtr(parv[2])) ? me.name : parv[2];
chname = (parc > 3) ? parv[3] : "*";
/*
** Summoning someone on remote server, find out which link to
** use and pass the message there...
*/
parv[1] = user;
parv[2] = host;
parv[3] = chname;
parv[4] = NULL;
if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
HUNTED_ISME)
{
#ifdef ENABLE_SUMMON
if ((fd = utmp_open()) == -1)
{
sendto_one(sptr, err_str(ERR_FILEERROR),
me.name, parv[0], "open", UTMP);
return 0;
}
# ifndef LEAST_IDLE
while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
sizeof(hostbuf))) == 0)
if (StrEq(namebuf, user))
break;
# else
/* use least-idle tty, not the first
* one we find in utmp. 10/9/90 Spike@world.std.com
* (loosely based on Jim Frost jimf@saber.com code)
*/
while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
sizeof(hostbuf))) == 0)
{
if (StrEq(namebuf, user))
{
(void)ircsprintf(ttyname, "/dev/%s", linetmp);
if (stat(ttyname, &stb) == -1)
{
sendto_one(sptr,
err_str(ERR_FILEERROR),
me.name, sptr->name,
"stat", ttyname);
return 0;
}
if (!ltime)
{
ltime = stb.st_mtime;
(void)strcpy(linebuf, linetmp);
}
else if (stb.st_mtime > ltime) /* less idle */
{
ltime = stb.st_mtime;
(void)strcpy(linebuf, linetmp);
}
}
}
# endif
(void)utmp_close(fd);
# ifdef LEAST_IDLE
if (ltime == 0)
# else
if (flag == -1)
# endif
sendto_one(sptr, err_str(ERR_NOLOGIN),
me.name, parv[0], user);
else
summon(sptr, user, linebuf, chname);
#else
sendto_one(sptr, err_str(ERR_SUMMONDISABLED), me.name, parv[0]);
#endif /* ENABLE_SUMMON */
}
return 0;
}
/*
** m_stats
** parv[0] = sender prefix
** parv[1] = statistics selector (defaults to Message frequency)
** parv[2] = server name (current server defaulted, if omitted)
**
** Currently supported are:
** M = Message frequency (the old stat behaviour)
** L = Local Link statistics
** C = Report C and N configuration lines
*/
/*
** m_stats/stats_conf
** Report N/C-configuration lines from this server. This could
** report other configuration lines too, but converting the
** status back to "char" is a bit akward--not worth the code
** it needs...
**
** Note: The info is reported in the order the server uses
** it--not reversed as in ircd.conf!
*/
static int report_array[][3] = {
{CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
{CONF_NOCONNECT_SERVER, RPL_STATSOLDNLINE, 'N'},
{CONF_NLINE, RPL_STATSNLINE, 'n'},
{CONF_CLIENT, RPL_STATSILINE, 'I'},
{CONF_KILL, RPL_STATSKLINE, 'K'},
{CONF_EXCEPT, RPL_STATSKLINE, 'E'},
{CONF_ZAP, RPL_STATSKLINE, 'Z'},
{CONF_QUARANTINED_NICK, RPL_STATSQLINE, 'Q'},
{CONF_LEAF, RPL_STATSLLINE, 'L'},
{CONF_OPERATOR, RPL_STATSOLINE, 'O'},
{CONF_HUB, RPL_STATSHLINE, 'H'},
{CONF_LOCOP, RPL_STATSOLINE, 'o'},
{CONF_CRULEALL, RPL_STATSDLINE, 'D'},
{CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
{CONF_UWORLD, RPL_STATSULINE, 'U'},
{CONF_MISSING, RPL_STATSXLINE, 'X'},
{CONF_TLINE, RPL_STATSTLINE, 't'},
{CONF_SOCKSEXCEPT, RPL_STATSELINE, 'e'},
{CONF_VERSION, RPL_STATSVLINE, 'V'},
{0, 0}
};
static void report_sqlined_nicks(sptr)
aClient *sptr;
{
aSqlineItem *tmp;
char *nickmask, *reason;
for (tmp = sqline; tmp; tmp = tmp->next)
{
if (tmp->status != CONF_ILLEGAL)
{
nickmask = BadPtr(tmp->sqline) ? "<NULL>" : tmp->sqline;
reason = BadPtr(tmp->reason) ? "<NULL>" : tmp->reason;
sendto_one(sptr, rpl_str(RPL_SQLINE_NICK), me.name,
sptr->name, nickmask, reason);
}
}
}
static void report_configured_links(sptr, mask)
aClient *sptr;
int mask;
{
static char null[] = "<NULL>";
aConfItem *tmp;
int *p, port, tmpmask;
char c, *host, *pass, *name;
tmpmask = (mask == CONF_MISSING) ? CONF_CONNECT_SERVER : mask;
for (tmp = conf; tmp; tmp = tmp->next)
if (tmp->status & tmpmask)
{
for (p = &report_array[0][0]; *p; p += 3)
if (*p == tmp->status)
break;
if (!*p)
continue;
c = (char)*(p + 2);
host = BadPtr(tmp->host) ? null : tmp->host;
pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
name = BadPtr(tmp->name) ? null : tmp->name;
port = (int)tmp->port;
/*
* On K line the passwd contents can be
* displayed on STATS reply. -Vesa
*/
/* Same with Z-lines and q/Q-lines -- Barubary */
if ((tmp->status == CONF_KILL) || (tmp->status &
CONF_QUARANTINE) || (tmp->status & CONF_EXCEPT)
|| (tmp->status == CONF_ZAP))
{
/* These mods are to tell the difference between the different kinds
* of klines. the only effect it has is in the display. --Russell
*/
/* Now translates spaces to _'s to show comments in klines -- Barubary */
char *temp;
if (!pass)
strcpy(buf, "<NULL>");
else
{
strcpy(buf, pass);
for (temp = buf; *temp; temp++)
if (*temp == ' ')
*temp = '_';
}
/* semicolon intentional -- Barubary */
if (tmp->status == CONF_QUARANTINED_NICK);
/* Hide password for servers -- Barubary */
else if (tmp->status & CONF_QUARANTINE)
strcpy(buf, "*");
else
{
/* This wasn't documented before - comments aren't displayed for akills
because they are all the same. -- Barubary */
if (tmp->tmpconf == KLINE_AKILL)
strcpy(buf, "*");
/* Show comments in E:Lines..
if (tmp->tmpconf == KLINE_EXCEPT)
strcpy(buf, "*");
*/
/* KLINE_PERM == 0 - watch out when doing
Z-lines. -- Barubary */
if (tmp->status != CONF_ZAP)
{
if (tmp->tmpconf == KLINE_PERM)
c = 'K';
if (tmp->tmpconf == KLINE_TEMP)
c = 'k';
if (tmp->tmpconf == KLINE_AKILL)
c = 'A';
if (tmp->tmpconf ==
KLINE_EXCEPT) c = 'E';
}
else
{
if (tmp->tmpconf == KLINE_PERM)
c = 'Z';
if (tmp->tmpconf == KLINE_TEMP)
c = 'z';
if (tmp->tmpconf == KLINE_AKILL)
c = 'S';
if (tmp->tmpconf ==
KLINE_EXCEPT) c = 'e';
}
}
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host,
buf, name, port, get_conf_class(tmp));
}
else if (mask & CONF_OPS)
{
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host, name, oflagstr(port),
get_conf_class(tmp));
}
/* connect rules are classless */
else if (tmp->status & CONF_CRULE)
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host, name);
/* Only display on X if server is missing */
else if (mask == CONF_MISSING)
{
if (!find_server(name, NULL))
sendto_one(sptr,
rpl_str(RPL_STATSXLINE), me.name,
sptr->name, name, port);
}
else if (mask == CONF_TLINE)
{
sendto_one(sptr, rpl_str(RPL_STATSTLINE),
me.name, sptr->name, host, pass, name);
}
else if (mask == CONF_SOCKSEXCEPT)
{
sendto_one(sptr, rpl_str(RPL_STATSELINE),
me.name, sptr->name, host, pass, name);
}
else if (mask == CONF_NLINE)
{
sendto_one(sptr, rpl_str(RPL_STATSNLINE),
me.name, sptr->name, host, pass);
}
else if (mask == CONF_VERSION)
sendto_one(sptr, rpl_str(RPL_STATSVLINE),
me.name, sptr->name, host, pass, name);
/* else if (mask == CONF_EXCEPT)
{
ppx = MyMalloc(strlen(tmp->passwd) + 1);
strcpy(ppx, tmp->passwd);
for (pp = ppx; *pp != '\0'; pp++) {
if (*pp == ' ')
*pp = '_';
}
sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
sptr->name, "E", host, ppx, name, 0,0, -1);
MyFree(ppx);
} */
else
{
if (!IsOper(sptr)
&& (mask & CONF_NOCONNECT_SERVER
|| mask & CONF_CONNECT_SERVER))
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, "*", name, port,
get_conf_class(tmp));
else
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host, name, port,
get_conf_class(tmp));
}
}
return;
}
/* Used to blank out ports -- Barubary */
char *get_client_name2(aClient *acptr, int showports)
{
char *pointer = get_client_name(acptr, TRUE);
if (!pointer)
return NULL;
if (showports)
return pointer;
if (!strrchr(pointer, '.'))
return NULL;
strcpy((char *)strrchr((char *)pointer, '.'), ".0]");
return pointer;
}
int m_stats(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
#ifndef DEBUGMODE
static char Sformat[] =
":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle";
static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u :%u";
#else
static char Sformat[] =
":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since CPU :Idle";
static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u %s";
char pbuf[96]; /* Should be enough for to ints */
#endif
struct Message *mptr;
aClient *acptr;
char stat = parc > 1 ? parv[1][0] : '\0';
int i;
int doall = 0, wilds = 0, showports = IsAnOper(sptr), remote = 0;
char *name;
#ifdef STATS_ONLYOPER
if (!IsAnOper(sptr))
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
#endif
if (hunt_server(cptr, sptr, ":%s STATS %s :%s", 2, parc,
parv) != HUNTED_ISME)
return 0;
if (parc > 2)
{
name = parv[2];
if (!mycmp(name, me.name))
doall = 2;
else if (match(name, me.name) == 0)
doall = 1;
if (index(name, '*') || index(name, '?'))
wilds = 1;
}
else
name = me.name;
if (stat != '\0')
sendto_umode(UMODE_EYES, "Stats \'%c\' requested by %s (%s@%s)",
stat, sptr->name, sptr->user->username,
IsHidden(sptr) ? sptr->user->virthost : sptr->
user->realhost);
else
sendto_umode(UMODE_EYES,
"Stats \'NULL\' requested by %s (%s@%s)", sptr->name,
sptr->user->username,
IsHidden(sptr) ? sptr->user->virthost : sptr->
user->realhost);
switch (stat)
{
case 'b': badwords_stats();
break;
case 'L':
case 'l':
/*
* 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.
*/
sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO,
parv[0]);
if (IsServer(cptr))
{
remote = 1;
wilds = 0;
}
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsInvisible(acptr) && (doall || wilds) &&
!(MyConnect(sptr) && IsOper(sptr)) &&
!IsAnOper(acptr) && (acptr != sptr))
continue;
if (remote && doall && !IsServer(acptr) &&
!IsMe(acptr))
continue;
if (remote && !doall && IsServer(acptr))
continue;
if (!doall && wilds && match(name, acptr->name))
continue;
if (!(parc == 2 && IsServer(acptr)) &&
!(doall || wilds) && mycmp(name, acptr->name))
continue;
#ifdef DEBUGMODE
ircsprintf(pbuf, "%d :%d", acptr->cputime,
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#endif
if (IsOper(sptr))
{
sendto_one(sptr, Lformat, me.name,
RPL_STATSLINKINFO, parv[0],
(isupper(stat)) ?
get_client_name2(acptr, showports) :
get_client_name(acptr, FALSE),
(int)DBufLength(&acptr->sendQ),
(int)acptr->sendM, (int)acptr->sendK,
(int)acptr->receiveM,
(int)acptr->receiveK,
TStime() - acptr->firsttime,
#ifndef DEBUGMODE
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#else
pbuf);
#endif
if (!IsServer(acptr) && IsAnOper(acptr))
sendto_one(acptr,
":%s NOTICE %s :*** %s did a /stats L on you! IP may have been shown",
me.name, acptr->name, sptr->name);
}
else if (!strchr(acptr->name, '.'))
sendto_one(sptr, Lformat, me.name,
RPL_STATSLINKINFO, parv[0],
IsHidden(acptr) ? acptr->name :
(isupper(stat)) ? /* Potvin - PreZ */
get_client_name2(acptr, showports) :
get_client_name(acptr, FALSE),
(int)DBufLength(&acptr->sendQ),
(int)acptr->sendM, (int)acptr->sendK,
(int)acptr->receiveM,
(int)acptr->receiveK,
TStime() - acptr->firsttime,
#ifndef DEBUGMODE
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#else
pbuf);
#endif
}
break;
case 'C':
case 'c':
report_configured_links(sptr, CONF_CONNECT_SERVER |
CONF_NOCONNECT_SERVER);
break;
case 'f':
case 'F':
report_flines(sptr);
break;
case 'G':
case 'g':
tkl_stats(sptr);
break;
case 'H':
case 'h':
report_configured_links(sptr, CONF_HUB | CONF_LEAF);
break;
case 'I':
case 'i':
report_configured_links(sptr, CONF_CLIENT);
break;
case 'E':
report_configured_links(sptr, CONF_EXCEPT);
break;
case 'e':
report_configured_links(sptr, CONF_SOCKSEXCEPT);
break;
case 'K':
case 'k':
report_configured_links(sptr,
CONF_KILL | CONF_ZAP | CONF_EXCEPT);
break;
case 'M':
case 'm':
for (mptr = msgtab; mptr->cmd; mptr++)
if (mptr->count)
#ifndef DEBUGMODE
sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
me.name, parv[0], mptr->cmd,
mptr->count, mptr->bytes);
#else
sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
me.name, parv[0], mptr->cmd,
mptr->count, mptr->bytes,
mptr->lticks,
mptr->lticks / CLOCKS_PER_SEC,
mptr->rticks,
mptr->rticks / CLOCKS_PER_SEC);
#endif
break;
case 'n':
report_configured_links(sptr, CONF_NLINE);
break;
case 'N':
if (IsOper(sptr))
report_network(sptr);
break;
case 'o':
case 'O':
/* if (SHOWOPERS == 1) {
if(IsOper(sptr)) {
report_configured_links(sptr, CONF_OPS);
break;
}
}
else
if (SHOWOPERS == 0) {
report_configured_links(sptr, CONF_OPS);
*/
if (SHOWOPERS == 0 && (IsOper(sptr)))
{
report_configured_links(sptr, CONF_OPS);
break;
}
if (SHOWOPERS == 1)
report_configured_links(sptr, CONF_OPS);
break;
case 'Q':
report_configured_links(sptr, CONF_QUARANTINE);
break;
case 'q':
report_sqlined_nicks(sptr);
break;
case 'R':
#ifdef DEBUGMODE
send_usage(sptr, parv[0]);
#endif
break;
case 's':
if (IsOper(sptr))
list_scache(sptr);
break;
case 'S':
if (IsOper(sptr))
report_dynconf(sptr);
break;
case 'D':
report_configured_links(sptr, CONF_CRULEALL);
break;
case 'd':
report_configured_links(sptr, CONF_CRULE);
break;
case 'r':
cr_report(sptr);
break;
case 't':
report_configured_links(sptr, CONF_TLINE);
break;
case 'T': /* /stats T not t:lines .. */
tstats(sptr, parv[0]);
break;
case 'U':
report_configured_links(sptr, CONF_UWORLD);
break;
case 'u':
{
time_t tmpnow;
tmpnow = TStime() - me.since;
sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
tmpnow / 86400, (tmpnow / 3600) % 24, (tmpnow / 60) % 60,
tmpnow % 60);
sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
max_connection_count, IRCstats.me_max);
break;
}
case 'v':
report_configured_links(sptr, CONF_VERSION);
break;
case 'V':
vhost_report(sptr);
break;
case 'W':
case 'w':
calc_load(sptr, parv[0]);
break;
case 'X':
case 'x':
report_configured_links(sptr, CONF_MISSING);
break;
case 'Y':
case 'y':
report_classes(sptr);
break;
case 'Z':
case 'z':
if (IsAnOper(sptr))
count_memory(sptr, parv[0]);
break;
default:
stat = '*';
break;
}
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
return 0;
}
/*
** m_users
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_users(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
#ifdef ENABLE_USERS
char namebuf[10], linebuf[10], hostbuf[17];
int fd, flag = 0;
#endif
if (hunt_server(cptr, sptr, ":%s USERS :%s", 1, parc,
parv) == HUNTED_ISME)
{
#ifdef ENABLE_USERS
if ((fd = utmp_open()) == -1)
{
sendto_one(sptr, err_str(ERR_FILEERROR),
me.name, parv[0], "open", UTMP);
return 0;
}
sendto_one(sptr, rpl_str(RPL_USERSSTART), me.name, parv[0]);
while (utmp_read(fd, namebuf, linebuf,
hostbuf, sizeof(hostbuf)) == 0)
{
flag = 1;
sendto_one(sptr, rpl_str(RPL_USERS), me.name, parv[0],
namebuf, linebuf, hostbuf);
}
if (flag == 0)
sendto_one(sptr, rpl_str(RPL_NOUSERS),
me.name, parv[0]);
sendto_one(sptr, rpl_str(RPL_ENDOFUSERS), me.name, parv[0]);
(void)utmp_close(fd);
#else
sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]);
#endif
}
return 0;
}
/*
** Note: At least at protocol level ERROR has only one parameter,
** although this is called internally from other functions
** --msa
**
** parv[0] = sender prefix
** parv[*] = parameters
*/
int m_error(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *para;
para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
Debug((DEBUG_ERROR, "Received ERROR message from %s: %s",
sptr->name, para));
/*
** Ignore error messages generated by normal user clients
** (because ill-behaving user clients would flood opers
** screen otherwise). Pass ERROR's from other sources to
** the local operator...
*/
if (IsPerson(cptr) || IsUnknown(cptr))
return 0;
if (cptr == sptr)
{
sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s -- %s",
me.name, get_client_name(cptr, FALSE), para);
sendto_locfailops("ERROR :from %s -- %s",
get_client_name(cptr, FALSE), para);
}
else
{
sendto_serv_butone(&me,
":%s GLOBOPS :ERROR from %s via %s -- %s", me.name,
sptr->name, get_client_name(cptr, FALSE), para);
sendto_ops("ERROR :from %s via %s -- %s", sptr->name,
get_client_name(cptr, FALSE), para);
}
return 0;
}
Link *helpign = NULL;
/* Now just empty ignore-list, in future reload dynamic help.
* Move out to help.c -Donwulff */
void reset_help()
{
free_str_list(helpign);
}
/*
** m_help (help/write to +h currently online) -Donwulff
** parv[0] = sender prefix
** parv[1] = optional message text
*/
int m_help(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *s;
Link *tmpl;
message = parc > 1 ? parv[1] : NULL;
/* Drags along from wallops code... I'm not sure what it's supposed to do,
at least it won't do that gracefully, whatever it is it does - but
checking whether or not it's a person _is_ good... -Donwulff */
if (!IsServer(sptr) && MyConnect(sptr) && !IsPerson(sptr))
{
}
if (IsServer(sptr) || IsHelpOp(sptr))
{
if (BadPtr(message))
return 0;
if (message[0] == '?')
{
parse_help(sptr, parv[0], message + 1);
return 0;
}
if (message[1] == '!')
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_HELP, TOK_HELP, "%s", message);
if (!myncmp(message, "IGNORE ", 7))
{
tmpl = make_link();
DupString(tmpl->value.cp, message + 7);
tmpl->next = helpign;
helpign = tmpl;
}
sendto_helpops("from %s (HelpOp): %s", parv[0], message);
}
else if (MyConnect(sptr))
{
/* New syntax: ?... never goes out, !... always does. */
if (!BadPtr(message))
{
parse_help(sptr, parv[0], message);
return 0;
}
if ((!BadPtr(message) && !(message[0] == '!'))
|| BadPtr(message))
if (parse_help(sptr, parv[0], message))
return 0;
s = make_nick_user_host(cptr->name, cptr->user->username,
cptr->user->realhost);
for (tmpl = helpign; tmpl; tmpl = tmpl->next)
if (match(tmpl->value.cp, s) == 0)
{
sendto_one(sptr, rpl_str(RPL_HELPIGN), me.name,
parv[0]);
return 0;
}
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_HELP, TOK_HELP, "%s", message);
sendto_helpops("from %s (Local): %s", parv[0], message);
sendto_one(sptr, rpl_str(RPL_HELPFWD), me.name, parv[0]);
}
else
{
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_HELP, TOK_HELP, "%s", message);
sendto_helpops("from %s: %s", parv[0], message);
}
return 0;
}
/*
* parv[0] = sender
* parv[1] = host/server mask.
* parv[2] = server to query
*/
int m_lusers(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char mydom_mask[HOSTLEN + 1];
/* Doesn't work anyways --Stskeeps
if (parc > 2)
if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
!= HUNTED_ISME)
return 0;
*/
mydom_mask[0] = '*';
strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1);
/* Just to correct results ---Stskeeps */
if (IRCstats.clients > IRCstats.global_max)
IRCstats.global_max = IRCstats.clients;
if (IRCstats.me_clients > IRCstats.me_max)
IRCstats.me_max = IRCstats.me_clients;
sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
IRCstats.clients - IRCstats.invisible, IRCstats.invisible,
IRCstats.servers);
if (IRCstats.operators)
sendto_one(sptr, rpl_str(RPL_LUSEROP),
me.name, parv[0], IRCstats.operators);
if (IRCstats.unknown)
sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN),
me.name, parv[0], IRCstats.unknown);
if (IRCstats.channels)
sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
me.name, parv[0], IRCstats.channels);
sendto_one(sptr, rpl_str(RPL_LUSERME),
me.name, parv[0], IRCstats.me_clients, IRCstats.me_servers);
sendto_one(sptr, rpl_str(RPL_LOCALUSERS),
me.name, parv[0], IRCstats.me_clients, IRCstats.me_max);
sendto_one(sptr, rpl_str(RPL_GLOBALUSERS),
me.name, parv[0], IRCstats.clients, IRCstats.global_max);
if ((IRCstats.me_clients + IRCstats.me_servers) > max_connection_count)
{
max_connection_count =
IRCstats.me_clients + IRCstats.me_servers;
if (max_connection_count % 10 == 0) /* only send on even tens */
sendto_ops("Maximum connections: %d (%d clients)",
max_connection_count, IRCstats.me_clients);
}
current_load_data.client_count = IRCstats.me_clients;
current_load_data.conn_count =
IRCstats.me_clients + IRCstats.me_servers;
return 0;
}
extern int Rha;
void save_tunefile(void)
{
FILE *tunefile;
tunefile = fopen(IRCDTUNE, "w+");
if (!tunefile)
{
#if !defined(_WIN32) && !defined(_AMIGA)
sendto_ops("Unable to write tunefile.. %s", strerror(errno));
#else
sendto_ops("Unable to write tunefile..");
#endif
return;
}
fprintf(tunefile, "%li\n", TSoffset);
fprintf(tunefile, "%li\n", IRCstats.me_max);
fprintf(tunefile, "%li\n", Rha);
fclose(tunefile);
}
void load_tunefile(void)
{
FILE *tunefile;
char buf[1024];
tunefile = fopen(IRCDTUNE, "r");
if (!tunefile)
return;
fprintf(stderr, "* Loading tunefile..\n");
fgets(buf, 1023, tunefile);
TSoffset = atol(buf);
fgets(buf, 1023, tunefile);
IRCstats.me_max = atol(buf);
fgets(buf, 1023, tunefile);
Rha = atol(buf);
fclose(tunefile);
}
/***********************************************************************
* m_connect() - Added by Jto 11 Feb 1989
***********************************************************************/
/*
** m_connect
** parv[0] = sender prefix
** parv[1] = servername
** parv[2] = port number
** parv[3] = remote server
*/
int m_connect(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int port, tmpport, retval;
aConfItem *aconf, *cconf;
aClient *acptr;
if (!IsPrivileged(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (MyClient(sptr) && !OPCanGRoute(sptr) && parc > 3)
{ /* Only allow LocOps to make */
/* local CONNECTS --SRB */
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (MyClient(sptr) && !OPCanLRoute(sptr) && parc <= 3)
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (hunt_server(cptr, sptr, ":%s CONNECT %s %s :%s",
3, parc, parv) != HUNTED_ISME)
return 0;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "CONNECT");
return -1;
}
if ((acptr = find_server(parv[1], NULL)))
{
sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
me.name, parv[0], parv[1], "already exists from",
acptr->from->name);
return 0;
}
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
match(parv[1], aconf->name) == 0)
break;
/* Checked first servernames, then try hostnames. */
if (!aconf)
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
(match(parv[1], aconf->host) == 0 ||
match(parv[1], index(aconf->host, '@') + 1) == 0))
break;
if (!aconf)
{
sendto_one(sptr,
"NOTICE %s :Connect: Host %s not listed in ircd.conf",
parv[0], parv[1]);
return 0;
}
/*
** Get port number from user, if given. If not specified,
** use the default form configuration structure. If missing
** from there, then use the precompiled default.
*/
tmpport = port = aconf->port;
if (parc > 2 && !BadPtr(parv[2]))
{
if ((port = atoi(parv[2])) <= 0)
{
sendto_one(sptr,
"NOTICE %s :Connect: Illegal port number", parv[0]);
return 0;
}
}
else if (port <= 0 && (port = PORTNUM) <= 0)
{
sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
me.name, parv[0]);
return 0;
}
/*
** Evaluate connection rules... If no rules found, allow the
** connect. Otherwise stop with the first true rule (ie: rules
** are ored together. Oper connects are effected only by D
** lines (CRULEALL) not d lines (CRULEAUTO).
*/
for (cconf = conf; cconf; cconf = cconf->next)
if ((cconf->status == CONF_CRULEALL) &&
(match(cconf->host, aconf->name) == 0))
if (crule_eval(cconf->passwd))
{
sendto_one(sptr,
"NOTICE %s :Connect: Disallowed by rule: %s",
parv[0], cconf->name);
return 0;
}
/*
** Notify all operators about remote connect requests
*/
if (!IsAnOper(cptr))
{
sendto_serv_butone(&me,
":%s GLOBOPS :Remote CONNECT %s %s from %s",
me.name, parv[1], parv[2] ? parv[2] : "",
get_client_name(sptr, FALSE));
#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
syslog(LOG_DEBUG, "CONNECT From %s : %s %d", parv[0], parv[1],
parv[2] ? parv[2] : "");
#endif
}
aconf->port = port;
switch (retval = connect_server(aconf, sptr, NULL))
{
case 0:
sendto_one(sptr,
":%s NOTICE %s :*** Connecting to %s[%s].",
me.name, parv[0], aconf->host, aconf->name);
break;
case -1:
sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
me.name, parv[0], aconf->host);
break;
case -2:
sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
me.name, parv[0], aconf->host);
break;
default:
sendto_one(sptr,
":%s NOTICE %s :*** Connection to %s failed: %s",
me.name, parv[0], aconf->host, strerror(retval));
}
aconf->port = tmpport;
return 0;
}
/*
** m_wallops (write to *all* opers currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_wallops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "WALLOPS");
return 0;
}
if (MyClient(sptr) && !OPCanWallOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
":%s WALLOPS :%s", parv[0], message);
return 0;
}
/* m_gnotice (Russell) sort of like wallop, but only to +g clients on
** this server.
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_gnotice(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GNOTICE");
return 0;
}
if (!IsServer(sptr) && MyConnect(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL, parv[0],
MSG_GNOTICE, TOK_GNOTICE, ":%s", message);
sendto_failops("from %s: %s", parv[0], message);
return 0;
}
/*
** m_addline (write a line to ircd.conf)
**
** De-Potvinized by codemastr
*/
int m_addline(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
char *text;
text = parc > 1 ? parv[1] : NULL;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDLINE");
return 0;
}
/* writes to current -f */
conf = fopen(configfile, "a");
if (conf == NULL)
{
return 0;
}
/* Display what they wrote too */
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to ircd.conf",
me.name, parv[0], text);
fprintf(conf, "# Added by %s\n", make_nick_user_host(sptr->name,
sptr->user->username, sptr->user->realhost));
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
}
/* I dunno what Potvin was smoking when he made this code, but it plain SUX
* this should work just as good, and no need for a loop -- codemastr */
fprintf(conf, "%s\n", text);
fclose(conf);
return 1;
}
/*
** m_addmotd (write a line to ircd.motd)
**
** De-Potvinized by codemastr
*/
int m_addmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
char *text;
text = parc > 1 ? parv[1] : NULL;
if (!MyConnect(sptr))
return 0;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDMOTD");
return 0;
}
conf = fopen(MOTD, "a");
if (conf == NULL)
{
return 0;
}
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to file: ircd.motd",
me.name, parv[0], text);
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
} */
fprintf(conf, "%s\n", text);
fclose(conf);
return 1;
}
/*
** m_svsmotd
**
*/
int m_svsmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf = NULL;
if (!IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "SVSMOTD");
return 0;
}
if ((*parv[1] != '!') && parc < 3)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "SVSMOTD");
return 0;
}
switch (*parv[1])
{
case '#':
conf = fopen(VPATH, "a");
sendto_ops("Added '%s' to services motd", parv[2]);
break;
case '!':
{
remove(VPATH);
sendto_ops("Wiped out services motd data");
break;
}
default:
break;
}
sendto_serv_butone_token(cptr, parv[0], MSG_SVSMOTD, TOK_SVSMOTD,
"%s :%s", parv[1], parv[2]);
if (conf == NULL)
{
return 0;
}
if (parc < 3 && (*parv[1] == '!'))
{
fclose(conf);
return 1;
}
fprintf(conf, "%s\n", parv[2]);
if (*parv[1] == '!')
sendto_ops("Added '%s' to services motd", parv[2]);
fclose(conf);
/* We editted it, so rehash it -- codemastr */
read_svsmotd(VPATH);
return 1;
}
/*
** m_addomotd (write a line to opermotd)
**
** De-Potvinized by codemastr
*/
int m_addomotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
char *text;
text = parc > 1 ? parv[1] : NULL;
if (!MyConnect(sptr))
return 0;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDMOTD");
return 0;
}
conf = fopen(OPATH, "a");
if (conf == NULL)
{
return 0;
}
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to OperMotd",
me.name, parv[0], text);
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
} */
fprintf(conf, "%s\n", text);
fclose(conf);
return 1;
}
/*
** m_globops (write to opers who are +g currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_globops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GLOBOPS");
return 0;
}
if (MyClient(sptr) && !OPCanGlobOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_GLOBOPS, TOK_GLOBOPS, ":%s", message);
sendto_failops_whoare_opers("from %s: %s", parv[0], message);
return 0;
}
/*
** m_locops (write to opers who are +g currently online *this* server)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_locops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "LOCOPS");
return 0;
}
if (MyClient(sptr) && !OPCanLocOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_locfailops("from %s: %s", parv[0], message);
return 0;
}
/*
** m_chatops (write to opers who are +b currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_chatops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "CHATOPS");
return 0;
}
if (ALLOW_CHATOPS == 1)
{
if (MyClient(sptr) && !SendChatops(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
parv[0]);
return 0;
}
}
else
{
if (MyClient(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
parv[0]);
return 0;
}
}
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_CHATOPS, TOK_CHATOPS, ":%s", message);
if (ALLOW_CHATOPS == 1)
sendto_umode(UMODE_CHATOP, "*** ChatOps -- from %s: %s",
parv[0], message);
return 0;
}
/* m_goper (Russell) sort of like wallop, but only to ALL +o clients on
** every server.
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_goper(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GOPER");
return 0;
}
/* if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))*/
if (!IsServer(sptr) || !IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone_token(IsServer(cptr) ? cptr : NULL,
parv[0], MSG_GOPER, TOK_GOPER, ":%s", message);
sendto_opers("from %s: %s", parv[0], message);
return 0;
}
/*
** m_time
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_time(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
if (hunt_server(cptr, sptr, ":%s TIME :%s", 1, parc,
parv) == HUNTED_ISME)
sendto_one(sptr, rpl_str(RPL_TIME), me.name, parv[0], me.name,
date((long)0));
return 0;
}
/*
** m_svskill
** parv[0] = servername
** parv[1] = client
** parv[2] = kill message
*/
int m_svskill(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
/* this is very wierd ? */
char *comment = NULL;
if (parc < 2)
return -1;
if (parc > 3)
return -1;
if (parc == 3)
comment = parv[2];
if (parc == 2)
comment = "SVS Killed";
if (!IsULine(cptr, sptr))
return -1;
/* if (hunt_server(cptr,sptr,":%s SVSKILL %s :%s",1,parc,parv) != HUNTED_ISME)
return 0;
*/
if (parc < 1 || (!(acptr = find_client(parv[1], NULL))))
return 0;
sendto_serv_butone(cptr, ":%s SVSKILL %s :%s", parv[0], parv[1],
comment);
return exit_client(cptr, acptr, sptr, comment);
}
/*
** m_admin
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_admin(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aConfItem *aconf;
/* Users may want to get the address in case k-lined, etc. -- Barubary
/* Only allow remote ADMINs if registered -- Barubary */
if (IsPerson(sptr) || IsServer(cptr))
if (hunt_server(cptr, sptr, ":%s ADMIN :%s", 1, parc,
parv) != HUNTED_ISME)
return 0;
if ((aconf = find_admin()))
{
sendto_one(sptr, rpl_str(RPL_ADMINME),
me.name, parv[0], me.name);
sendto_one(sptr, rpl_str(RPL_ADMINLOC1),
me.name, parv[0], (aconf->host ? aconf->host : "-"));
sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
me.name, parv[0], (aconf->passwd ? aconf->passwd : "-"));
sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
me.name, parv[0], (aconf->name ? aconf->name : "-"));
}
else
sendto_one(sptr, err_str(ERR_NOADMININFO),
me.name, parv[0], me.name);
return 0;
}
/*
** m_rehash
** remote rehash by binary
** now allows the -flags in remote rehash
** ugly code but it seems to work :) -- codemastr
*/
int m_rehash(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int x;
if (MyClient(sptr) && !OPCanRehash(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (!MyClient(sptr) && !(IsTechAdmin(sptr) || IsNetAdmin(sptr))
&& !IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
x = 0;
if (!BadPtr(parv[1]))
{
if (*parv[1] == '-')
{
if (!match("-dcc*", parv[1]))
{
sendto_ops
("Rehashing dccdeny.conf on request of %s",
sptr->name);
dcc_rehash();
return 0;
}
if (!match("-dyn*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing dynamic configuration on request of %s",
sptr->name);
load_conf(ZCONF, 1);
return 0;
}
if (!match("-gar*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
do_garbage_collect = 1;
return 0;
}
if (!match("-rest*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing channel restrict configuration on request of %s",
sptr->name);
cr_rehash();
return 0;
}
if (!match("-o*motd", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing OperMOTD on request of %s",
sptr->name);
opermotd = (aMotd *) read_opermotd(OPATH);
return 0;
}
if (!match("-b*motd", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops("Rehashing BotMOTD on request of %s",
sptr->name);
botmotd = (aMotd *) read_botmotd(BPATH);
return 0;
}
if (!match("-motd*", parv[1])
|| !match("-rules*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing all MOTDs and RULES on request of %s",
sptr->name);
motd = (aMotd *) read_motd(MPATH);
rules = (aMotd *) read_rules(RPATH);
read_tlines();
return 0;
}
if (!match("-vhos*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing vhost configuration on request of %s",
sptr->name);
vhost_rehash();
return 0;
}
#ifdef STRIPBADWORDS
if (!match("-bad*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops
("Rehashing badword configuration on request of %s",
sptr->name);
freebadwords();
loadbadwords_channel("badwords.channel.conf");
loadbadwords_message("badwords.message.conf");
return 0;
}
#endif
}
if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
parv[0]);
return 0;
}
/* This little number allows us to send a -param to another server,
* but only if it exists -- codemastr*/
if (parv[2] != NULL)
{
if ((x =
hunt_server(cptr, sptr, ":%s REHASH %s %s", 1, parc,
parv)) != HUNTED_ISME)
return 0;
}
if (parv[2] == NULL)
{
if ((x =
hunt_server(cptr, sptr, ":%s REHASH %s", 1, parc,
parv)) != HUNTED_ISME)
return 0;
}
}
if (cptr != sptr)
{
#ifndef REMOTE_REHASH
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
#else
if (parv[2] == NULL)
{
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing server config file",
me.name, sptr->name);
sendto_ops
("%s is remotely rehashing server config file",
parv[0]);
}
/* Then we have a hack here to parse the flags (thats the ugly part) */
else
{
if (!BadPtr(parv[2]))
{
if (*parv[2] == '-')
{
if (!match("-dcc*", parv[2]))
{
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing dccdeny.conf",
me.name, sptr->name);
sendto_ops
("Remotely rehashing dccdeny.conf on request of %s",
sptr->name);
dcc_rehash();
return 0;
}
if (!match("-dyn*", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing dynamic configuration",
me.name, sptr->name);
sendto_ops
("Remotely rehashing dynamic configuration on request of %s",
sptr->name);
load_conf(ZCONF, 1);
return 0;
}
if (!match("-rest*", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing channel restrict configuration",
me.name, sptr->name);
sendto_ops
("Remotely rehashing channel restrict configuration on request of %s",
sptr->name);
cr_rehash();
return 0;
}
if (!match("-o*motd", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing OperMOTD",
me.name, sptr->name);
sendto_ops
("Remotely rehashing OperMOTD on request of %s",
sptr->name);
opermotd =
(aMotd *)
read_opermotd(OPATH);
return 0;
}
if (!match("-b*motd", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing BotMOTD",
me.name, sptr->name);
sendto_ops
("Remotely rehashing BotMOTD on request of %s",
sptr->name);
botmotd =
(aMotd *)
read_botmotd(BPATH);
return 0;
}
if (!match("-motd*", parv[2])
|| !match("-rules*", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing all MOTDs and RULES",
me.name, sptr->name);
sendto_ops
("Remotely rehashing all MOTDs and RULES on request of %s",
sptr->name);
motd =
(aMotd *) read_motd(MPATH);
rules =
(aMotd *) read_rules(RPATH);
read_tlines();
return 0;
}
if (!match("-vhos*", parv[2]))
{
if (!IsAdmin(sptr))
return 0;
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely rehashing vhost configuration",
me.name, sptr->name);
sendto_ops
("Remotely rehashing vhost configuration on request of %s",
sptr->name);
vhost_rehash();
return 0;
}
}
}
}
#endif
}
else
{
sendto_ops("%s is rehashing server config file", parv[0]);
}
sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
#ifdef USE_SYSLOG
syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
#endif
return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
}
/*
** m_restart
**
** parv[1] - password *OR* reason if no X:line
** parv[2] - reason for restart (optional & only if X:line exists)
**
** The password is only valid if there is a matching X line in the
** config file. If it is not, then it becomes the
*/
int m_restart(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *pass = NULL, *encr;
int x;
#ifdef CRYPT_XLINE_PASSWORD
char salt[3];
extern char *crypt();
#endif
if (MyClient(sptr) && !OPCanRestart(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (!MyClient(sptr) && !(IsTechAdmin(sptr) || IsNetAdmin(sptr))
&& !IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc > 2)
{
/* Remote restart. */
if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
parv[0]);
return 0;
}
if ((x =
hunt_server(cptr, sptr, ":%s RESTART %s %s :%s", 2, parc,
parv)) != HUNTED_ISME)
return 0;
}
if (cptr != sptr)
{
sendto_serv_butone(&me,
":%s GLOBOPS :%s is remotely restarting server (%s)",
me.name, sptr->name, parv[3]);
sendto_ops("%s is remotely restarting IRCd (%s)", parv[0],
parv[3]);
}
if ((pass = find_restartpass()))
{
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
parv[0], "RESTART");
return 0;
}
#ifdef CRYPT_XLINE_PASSWORD
salt[0]=pass[0];
salt[1]=pass[1];
salt[3]='\0';
encr = crypt(parv[1], salt);
#else
encr = parv[1];
#endif
if (strcmp(pass, encr))
{
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name,
parv[0]);
return 0;
}
/* Hack to make the code after this if { } easier: we assign the comment to the
* first param, as if we had not had an X:line. We do not need the password
* now anyways. Accordingly we decrement parc ;) -- NikB
*/
parv[1] = parv[2];
parc--;
}
#ifdef USE_SYSLOG
syslog(LOG_WARNING, "Server RESTART by %s - %s\n",
get_client_name(sptr, FALSE),
(!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
: (parc > 1 ? parv[2] : "No reason")));
#endif
sendto_ops("Server is Restarting by request of %s", parv[0]);
server_reboot((!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
: (parc > 1 ? parv[2] : "No reason")));
return 0;
}
/*
** m_trace
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_trace(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int i;
aClient *acptr;
aClass *cltmp;
char *tname;
int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
int cnt = 0, wilds, dow;
time_t now;
if (parc > 2)
if (hunt_server(cptr, sptr, ":%s TRACE %s :%s", 2, parc, parv))
return 0;
if (parc > 1)
tname = parv[1];
else
tname = me.name;
if (!IsOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
{
case HUNTED_PASS: /* note: gets here only if parv[1] exists */
{
aClient *ac2ptr;
ac2ptr = next_client(client, tname);
sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
version, debugmode, tname, ac2ptr->from->name);
return 0;
}
case HUNTED_ISME:
break;
default:
return 0;
}
doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
wilds = !parv[1] || index(tname, '*') || index(tname, '?');
dow = wilds || doall;
#ifndef _WIN32
for (i = 0; i < MAXCONNECTIONS; i++)
link_s[i] = 0, link_u[i] = 0;
#else
bzero(link_s, sizeof(link_s));
bzero(link_u, sizeof(link_u));
#endif
if (doall)
for (acptr = client; acptr; acptr = acptr->next)
#ifdef SHOW_INVISIBLE_LUSERS
if (IsPerson(acptr))
link_u[acptr->from->fd]++;
#else
if (IsPerson(acptr) &&
(!IsInvisible(acptr) || IsOper(sptr)))
link_u[acptr->from->fd]++;
#endif
else if (IsServer(acptr))
link_s[acptr->from->fd]++;
/* report all direct connections */
now = TStime();
for (i = 0; i <= highest_fd; i++)
{
char *name;
int class;
if (!(acptr = local[i])) /* Local Connection? */
continue;
/* More bits of code to allow oers to see all users on remote traces
* if (IsInvisible(acptr) && dow &&
* if (dow &&
* !(MyConnect(sptr) && IsOper(sptr)) && */
if (!IsOper(sptr) && !IsAnOper(acptr) && (acptr != sptr))
continue;
if (!doall && wilds && match(tname, acptr->name))
continue;
if (!dow && mycmp(tname, acptr->name))
continue;
name = get_client_name(acptr, FALSE);
class = get_client_class(acptr);
switch (acptr->status)
{
case STAT_CONNECTING:
sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
me.name, parv[0], class, name);
cnt++;
break;
case STAT_HANDSHAKE:
sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name,
parv[0], class, name);
cnt++;
break;
case STAT_ME:
break;
case STAT_UNKNOWN:
sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
me.name, parv[0], class, name);
cnt++;
break;
case STAT_CLIENT:
/* Only opers see users if there is a wildcard
* but anyone can see all the opers.
*/
/* if (IsOper(sptr) &&
* Allow opers to see invisible users on a remote trace or wildcard
* search ... sure as hell helps to find clonebots. --Russell
* (MyClient(sptr) || !(dow && IsInvisible(acptr)))
* || !dow || IsAnOper(acptr)) */
if (IsOper(sptr) ||
(IsAnOper(acptr) && !IsInvisible(acptr)))
{
if (IsAnOper(acptr))
sendto_one(sptr,
rpl_str(RPL_TRACEOPERATOR),
me.name,
parv[0], class, acptr->name,
IsHidden(acptr) ? acptr->
user->virthost : acptr->user->
realhost, now - acptr->lasttime);
else
sendto_one(sptr,
rpl_str(RPL_TRACEUSER), me.name,
parv[0], class, acptr->name,
acptr->user->realhost,
now - acptr->lasttime);
cnt++;
}
break;
case STAT_SERVER:
if (acptr->serv->user)
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], class, link_s[i],
link_u[i], name, acptr->serv->by,
acptr->serv->user->username,
acptr->serv->user->realhost,
now - acptr->lasttime);
else
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], class, link_s[i],
link_u[i], name, *(acptr->serv->by) ?
acptr->serv->by : "*", "*", me.name,
now - acptr->lasttime);
cnt++;
break;
case STAT_LOG:
sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name,
parv[0], LOGFILE, acptr->port);
cnt++;
break;
default: /* ...we actually shouldn't come here... --msa */
sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name,
parv[0], name);
cnt++;
break;
}
}
/*
* Add these lines to summarize the above which can get rather long
* and messy when done remotely - Avalon
*/
if (!IsAnOper(sptr) || !cnt)
{
if (cnt)
return 0;
/* let the user have some idea that its at the end of the
* trace
*/
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], 0, link_s[me.fd],
link_u[me.fd], me.name, "*", "*", me.name);
return 0;
}
for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
if (Links(cltmp) > 0)
sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
parv[0], Class(cltmp), Links(cltmp));
return 0;
}
/*
* Heavily modified from the ircu m_motd by codemastr
* Also svsmotd support added
*/
int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aTrecord *ptr;
aMotd *temp, *temp2;
struct tm *tm = motd_tm;
int svsnofile = 0;
if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1, parc,
parv) != HUNTED_ISME)
return 0;
#ifndef TLINE_Remote
if (!MyConnect(sptr))
{
temp = motd;
goto playmotd;
}
#endif
for (ptr = tdata; ptr; ptr = ptr->next)
{
if (!match(ptr->hostmask, cptr->user->realhost))
break;
}
if (ptr)
{
temp = ptr->tmotd;
tm = ptr->tmotd_tm;
}
else
temp = motd;
playmotd:
if (temp == NULL)
{
sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
svsnofile = 1;
goto svsmotd;
}
if (tm)
{
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0],
me.name);
sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name,
RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1,
1900 + tm->tm_year, tm->tm_hour, tm->tm_min);
}
while (temp)
{
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
temp->line);
temp = temp->next;
}
svsmotd:
temp2 = svsmotd;
while (temp2)
{
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
temp2->line);
temp2 = temp2->next;
}
if (svsnofile == 0)
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
return 0;
}
/*
* Modified from comstud by codemastr
*/
int m_opermotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aMotd *temp;
if (!IsAnOper(sptr))
return 0;
if (opermotd == (aMotd *) NULL)
{
sendto_one(sptr, err_str(ERR_NOOPERMOTD), me.name, parv[0]);
return 0;
}
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
"\2IRC Operator Message of the Day\2");
temp = opermotd;
while (temp)
{
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
temp->line);
temp = temp->next;
}
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
return 0;
}
/* read_tlines
* Read info from T:lines into trecords which include the file
* timestamp, the hostmask, and the contents of the motd file
* -Ghostwolf 7sep97
* Modified for Unreal and to support RULES by codemastr
*/
void read_tlines()
{
aConfItem *tmp;
aTrecord *temp, *last = NULL; /* Init. to avoid compiler warning */
aMotd *amotd, *arules;
/* Free the old trecords and the associated motd contents first */
while (tdata)
{
last = tdata->next;
while (tdata->tmotd)
{
amotd = tdata->tmotd->next;
MyFree(tdata->tmotd);
tdata->tmotd = amotd;
}
/* Clear rules too */
while (tdata->trules)
{
arules = tdata->trules->next;
MyFree(tdata->trules);
tdata->trules = arules;
}
MyFree(tdata);
tdata = last;
}
for (tmp = conf; tmp; tmp = tmp->next)
if (tmp->status == CONF_TLINE && tmp->host && tmp->passwd)
{
temp = (aTrecord *) MyMalloc(sizeof(aTrecord));
if (!temp)
outofmemory();
temp->hostmask = tmp->host;
temp->tmotd = read_motd(tmp->passwd);
temp->trules = read_rules(tmp->name);
temp->tmotd_tm = motd_tm;
temp->next = NULL;
if (!tdata)
tdata = temp;
else
last->next = temp;
last = temp;
}
}
/*
* A merge from ircu and bahamut, and some extra stuff added by codemastr
*/
aMotd *read_svsmotd(char *filename)
{
int fd = open(filename, O_RDONLY);
aMotd *temp, *newmotd, *last, *old;
char line[82];
char *tmp;
int i;
if (fd == -1)
return NULL;
while (svsmotd)
{
old = svsmotd->next;
MyFree(svsmotd);
svsmotd = old;
}
newmotd = last = NULL;
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
{
line[i] = '\0';
if ((tmp = (char *)strchr(line, '\n')))
*tmp = '\0';
if ((tmp = (char *)strchr(line, '\r')))
*tmp = '\0';
temp = (aMotd *) MyMalloc(sizeof(aMotd));
if (!temp)
outofmemory();
strcpy(temp->line, line);
temp->next = NULL;
if (!newmotd)
newmotd = temp;
else
last->next = temp;
last = temp;
}
close(fd);
return newmotd;
}
/*
* A merge from ircu and bahamut, and some extra stuff added by codemastr
*/
aMotd *read_rules(char *filename)
{
int fd = open(filename, O_RDONLY);
aMotd *temp, *newmotd, *last, *old;
char line[82];
char *tmp;
int i;
if (fd == -1)
return NULL;
/* If it is the default RULES, clear it -- codemastr */
if (!stricmp(filename, RPATH))
{
while (rules)
{
old = rules->next;
MyFree(rules);
rules = old;
}
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
newmotd = last = NULL;
while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
{
line[i] = '\0';
if ((tmp = (char *)strchr(line, '\n')))
*tmp = '\0';
if ((tmp = (char *)strchr(line, '\r')))
*tmp = '\0';
temp = (aMotd *) MyMalloc(sizeof(aMotd));
if (!temp)
outofmemory();
strcpy(temp->line, line);
temp->next = NULL;
if (!newmotd)
newmotd = temp;
else
last->next = temp;
last = temp;
}
close(fd);
return newmotd;
}
/*
* A merge from ircu and bahamut, and some extra stuff added by codemastr
*/
aMotd *read_motd(char *filename)
{
int fd = open(filename, O_RDONLY);
aMotd *temp, *newmotd, *last, *old;
struct stat sb;
char line[82];
char *tmp;
int i;
if (fd == -1)
return NULL;
fstat(fd, &sb);
/* If it is the default MOTD, clear it -- codemastr */
if (!stricmp(filename, MPATH))
{
while (motd)
{
old = motd->next;
MyFree(motd);
motd = old;
}
/* We also wanna set it's last changed value -- codemastr */
motd_tm = localtime(&sb.st_mtime);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
newmotd = last = NULL;
while ((i = dgets(fd, line, 81)) > 0)
{
line[i] = '\0';
if ((tmp = (char *)strchr(line, '\n')))
*tmp = '\0';
if ((tmp = (char *)strchr(line, '\r')))
*tmp = '\0';
temp = (aMotd *) MyMalloc(sizeof(aMotd));
if (!temp)
outofmemory();
strcpy(temp->line, line);
temp->next = NULL;
if (!newmotd)
newmotd = temp;
else
last->next = temp;
last = temp;
}
close(fd);
return newmotd;
}
/*
* A merge from ircu and bahamut, and some extra stuff added by codemastr
*/
aMotd *read_opermotd(char *filename)
{
int fd = open(filename, O_RDONLY);
aMotd *temp, *newmotd, *last, *old;
char line[82];
char *tmp;
int i;
if (fd == -1)
return NULL;
while (opermotd)
{
old = opermotd->next;
MyFree(opermotd);
opermotd = old;
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
newmotd = last = NULL;
while ((i = dgets(fd, line, 81)) > 0)
{
line[i] = '\0';
if ((tmp = (char *)strchr(line, '\n')))
*tmp = '\0';
if ((tmp = (char *)strchr(line, '\r')))
*tmp = '\0';
temp = (aMotd *) MyMalloc(sizeof(aMotd));
if (!temp)
outofmemory();
strcpy(temp->line, line);
temp->next = NULL;
if (!newmotd)
newmotd = temp;
else
last->next = temp;
last = temp;
}
close(fd);
return newmotd;
}
/*
* A merge from ircu and bahamut, and some extra stuff added by codemastr
*/
aMotd *read_botmotd(char *filename)
{
int fd = open(filename, O_RDONLY);
aMotd *temp, *newmotd, *last, *old;
char line[82];
char *tmp;
int i;
if (fd == -1)
return NULL;
while (botmotd)
{
old = botmotd->next;
MyFree(botmotd);
botmotd = old;
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
newmotd = last = NULL;
while (i = dgets(fd, line, 81) > 0)
{
line[i] = '\0';
if ((tmp = (char *)strchr(line, '\n')))
*tmp = '\0';
if ((tmp = (char *)strchr(line, '\r')))
*tmp = '\0';
temp = (aMotd *) MyMalloc(sizeof(aMotd));
if (!temp)
outofmemory();
strcpy(temp->line, line);
temp->next = NULL;
if (!newmotd)
newmotd = temp;
else
last->next = temp;
last = temp;
}
close(fd);
return newmotd;
}
/*
* Modified from comstud by codemastr
*/
int m_botmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aMotd *temp;
if (hunt_server(cptr, sptr, ":%s BOTMOTD :%s", 1, parc,
parv) != HUNTED_ISME)
return 0;
if (botmotd == (aMotd *) NULL)
{
sendto_one(sptr, ":%s NOTICE AUTH :BOTMOTD File not found",
me.name);
return 0;
}
sendto_one(sptr, ":%s NOTICE AUTH :- %s Bot Message of the Day - ",
me.name, me.name);
temp = botmotd;
while (temp)
{
sendto_one(sptr, ":%s NOTICE AUTH :- %s", me.name, temp->line);
temp = temp->next;
}
sendto_one(sptr, ":%s NOTICE AUTH :End of /BOTMOTD command.", me.name);
return 0;
}
/*
* Heavily modified from the ircu m_motd by codemastr
* Also svsmotd support added
*/
int m_rules(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aTrecord *ptr;
aMotd *temp;
if (hunt_server(cptr, sptr, ":%s RULES :%s", 1, parc,
parv) != HUNTED_ISME)
return 0;
#ifndef TLINE_Remote
if (!MyConnect(sptr))
{
temp = rules;
goto playrules;
}
#endif
for (ptr = tdata; ptr; ptr = ptr->next)
{
if (!match(ptr->hostmask, cptr->user->realhost))
break;
}
if (ptr)
{
temp = ptr->trules;
}
else
temp = rules;
playrules:
if (temp == NULL)
{
sendto_one(sptr, err_str(ERR_NORULES), me.name, parv[0]);
return 0;
}
sendto_one(sptr, rpl_str(RPL_RULESSTART), me.name, parv[0], me.name);
while (temp)
{
sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0],
temp->line);
temp = temp->next;
}
sendto_one(sptr, rpl_str(RPL_ENDOFRULES), me.name, parv[0]);
return 0;
}
/*
** m_close - added by Darren Reed Jul 13 1992.
*/
int m_close(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
int i;
int closed = 0;
if (!MyOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
for (i = highest_fd; i; i--)
{
if (!(acptr = local[i]))
continue;
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
!IsHandshake(acptr))
continue;
sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
get_client_name(acptr, TRUE), acptr->status);
(void)exit_client(acptr, acptr, acptr, "Oper Closing");
closed++;
}
sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
sendto_realops("%s!%s@%s closed %d unknown connections", sptr->name,
sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost, closed);
IRCstats.unknown = 0;
return 0;
}
/* m_die, this terminates the server, and it intentionally does not
* have a reason. If you use it you should first do a GLOBOPS and
* then a server notice to let everyone know what is going down...
*/
int m_die(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
int i;
char *pass = NULL, *encr;
#ifdef CRYPT_XLINE_PASSWORD
char salt[3];
extern char *crypt();
#endif
if (!MyClient(sptr) || !OPCanDie(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if ((pass = find_diepass())) /* See if we have and DIE/RESTART password */
{
if (parc < 2) /* And if so, require a password :) */
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name,
parv[0], "DIE");
return 0;
}
#ifdef CRYPT_XLINE_PASSWORD
salt[0] = pass[0];
salt[1] = pass[1];
salt[3] = '\0';
encr = crypt(parv[1], salt);
#else
encr = parv[1];
#endif
if (strcmp(pass,encr))
{
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name,
parv[0]);
return 0;
}
}
/* Let the +s know what is going on */
sendto_ops("Server Terminating by request of %s", parv[0]);
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsClient(acptr))
sendto_one(acptr,
":%s NOTICE %s :Server Terminating. %s",
me.name, acptr->name, get_client_name(sptr, TRUE));
else if (IsServer(acptr))
sendto_one(acptr, ":%s ERROR :Terminated by %s",
me.name, get_client_name(sptr, TRUE));
}
(void)s_die();
return 0;
}
char servername[128][128];
int server_usercount[128];
int numservers = 0;
/*
* New /MAP format -Potvin
* dump_map function.
*/
void dump_map(cptr, server, mask, prompt_length, length)
aClient *cptr, *server;
char *mask;
int prompt_length;
int length;
{
static char prompt[64];
char *p = &prompt[prompt_length];
int cnt = 0, local = 0;
aClient *acptr;
*p = '\0';
if (prompt_length > 60)
sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name,
prompt, server->name);
else
{
for (acptr = client; acptr; acptr = acptr->next)
{
if (IsPerson(acptr))
{
++cnt; /* == */
if (!strcmp(acptr->user->server, server->name))
++local;
}
}
sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt,
length, server->name, local, (local * 100) / cnt);
cnt = 0;
}
if (prompt_length > 0)
{
p[-1] = ' ';
if (p[-2] == '`')
p[-2] = ' ';
}
if (prompt_length > 60)
return;
strcpy(p, "|-");
for (acptr = client; acptr; acptr = acptr->next)
{
if (HIDE_ULINES == 1)
{
if (!IsServer(acptr) || strcmp(acptr->serv->up, server->name))
continue;
if (IsULine(acptr, acptr)
&& !IsAnOper(cptr))
continue;
}
if (match(mask, acptr->name))
acptr->flags &= ~FLAGS_MAP;
else
{
acptr->flags |= FLAGS_MAP;
cnt++;
}
}
for (acptr = client; acptr; acptr = acptr->next)
{
if (!(acptr->flags & FLAGS_MAP) || /* != */
!IsServer(acptr) || strcmp(acptr->serv->up, server->name))
continue;
if (HIDE_ULINES == 1) {
if (IsULine(acptr,acptr) && !IsAnOper(cptr))
continue;
}
if (--cnt == 0)
*p = '`';
dump_map(cptr, acptr, mask, prompt_length + 2, length - 2);
}
if (prompt_length > 0)
p[-1] = '-';
}
/*
** New /MAP format. -Potvin
** m_map (NEW)
**
** parv[0] = sender prefix
** parv[1] = server mask
**/
int m_map(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
int longest = strlen(me.name);
if (parc < 2)
parv[1] = "*";
for (acptr = client; acptr; acptr = acptr->next)
if (IsServer(acptr)
&& (strlen(acptr->name) + acptr->hopcount * 2) > longest)
longest = strlen(acptr->name) + acptr->hopcount * 2;
if (longest > 60)
longest = 60;
longest += 2;
dump_map(sptr, &me, "*", 0, longest);
sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
return 0;
}
#ifdef _WIN32
/*
* Added to let the local console shutdown the server without just
* calling exit(-1), in Windows mode. -Cabal95
*/
int localdie(void)
{
aClient *acptr;
int i;
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsClient(acptr))
sendto_one(acptr,
":%s NOTICE %s :Server Terminated by local console",
me.name, acptr->name);
else if (IsServer(acptr))
sendto_one(acptr,
":%s ERROR :Terminated by local console", me.name);
}
(void)s_die();
return 0;
}
#endif