mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-30 04:56:38 +02:00
4923 lines
120 KiB
C
4923 lines
120 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
|
|
#define AllocCpy(x,y) x = (char *) MyMalloc(strlen(y) + 1); strcpy(x,y)
|
|
|
|
#include "struct.h"
|
|
#include "common.h"
|
|
#include "sys.h"
|
|
#include "numeric.h"
|
|
#include "msg.h"
|
|
#include "channel.h"
|
|
#include "userload.h"
|
|
#include "version.h"
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include "h.h"
|
|
#include <string.h>
|
|
|
|
|
|
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;
|
|
struct tm *motd_tm;
|
|
aMotd *read_file(char *filename, aMotd **list);
|
|
aMotd *read_motd(char *filename);
|
|
aMotd *read_rules(char *filename);
|
|
|
|
/*
|
|
** 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);
|
|
if (MyClient(sptr))
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_PROTOCTL), me.name,
|
|
sptr->name, PROTOCTL_PARAMETERS);
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
if (!(*parv[1] == '@'))
|
|
{
|
|
server = parv[1];
|
|
|
|
/*
|
|
** 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
|
|
{
|
|
server = parv[1];
|
|
acptr = (aClient *)find_server_by_base64(server + 1);
|
|
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, "NS") == 0)
|
|
{
|
|
#ifdef PROTOCTL_MADNESS
|
|
if (remove)
|
|
{
|
|
ClearNS(cptr);
|
|
continue;
|
|
}
|
|
#endif
|
|
Debug((DEBUG_ERROR,
|
|
"Chose protocol %s for link %s",
|
|
proto, cptr->name));
|
|
SetNS(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);
|
|
}
|
|
else if (strcmp(s, "SJB64") == 0)
|
|
{
|
|
#ifndef PROTOCTL_MADNESS
|
|
if (remove)
|
|
{
|
|
cptr->proto &= ~PROTO_SJB64;
|
|
continue;
|
|
}
|
|
#endif
|
|
Debug((DEBUG_ERROR,
|
|
"Chose protocol %s for link %s",
|
|
proto, cptr->name));
|
|
cptr->proto |= PROTO_SJB64;
|
|
}
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
char *num = NULL;
|
|
int m_server_synch(aClient *cptr, long numeric, ConfigItem_link *conf);
|
|
|
|
/*
|
|
** m_server
|
|
** parv[0] = sender prefix
|
|
** parv[1] = servername
|
|
** parv[2] = hopcount
|
|
** parv[3] = numeric
|
|
** parv[4] = serverinfo
|
|
**
|
|
** on old protocols, serverinfo is parv[3], and numeric is left out
|
|
**
|
|
** Recode 2001 by Stskeeps
|
|
*/
|
|
int m_server(cptr, sptr, parc, parv)
|
|
aClient *cptr, *sptr;
|
|
int parc;
|
|
char *parv[];
|
|
{
|
|
char *servername = NULL; /* Pointer for servername */
|
|
char *password = NULL;
|
|
char *ch = NULL; /* */
|
|
char *inpath = get_client_name(cptr, TRUE);
|
|
aClient *acptr = NULL, *ocptr = NULL;
|
|
ConfigItem_ban *bconf;
|
|
int hop = 0, numeric = 0;
|
|
char info[REALLEN + 61];
|
|
ConfigItem_link *aconf = NULL;
|
|
ConfigItem_deny_link *deny;
|
|
char *flags = NULL, *protocol = NULL, *inf = NULL;
|
|
|
|
|
|
/* Ignore it */
|
|
if (IsPerson(sptr))
|
|
{
|
|
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);
|
|
sptr->since += 7;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We do some parameter checks now. We want atleast upto serverinfo now
|
|
*/
|
|
if (parc < 4 || (!*parv[3]))
|
|
{
|
|
sendto_one(sptr, "ERROR :Not enough SERVER parameters");
|
|
return 0;
|
|
}
|
|
|
|
if (IsUnknown(cptr) && (cptr->listener->umodes & LISTENER_CLIENTSONLY))
|
|
{
|
|
return exit_client(cptr, sptr, sptr,
|
|
"This port is for clients only");
|
|
}
|
|
|
|
/* Now, let us take a look at the parameters we got
|
|
* Passes here:
|
|
* Check for bogus server name
|
|
*/
|
|
|
|
servername = parv[1];
|
|
/* Cut off if too big */
|
|
if (strlen(servername) > HOSTLEN)
|
|
servername[HOSTLEN] = '\0';
|
|
/* Check if bogus, like spaces and ~'s */
|
|
for (ch = servername; *ch; ch++)
|
|
if (*ch <= ' ' || *ch > '~')
|
|
break;
|
|
if (*ch || !index(servername, '.'))
|
|
{
|
|
sendto_one(sptr, "ERROR :Bogus server name (%s)",
|
|
sptr->name, servername);
|
|
sendto_umode
|
|
(UMODE_JUNK,
|
|
"WARNING: Bogus server name (%s) from %s (maybe just a fishy client)",
|
|
servername, get_client_name(cptr, TRUE));
|
|
|
|
return exit_client(cptr, sptr, sptr, "Bogus server name");
|
|
}
|
|
|
|
if ((IsUnknown(cptr) || IsHandshake(cptr)) && !cptr->passwd)
|
|
{
|
|
sendto_one(sptr, "ERROR :Missing password");
|
|
return exit_client(cptr, sptr, sptr, "Missing password");
|
|
}
|
|
|
|
/*
|
|
* Now, we can take a look at it all
|
|
*/
|
|
if (IsUnknown(cptr) || IsHandshake(cptr))
|
|
{
|
|
/* For now, we don't check based on DNS, it is slow, and IPs
|
|
are better */
|
|
aconf = Find_link(cptr->username, cptr->sockhost, cptr->sockhost,
|
|
servername);
|
|
if (!aconf)
|
|
{
|
|
sendto_one(cptr,
|
|
"ERROR :Link denied (No matching link configuration) %s",
|
|
inpath);
|
|
sendto_locfailops
|
|
("Link denied (No matching link configuration) %s",
|
|
inpath);
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Link denied (No matching link configuration)");
|
|
}
|
|
/* Now for checking passwords */
|
|
#ifdef CRYPT_LINK_PASSWORD
|
|
if (!BadPtr(cptr->passwd))
|
|
{
|
|
char salt[3];
|
|
char *encr;
|
|
extern char *crypt();
|
|
|
|
salt[0] = aconf->recvpwd[0];
|
|
salt[1] = aconf->recvpwd[1];
|
|
salt[2] = '\0';
|
|
|
|
password = crypt(cptr->passwd, salt);
|
|
}
|
|
else
|
|
{
|
|
password = "";
|
|
}
|
|
#else
|
|
password = cptr->passwd;
|
|
#endif
|
|
if (!StrEq(aconf->recvpwd, password))
|
|
{
|
|
sendto_one(cptr,
|
|
"ERROR :Link denied (Passwords don't match) %s",
|
|
inpath);
|
|
sendto_locfailops
|
|
("Link denied (Passwords don't match) %s", inpath);
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Link denied (Passwords don't match)");
|
|
}
|
|
|
|
/*
|
|
* Third phase, we check that the server does not exist
|
|
* already
|
|
*/
|
|
if ((acptr = find_server(servername, NULL)))
|
|
{
|
|
/* Found. Bad. Quit. */
|
|
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",
|
|
servername,
|
|
(ocptr->from ? ocptr->from->name : "<nobody>"));
|
|
sendto_ops
|
|
("Link %s cancelled, server %s already exists from %s",
|
|
get_client_name(acptr, TRUE), servername,
|
|
(ocptr->from ? ocptr->from->name : "<nobody>"));
|
|
return exit_client(acptr, acptr, acptr,
|
|
"Server Exists");
|
|
}
|
|
if (bconf = Find_ban(servername, CONF_BAN_SERVER))
|
|
{
|
|
sendto_realops
|
|
("Cancelling link %s, banned server",
|
|
get_client_name(cptr, TRUE));
|
|
sendto_one(cptr, "ERROR :Banned server (%s)", bconf->reason ? bconf->reason : "no reason");
|
|
return exit_client(cptr, cptr, &me, "Banned server");
|
|
}
|
|
if (aconf->class->clients + 1 > aconf->class->maxclients)
|
|
{
|
|
sendto_realops
|
|
("Cancelling link %s, full class",
|
|
get_client_name(cptr, TRUE));
|
|
return exit_client(cptr, cptr, &me, "Full class");
|
|
}
|
|
/* OK, let us check in the data now now */
|
|
hop = TS2ts(parv[2]);
|
|
numeric = (parc > 4) ? TS2ts(parv[3]) : 0;
|
|
(void)strncpy(info, parv[parc - 1], REALLEN + 60);
|
|
strncpyzt(cptr->name, servername, sizeof(cptr->name));
|
|
cptr->hopcount = hop;
|
|
/* Add ban server stuff */
|
|
if (SupportVL(cptr))
|
|
{
|
|
/* we also have a fail safe incase they say they are sending
|
|
* VL stuff and don't -- codemastr
|
|
*/
|
|
ConfigItem_deny_version *vlines;
|
|
inf = NULL;
|
|
protocol = NULL;
|
|
flags = NULL;
|
|
num = NULL;
|
|
protocol = (char *)strtok((char *)info, "-");
|
|
if (protocol)
|
|
flags = (char *)strtok((char *)NULL, "-");
|
|
if (flags)
|
|
num = (char *)strtok((char *)NULL, " ");
|
|
if (num)
|
|
inf = (char *)strtok((char *)NULL, "");
|
|
if (inf) {
|
|
strncpyzt(cptr->info, inf[0] ? inf : me.name,
|
|
sizeof(cptr->info));
|
|
|
|
for (vlines = conf_deny_version; vlines; vlines = (ConfigItem_deny_version *) vlines->next) {
|
|
if (!match(vlines->mask, cptr->name))
|
|
break;
|
|
}
|
|
if (vlines) {
|
|
char *proto = vlines->version;
|
|
char *vflags = vlines->flags;
|
|
int version, result = 0, i;
|
|
protocol++;
|
|
version = atoi(protocol);
|
|
switch (*proto) {
|
|
case '<':
|
|
proto++;
|
|
if (version < atoi(proto))
|
|
result = 1;
|
|
break;
|
|
case '>':
|
|
proto++;
|
|
if (version > atoi(proto))
|
|
result = 1;
|
|
break;
|
|
case '=':
|
|
proto++;
|
|
if (version == atoi(proto))
|
|
result = 1;
|
|
break;
|
|
case '!':
|
|
proto++;
|
|
if (version != atoi(proto))
|
|
result = 1;
|
|
break;
|
|
default:
|
|
if (version == atoi(proto))
|
|
result = 1;
|
|
break;
|
|
}
|
|
if (version == 0 || *proto == '*')
|
|
result = 0;
|
|
|
|
if (result)
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Denied by V:line");
|
|
|
|
for (i = 0; vflags[i]; i++) {
|
|
if (vflags[i] == '!') {
|
|
i++;
|
|
if (strchr(flags, vflags[i])) {
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
else if (!strchr(flags, vflags[i])) {
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (*vflags == '*' || !strcmp(flags, "0"))
|
|
result = 0;
|
|
if (result)
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Denied by V:line");
|
|
}
|
|
}
|
|
else
|
|
strncpyzt(cptr->info, info[0] ? info : me.name,
|
|
sizeof(cptr->info));
|
|
|
|
}
|
|
else
|
|
strncpyzt(cptr->info, info[0] ? info : me.name,
|
|
sizeof(cptr->info));
|
|
/* Numerics .. */
|
|
numeric = num ? atol(num) : numeric;
|
|
if (numeric)
|
|
{
|
|
if (numeric_collides(numeric))
|
|
{
|
|
sendto_locfailops("Link %s denied, colliding server numeric",
|
|
inpath);
|
|
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Colliding server numeric (choose another)");
|
|
}
|
|
}
|
|
for (deny = conf_deny_link; deny; deny = (ConfigItem_deny_link *) deny->next) {
|
|
if (deny->flag.type == CRULE_ALL && !match(deny->mask, servername)
|
|
&& crule_eval(deny->rule)) {
|
|
sendto_ops("Refused connection from %s.",
|
|
get_client_host(cptr));
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Disallowed by connection rule");
|
|
}
|
|
}
|
|
|
|
/* Start synch now */
|
|
m_server_synch(cptr, numeric, aconf);
|
|
}
|
|
else
|
|
{
|
|
m_server_remote(cptr, sptr, parc, parv);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int m_server_remote(aClient *cptr, aClient *sptr, int parc, char *parv[])
|
|
{
|
|
aClient *acptr, *ocptr, *bcptr;
|
|
ConfigItem_link *aconf;
|
|
ConfigItem_ban *bconf;
|
|
int hop;
|
|
char info[REALLEN + 61];
|
|
long numeric = 0;
|
|
char *servername = parv[1];
|
|
int i;
|
|
|
|
if ((acptr = find_server(servername, NULL)))
|
|
{
|
|
/* Found. Bad. Quit. */
|
|
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",
|
|
servername,
|
|
(ocptr->from ? ocptr->from->name : "<nobody>"));
|
|
sendto_ops
|
|
("Link %s cancelled, server %s already exists from %s",
|
|
get_client_name(acptr, TRUE), servername,
|
|
(ocptr->from ? ocptr->from->name : "<nobody>"));
|
|
return exit_client(acptr, acptr, acptr,
|
|
"Server Exists");
|
|
}
|
|
if (bconf = Find_ban(servername, CONF_BAN_SERVER))
|
|
{
|
|
sendto_realops
|
|
("Cancelling link %s, banned server %s",
|
|
get_client_name(cptr, TRUE), servername);
|
|
sendto_one(cptr, "ERROR :Banned server (%s)", bconf->reason ? bconf->reason : "no reason");
|
|
return exit_client(cptr, cptr, &me, "Brought in banned server");
|
|
}
|
|
/* OK, let us check in the data now now */
|
|
hop = TS2ts(parv[2]);
|
|
numeric = (parc > 4) ? TS2ts(parv[3]) : 0;
|
|
(void)strncpy(info, parv[parc - 1], REALLEN + 60);
|
|
if (!cptr->serv->conf)
|
|
{
|
|
sendto_realops("Lost conf for %s!!, dropping link", cptr->name);
|
|
return exit_client(cptr, cptr, cptr, "Lost configuration");
|
|
}
|
|
aconf = cptr->serv->conf;
|
|
if (aconf->leafmask)
|
|
{
|
|
if (!match(aconf->leafmask, servername))
|
|
{
|
|
sendto_locfailops("Link %s(%s) cancelled, disallowed by leaf configuration", cptr->name, servername);
|
|
return exit_client(cptr, cptr, cptr, "Disallowed by leaf configuration");
|
|
}
|
|
}
|
|
if (aconf->leafdepth && (hop > aconf->leafdepth))
|
|
{
|
|
sendto_locfailops("Link %s(%s) cancelled, too deep depth", cptr->name, servername);
|
|
return exit_client(cptr, cptr, cptr, "Too deep link depth (leaf)");
|
|
}
|
|
/* ADD: ban server code */
|
|
if (numeric)
|
|
{
|
|
if (numeric_collides(numeric))
|
|
{
|
|
sendto_locfailops("Link %s(%s) cancelled, colliding server numeric",
|
|
cptr->name, servername);
|
|
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Colliding server numeric (choose another)");
|
|
}
|
|
}
|
|
acptr = make_client(cptr, find_server_quick(parv[0]));
|
|
(void)make_server(acptr);
|
|
acptr->serv->numeric = numeric;
|
|
acptr->hopcount = hop;
|
|
strncpyzt(acptr->name, servername, 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(cptr)
|
|
|| (Find_uline(acptr->name)))
|
|
acptr->flags |= FLAGS_ULINE;
|
|
add_server_to_table(acptr);
|
|
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);
|
|
for (i = 0; i <= highest_fd; i++)
|
|
{
|
|
if (!(bcptr = local[i]) || !IsServer(bcptr) ||
|
|
bcptr == cptr || IsMe(bcptr))
|
|
continue;
|
|
if (SupportNS(bcptr))
|
|
{
|
|
sendto_one(bcptr,
|
|
"%c%s %s %s %d %i :%s",
|
|
(sptr->serv->numeric ? '@' : ':'),
|
|
(sptr->serv->numeric ? base64enc(sptr->serv->numeric) : sptr->name),
|
|
IsToken(bcptr) ? TOK_SERVER : MSG_SERVER,
|
|
acptr->name, hop + 1, numeric, acptr->info);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(bcptr, ":%s %s %s %d :%s",
|
|
parv[0],
|
|
IsToken(bcptr) ? TOK_SERVER : MSG_SERVER,
|
|
acptr->name, hop + 1, acptr->info);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int m_server_synch(aClient *cptr, long numeric, ConfigItem_link *aconf)
|
|
{
|
|
char *servername = cptr->name;
|
|
char *inpath = get_client_name(cptr, TRUE);
|
|
extern char serveropts[];
|
|
aClient *acptr;
|
|
aChannel *chptr;
|
|
int i;
|
|
|
|
current_load_data.conn_count++;
|
|
update_load();
|
|
|
|
if (cptr->passwd)
|
|
{
|
|
MyFree(cptr->passwd);
|
|
cptr->passwd = NULL;
|
|
}
|
|
if (IsUnknown(cptr))
|
|
{
|
|
sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
|
|
sendto_one(cptr, "PASS :%s", aconf->connpwd);
|
|
sendto_one(cptr, "SERVER %s 1 :U%d-%s-%i %s",
|
|
me.name, UnrealProtocol,
|
|
serveropts, me.serv->numeric,
|
|
(me.info[0]) ? (me.info) : "IRCers United");
|
|
}
|
|
/* Set up server structure */
|
|
SetServer(cptr);
|
|
IRCstats.me_servers++;
|
|
IRCstats.servers++;
|
|
IRCstats.unknown--;
|
|
#ifndef NO_FDLIST
|
|
addto_fdlist(cptr->fd, &serv_fdlist);
|
|
#endif
|
|
if ((Find_uline(cptr->name)))
|
|
cptr->flags |= FLAGS_ULINE;
|
|
cptr->flags |= FLAGS_TS8;
|
|
nextping = TStime();
|
|
(void)find_or_add(cptr->name);
|
|
#ifdef USE_SSL
|
|
if (IsSecure(cptr))
|
|
{
|
|
sendto_serv_butone(&me, ":%s SMO o :(\2link\2) Secure link %s -> %s established (%s)",
|
|
me.name, me.name, inpath, (char *) ssl_get_cipher((SSL *)cptr->ssl));
|
|
sendto_realops("(\2link\2) Secure link %s -> %s established (%s)",
|
|
me.name, inpath, (char *) ssl_get_cipher((SSL *)cptr->ssl));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
sendto_serv_butone(&me, ":%s SMO o :(\2link\2) Link %s -> %s established",
|
|
me.name, me.name, inpath);
|
|
sendto_realops("(\2link\2) Link %s -> %s established",
|
|
me.name, inpath);
|
|
}
|
|
(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->numeric = numeric;
|
|
cptr->serv->conf = aconf;
|
|
cptr->serv->conf->refcount++;
|
|
cptr->serv->conf->class->clients++;
|
|
cptr->class = cptr->serv->conf->class;
|
|
add_server_to_table(cptr);
|
|
for (i = 0; i <= highest_fd; i++)
|
|
{
|
|
if (!(acptr = local[i]) || !IsServer(acptr) ||
|
|
acptr == cptr || IsMe(acptr))
|
|
continue;
|
|
|
|
if (SupportNS(acptr))
|
|
{
|
|
sendto_one(acptr, "%c%s %s %s 2 %i :%s",
|
|
(me.serv->numeric ? '@' : ':'),
|
|
(me.serv->numeric ? base64enc(me.
|
|
serv->numeric) : me.name),
|
|
(IsToken(acptr) ? TOK_SERVER : MSG_SERVER),
|
|
cptr->name, cptr->serv->numeric, cptr->info);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(acptr, ":%s %s %s 2 :%s",
|
|
me.name,
|
|
(IsToken(acptr) ? TOK_SERVER : MSG_SERVER),
|
|
cptr->name, cptr->info);
|
|
}
|
|
}
|
|
for (acptr = &me; acptr; acptr = acptr->prev)
|
|
{
|
|
/* acptr->from == acptr for acptr == cptr */
|
|
if (acptr->from == cptr)
|
|
continue;
|
|
if (IsServer(acptr))
|
|
{
|
|
if (SupportNS(cptr))
|
|
{
|
|
/* this has to work. */
|
|
numeric =
|
|
((aClient *)find_server_quick(acptr->
|
|
serv->up))->serv->numeric;
|
|
|
|
sendto_one(cptr, "%c%s %s %s %d %i :%s",
|
|
(numeric ? '@' : ':'),
|
|
(numeric ? base64enc(numeric) :
|
|
acptr->serv->up),
|
|
IsToken(cptr) ? TOK_SERVER : MSG_SERVER,
|
|
acptr->name, acptr->hopcount + 1,
|
|
acptr->serv->numeric, acptr->info);
|
|
}
|
|
else
|
|
sendto_one(cptr, ":%s %s %s %d :%s",
|
|
acptr->serv->up,
|
|
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
|
|
acptr->name, acptr->hopcount + 1,
|
|
acptr->info);
|
|
|
|
}
|
|
}
|
|
/* Synching nick information */
|
|
for (acptr = &me; acptr; acptr = acptr->prev)
|
|
{
|
|
/* acptr->from == acptr for acptr == cptr */
|
|
if (acptr->from == cptr)
|
|
continue;
|
|
if (IsPerson(acptr))
|
|
{
|
|
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))
|
|
{
|
|
if (SupportNS(cptr)
|
|
&& acptr->srvptr->serv->numeric)
|
|
{
|
|
sendto_one(cptr,
|
|
cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %d %B %s %s %b %lu %s %s :%s"
|
|
:
|
|
"%s %s %d %d %s %s %b %lu %s %s :%s",
|
|
(IsToken(cptr) ? TOK_NICK :
|
|
MSG_NICK), acptr->name,
|
|
acptr->hopcount + 1,
|
|
acptr->lastnick,
|
|
acptr->user->username,
|
|
acptr->user->realhost,
|
|
acptr->srvptr->
|
|
serv->numeric,
|
|
acptr->user->servicestamp,
|
|
(!buf
|
|
|| *buf ==
|
|
'\0' ? "+" : buf),
|
|
((IsHidden(acptr)
|
|
&& (acptr->
|
|
umodes & UMODE_SETHOST)) ?
|
|
acptr->
|
|
user->virthost : "*"),
|
|
acptr->info);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr,
|
|
(cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %d %B %s %s %s %lu %s %s :%s"
|
|
:
|
|
"%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,
|
|
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,
|
|
(SupportNS(cptr) ?
|
|
(acptr->srvptr->serv->numeric ?
|
|
base64enc(acptr->srvptr->
|
|
serv->numeric) : 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,
|
|
(cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %s %B :%s"
|
|
:
|
|
"%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
|
|
*/
|
|
{
|
|
ConfigItem_ban *bconf;
|
|
char *ns = NULL;
|
|
|
|
if (me.serv->numeric && SupportNS(cptr))
|
|
ns = base64enc(me.serv->numeric);
|
|
else
|
|
ns = NULL;
|
|
|
|
for (bconf = conf_ban; bconf; bconf = (ConfigItem_ban *) bconf->next)
|
|
{
|
|
if (bconf->flag.type == CONF_BAN_NICK)
|
|
if (bconf->flag.type2 == CONF_BAN_TYPE_AKILL)
|
|
if (bconf->reason)
|
|
sendto_one(cptr, "%s%s %s %s :%s",
|
|
ns ? "@" : ":",
|
|
ns ? ns : me.name,
|
|
(IsToken(cptr) ? TOK_SQLINE :
|
|
MSG_SQLINE), bconf->mask,
|
|
bconf->reason);
|
|
else
|
|
sendto_one(cptr, "%s%s %s %s",
|
|
ns ? "@" : ":",
|
|
ns ? ns : me.name,
|
|
me.name,
|
|
(IsToken(cptr) ? TOK_SQLINE :
|
|
MSG_SQLINE), bconf->mask);
|
|
}
|
|
}
|
|
|
|
sendto_one(cptr, "%s %li %li %li %X 0 0 0 :%s",
|
|
(IsToken(cptr) ? TOK_NETINFO : MSG_NETINFO),
|
|
IRCstats.global_max, TStime(), UnrealProtocol,
|
|
CLOAK_KEYCRC,
|
|
ircnetwork);
|
|
return 0;
|
|
|
|
}
|
|
|
|
int m_server_estab(cptr)
|
|
aClient *cptr;
|
|
{
|
|
#ifdef WTF
|
|
aClient *acptr;
|
|
aConfItem *aconf, *bconf;
|
|
char *inpath, *host, *s, *encr;
|
|
int split, i;
|
|
extern char serveropts[];
|
|
unsigned long numeric;
|
|
|
|
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 && *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 && encr && !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");
|
|
}
|
|
if (cptr->passwd)
|
|
{
|
|
MyFree(cptr->passwd);
|
|
cptr->passwd = NULL;
|
|
}
|
|
#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-%i %s",
|
|
my_name_for_link(me.name, aconf), UnrealProtocol,
|
|
serveropts, me.serv->numeric,
|
|
(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->name)))
|
|
cptr->flags |= FLAGS_ULINE;
|
|
cptr->flags |= FLAGS_TS8;
|
|
nextping = TStime();
|
|
(void)find_or_add(cptr->name);
|
|
if (TRUEHUB == 1)
|
|
{
|
|
#ifdef USE_SSL
|
|
if (IsSecure(cptr))
|
|
sendto_serv_butone(&me,
|
|
":%s GLOBOPS :Secure link with %s established (%s).",
|
|
me.name, inpath,
|
|
(char *)ssl_get_cipher((SSL *) cptr->ssl));
|
|
else
|
|
#endif
|
|
sendto_serv_butone(&me,
|
|
":%s GLOBOPS :Link with %s established.", me.name,
|
|
inpath);
|
|
}
|
|
#ifdef USE_SSL
|
|
if (IsSecure(cptr))
|
|
sendto_locfailops("Secure Link with %s established (%s).",
|
|
inpath, (char *)ssl_get_cipher((SSL *) cptr->ssl));
|
|
|
|
else
|
|
#endif
|
|
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;
|
|
|
|
if (num && numeric_collides(TS2ts(num)))
|
|
{
|
|
sendto_serv_butone(&me,
|
|
":%s GLOBOPS :Cancelling link %s, colliding numeric",
|
|
me.name, inpath);
|
|
sendto_locfailops("Cancelling link %s, colliding numeric",
|
|
inpath);
|
|
return exit_client(cptr, cptr, cptr,
|
|
"Colliding server numeric (choose another in the M:line)");
|
|
}
|
|
|
|
if (num)
|
|
{
|
|
cptr->serv->numeric = TS2ts(num);
|
|
num = NULL;
|
|
}
|
|
add_server_to_table(cptr);
|
|
/*
|
|
** 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 (SupportNS(acptr))
|
|
{
|
|
sendto_one(acptr, "%c%s %s %s 2 %i :%s",
|
|
(me.serv->numeric ? '@' : ':'),
|
|
(me.serv->numeric ? base64enc(me.
|
|
serv->numeric) : me.name),
|
|
(IsToken(acptr) ? TOK_SERVER : MSG_SERVER),
|
|
cptr->name, cptr->serv->numeric, cptr->info);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(acptr, ":%s %s %s 2 :%s",
|
|
me.name,
|
|
(IsToken(acptr) ? 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 (SupportNS(cptr))
|
|
{
|
|
/* this has to work. */
|
|
numeric =
|
|
((aClient *)find_server_quick(acptr->
|
|
serv->up))->serv->numeric;
|
|
|
|
sendto_one(cptr, "%c%s %s %s %d %i :%s",
|
|
(numeric ? '@' : ':'),
|
|
(numeric ? base64enc(numeric) :
|
|
acptr->serv->up),
|
|
IsToken(cptr) ? TOK_SERVER : MSG_SERVER,
|
|
acptr->name, acptr->hopcount + 1,
|
|
acptr->serv->numeric, acptr->info);
|
|
}
|
|
else
|
|
sendto_one(cptr, ":%s %s %s %d :%s",
|
|
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))
|
|
{
|
|
if (SupportNS(cptr)
|
|
&& acptr->srvptr->serv->numeric)
|
|
{
|
|
sendto_one(cptr,
|
|
cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %d %B %s %s %b %lu %s %s :%s"
|
|
:
|
|
"%s %s %d %d %s %s %b %lu %s %s :%s",
|
|
(IsToken(cptr) ? TOK_NICK :
|
|
MSG_NICK), acptr->name,
|
|
acptr->hopcount + 1,
|
|
acptr->lastnick,
|
|
acptr->user->username,
|
|
acptr->user->realhost,
|
|
acptr->srvptr->
|
|
serv->numeric,
|
|
acptr->user->servicestamp,
|
|
(!buf
|
|
|| *buf ==
|
|
'\0' ? "+" : buf),
|
|
((IsHidden(acptr)
|
|
&& (acptr->
|
|
umodes & UMODE_SETHOST)) ?
|
|
acptr->
|
|
user->virthost : "*"),
|
|
acptr->info);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr,
|
|
(cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %d %B %s %s %s %lu %s %s :%s"
|
|
:
|
|
"%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,
|
|
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,
|
|
(SupportNS(cptr) ?
|
|
(acptr->srvptr->serv->numeric ?
|
|
base64enc(acptr->srvptr->
|
|
serv->numeric) : 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,
|
|
(cptr->proto & PROTO_SJB64 ?
|
|
"%s %s %s %B :%s"
|
|
:
|
|
"%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;
|
|
char *ns = NULL;
|
|
|
|
if (me.serv->numeric && SupportNS(cptr))
|
|
ns = base64enc(me.serv->numeric);
|
|
else
|
|
ns = NULL;
|
|
|
|
/* for (tmp = sqline; tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->status != CONF_ILLEGAL)
|
|
if (tmp->reason)
|
|
sendto_one(cptr, "%s%s %s %s :%s",
|
|
ns ? "@" : ":",
|
|
ns ? ns : me.name,
|
|
(IsToken(cptr) ? TOK_SQLINE :
|
|
MSG_SQLINE), tmp->sqline,
|
|
tmp->reason);
|
|
else
|
|
sendto_one(cptr, "%s%s %s %s",
|
|
ns ? "@" : ":",
|
|
ns ? ns : me.name,
|
|
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);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** m_links
|
|
** parv[0] = sender prefix
|
|
** or
|
|
** parv[0] = sender prefix
|
|
**
|
|
** Recoded by Stskeeps
|
|
*/
|
|
int m_links(cptr, sptr, parc, parv)
|
|
aClient *cptr, *sptr;
|
|
int parc;
|
|
char *parv[];
|
|
{
|
|
Link *lp;
|
|
aClient *acptr;
|
|
|
|
for (lp = Servers; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->value.cptr;
|
|
|
|
/* Some checks */
|
|
if (HIDE_ULINES && IsULine(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], "*");
|
|
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] = cloak-crc (> u2302)
|
|
** 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;
|
|
char buf[512];
|
|
|
|
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);
|
|
return 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 = TS2ts(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);
|
|
|
|
}
|
|
ircsprintf(buf, "%X", CLOAK_KEYCRC);
|
|
if (strcmp(buf, parv[4]))
|
|
{
|
|
sendto_realops
|
|
("Link %s is having a different cloak key - %s != %s",
|
|
cptr->name, parv[4], buf);
|
|
}
|
|
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@unrealircd.com>",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * codemastr <codemastr@unrealircd.com>",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * DrBin <drbin@unrealircd.com>",
|
|
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://www.unrealircd.com",
|
|
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;
|
|
}
|
|
|
|
char *get_cptr_status(aClient *acptr)
|
|
{
|
|
static char buf[10];
|
|
char *p = buf;
|
|
|
|
*p = '\0';
|
|
*p++ = '[';
|
|
if (acptr->flags & FLAGS_LISTEN)
|
|
{
|
|
if (acptr->umodes & LISTENER_NORMAL)
|
|
*p++ = '*';
|
|
if (acptr->umodes & LISTENER_SERVERSONLY)
|
|
*p++ = 'S';
|
|
if (acptr->umodes & LISTENER_CLIENTSONLY)
|
|
*p++ = 'C';
|
|
#ifdef USE_SSL
|
|
if (acptr->umodes & LISTENER_SSL)
|
|
*p++ = 's';
|
|
#endif
|
|
if (acptr->umodes & LISTENER_REMOTEADMIN)
|
|
*p++ = 'R';
|
|
if (acptr->umodes & LISTENER_JAVACLIENT)
|
|
*p++ = 'J';
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_SSL
|
|
if (acptr->flags & FLAGS_SSL)
|
|
*p++ = 's';
|
|
#endif
|
|
}
|
|
*p++ = ']';
|
|
*p++ = '\0';
|
|
return (buf);
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/*
|
|
** m_stats
|
|
** parv[0] = sender prefix
|
|
** parv[1] = statistics selector (defaults to Message frequency)
|
|
** parv[2] = server name (current server defaulted, if omitted)
|
|
**
|
|
*/
|
|
/*
|
|
** Note: The info is reported in the order the server uses
|
|
** it--not reversed as in ircd.conf!
|
|
*/
|
|
|
|
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%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%s %u %u %u %u %u %u %s";
|
|
char pbuf[96]; /* Should be enough for to ints */
|
|
#endif
|
|
ConfigItem_link *link_p;
|
|
aCommand *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;
|
|
|
|
if (hunt_server(cptr, sptr, ":%s STATS %s :%s", 2, parc,
|
|
parv) != HUNTED_ISME)
|
|
return 0;
|
|
|
|
#ifdef STATS_ONLYOPER
|
|
if (!IsAnOper(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
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;
|
|
|
|
switch (stat)
|
|
{
|
|
#ifdef STRIPBADWORDS
|
|
case 'b':
|
|
{
|
|
ConfigItem_badword *words;
|
|
|
|
for (words = conf_badword_channel; words; words = (ConfigItem_badword *) words->next) {
|
|
sendto_one(sptr, ":%s %i %s :c %s %s", me.name, RPL_TEXT, sptr->name, words->word, words->replace ? words->replace : "<censored>");
|
|
}
|
|
for (words = conf_badword_message; words; words = (ConfigItem_badword *) words->next) {
|
|
sendto_one(sptr, ":%s %i %s :m %s %s", me.name, RPL_TEXT, sptr->name, words->word, words->replace ? words->replace : "<censored>");
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
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)
|
|
|| (acptr->flags & FLAGS_LISTEN))) && !(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),
|
|
get_cptr_status(acptr),
|
|
(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),
|
|
get_cptr_status(acptr),
|
|
(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':
|
|
case 'H':
|
|
case 'h':
|
|
for (link_p = conf_link; link_p; link_p = (ConfigItem_link *) link_p->next)
|
|
{
|
|
sendto_one(sptr, ":%s 213 %s C %s@%s * %s %i %s %s%s%s",
|
|
me.name, sptr->name, IsOper(sptr) ? link_p->username : "*",
|
|
IsOper(sptr) ? link_p->hostname : "*", link_p->servername,
|
|
link_p->port,
|
|
link_p->class->name,
|
|
(link_p->options & CONNECT_AUTO) ? "a" : "",
|
|
(link_p->options & CONNECT_SSL) ? "S" : "",
|
|
(link_p->options & CONNECT_ZIP) ? "z" : "");
|
|
if (link_p->hubmask)
|
|
{
|
|
sendto_one(sptr, ":%s 244 %s H %s * %s",
|
|
me.name, sptr->name, link_p->hubmask,
|
|
link_p->servername);
|
|
}
|
|
else
|
|
if (link_p->leafmask)
|
|
{
|
|
sendto_one(sptr, ":%s 241 %s L %s * %s %d",
|
|
me.name, sptr->name,
|
|
link_p->leafmask, link_p->leafdepth);
|
|
}
|
|
}
|
|
break;
|
|
case 'f':
|
|
case 'F':
|
|
report_flines(sptr);
|
|
break;
|
|
|
|
case 'G':
|
|
case 'g':
|
|
tkl_stats(sptr);
|
|
break;
|
|
case 'I':
|
|
case 'i':
|
|
{
|
|
ConfigItem_allow *allows;
|
|
for (allows = conf_allow; allows; allows = (ConfigItem_allow *) allows->next) {
|
|
sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
|
|
parv[0], allows->ip, allows->hostname, allows->maxperip, allows->class->name, allows->server ? allows->server : defserv, allows->port ? allows->port : 6667);
|
|
}
|
|
break;
|
|
}
|
|
case 'E':
|
|
{
|
|
ConfigItem_except *excepts;
|
|
for (excepts = conf_except; excepts; excepts = (ConfigItem_except *) excepts->next) {
|
|
if (excepts->flag.type == 1)
|
|
sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
|
|
parv[0], "E", excepts->mask, "");
|
|
}
|
|
break;
|
|
}
|
|
case 'e':
|
|
{
|
|
ConfigItem_except *excepts;
|
|
for (excepts = conf_except; excepts;
|
|
excepts = (ConfigItem_except *) excepts->next)
|
|
{
|
|
if (excepts->flag.type == 0)
|
|
sendto_one(sptr, rpl_str(RPL_STATSELINE),
|
|
me.name, parv[0], excepts->mask);
|
|
}
|
|
break;
|
|
}
|
|
case 'K':
|
|
case 'k':
|
|
{
|
|
ConfigItem_ban *bans;
|
|
ConfigItem_except *excepts;
|
|
char type[2];
|
|
for (bans = conf_ban; bans; bans = (ConfigItem_ban *)bans->next) {
|
|
if (bans->flag.type == CONF_BAN_USER) {
|
|
if (bans->flag.type2 == CONF_BAN_TYPE_CONF)
|
|
type[0] = 'K';
|
|
else if (bans->flag.type2 == CONF_BAN_TYPE_AKILL)
|
|
type[0] = 'A';
|
|
else if (bans->flag.type2 == CONF_BAN_TYPE_TEMPORARY)
|
|
type[0] = 'k';
|
|
type[1] = '\0';
|
|
sendto_one(sptr, rpl_str(RPL_STATSKLINE),
|
|
me.name, parv[0], type, bans->mask, bans->reason ? bans->reason : "<no reason>");
|
|
}
|
|
else if (bans->flag.type == CONF_BAN_IP) {
|
|
if (bans->flag.type2 == CONF_BAN_TYPE_CONF)
|
|
type[0] = 'Z';
|
|
else if (bans->flag.type2 == CONF_BAN_TYPE_AKILL)
|
|
type[0] = 'S';
|
|
else if (bans->flag.type2 == CONF_BAN_TYPE_TEMPORARY)
|
|
type[0] = 'z';
|
|
type[1] = '\0';
|
|
sendto_one(sptr, rpl_str(RPL_STATSKLINE),
|
|
me.name, parv[0], type, bans->mask, bans->reason ? bans->reason : "<no reason>");
|
|
}
|
|
|
|
}
|
|
for (excepts = conf_except; excepts; excepts = (ConfigItem_except *)excepts->next) {
|
|
if (excepts->flag.type == 1)
|
|
sendto_one(sptr, rpl_str(RPL_STATSKLINE),
|
|
me.name, parv[0], "E", excepts->mask, "");
|
|
}
|
|
break;
|
|
}
|
|
case 'M':
|
|
case 'm':
|
|
for (i = 0; i <= 255; i++)
|
|
for (mptr = CommandHash[i]; mptr; mptr = mptr->next)
|
|
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':
|
|
{
|
|
ConfigItem_ban *bans;
|
|
|
|
for (bans = conf_ban; bans; bans = (ConfigItem_ban *)bans->next) {
|
|
if (bans->flag.type == CONF_BAN_REALNAME)
|
|
sendto_one(sptr, rpl_str(RPL_STATSNLINE),
|
|
me.name, parv[0], bans->mask, bans->reason ? bans->reason : "<no reason>");
|
|
}
|
|
break;
|
|
}
|
|
case 'N':
|
|
if (IsOper(sptr))
|
|
report_network(sptr);
|
|
break;
|
|
case 'o':
|
|
case 'O':
|
|
if (SHOWOPERS == 0 && (IsOper(sptr)))
|
|
{
|
|
break;
|
|
}
|
|
if (SHOWOPERS == 1)
|
|
break;
|
|
case 'P':
|
|
if (IsOper(sptr))
|
|
{
|
|
for (i = 0; i <= highest_fd; i++)
|
|
{
|
|
if (!(acptr = local[i]))
|
|
continue;
|
|
if (!IsListening(acptr))
|
|
continue;
|
|
sendto_one(sptr, ":%s NOTICE %s :*** Listener on %s:%i, clients %i. is %s",
|
|
me.name, sptr->name,
|
|
((ConfigItem_listen *)acptr->class)->ip,
|
|
((ConfigItem_listen *)acptr->class)->port,
|
|
((ConfigItem_listen *)acptr->class)->clients,
|
|
((ConfigItem_listen *)acptr->class)->flag.temporary ? "TEMPORARY" : "PERM");
|
|
}
|
|
}
|
|
break;
|
|
case 'Q':
|
|
{
|
|
ConfigItem_ban *bans;
|
|
|
|
for (bans = conf_ban; bans; bans = (ConfigItem_ban *)bans->next) {
|
|
if (bans->flag.type == CONF_BAN_NICK && bans->flag.type2 != CONF_BAN_TYPE_AKILL)
|
|
sendto_one(sptr, rpl_str(RPL_STATSQLINE),
|
|
me.name, parv[0], bans->reason, bans->mask);
|
|
}
|
|
}
|
|
break;
|
|
case 'q':
|
|
{
|
|
ConfigItem_ban *bans;
|
|
|
|
for (bans = conf_ban; bans; bans = (ConfigItem_ban *)bans->next) {
|
|
if (bans->flag.type == CONF_BAN_NICK && bans->flag.type2 == CONF_BAN_TYPE_AKILL)
|
|
sendto_one(sptr, rpl_str(RPL_SQLINE_NICK),
|
|
me.name, parv[0], bans->mask, bans->reason);
|
|
}
|
|
break;
|
|
}
|
|
case 'R':
|
|
#ifdef DEBUGMODE
|
|
send_usage(sptr, parv[0]);
|
|
#endif
|
|
break;
|
|
case 's':
|
|
if (IsOper(sptr))
|
|
{
|
|
sendto_one(sptr, ":%s NOTICE %s :*** SCACHE:",
|
|
me.name, sptr->name);
|
|
list_scache(sptr);
|
|
sendto_one(sptr, ":%s NOTICE %s :*** NS:", me.name,
|
|
sptr->name);
|
|
ns_stats(sptr);
|
|
}
|
|
break;
|
|
case 'S':
|
|
if (IsOper(sptr))
|
|
report_dynconf(sptr);
|
|
break;
|
|
case 'D':
|
|
{
|
|
ConfigItem_deny_link *links;
|
|
|
|
for (links = conf_deny_link; links; links = (ConfigItem_deny_link *) links->next) {
|
|
if (links->flag.type == CRULE_ALL)
|
|
sendto_one(sptr, rpl_str(RPL_STATSDLINE), me.name, sptr->name,
|
|
"D", links->mask, links->prettyrule);
|
|
}
|
|
break;
|
|
}
|
|
case 'd':
|
|
{
|
|
ConfigItem_deny_link *links;
|
|
|
|
for (links = conf_deny_link; links; links = (ConfigItem_deny_link *) links->next) {
|
|
if (links->flag.type == CRULE_AUTO)
|
|
sendto_one(sptr, rpl_str(RPL_STATSDLINE), me.name, sptr->name,
|
|
"d", links->mask, links->prettyrule);
|
|
}
|
|
break;
|
|
}
|
|
case 'r':
|
|
|
|
/* FIXME: cr_report(sptr); */
|
|
break;
|
|
case 't':
|
|
{
|
|
ConfigItem_tld *tld;
|
|
for (tld = conf_tld; tld; tld = (ConfigItem_tld *) tld->next)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_STATSTLINE), me.name,
|
|
parv[0], tld->mask, tld->motd_file,
|
|
tld->rules_file ? tld->rules_file : "none");
|
|
}
|
|
break;
|
|
}
|
|
case 'T': /* /stats T not t:lines .. */
|
|
tstats(sptr, parv[0]);
|
|
break;
|
|
case 'U':
|
|
{
|
|
ConfigItem_ulines *ulines;
|
|
for (ulines = conf_ulines; ulines;
|
|
ulines = (ConfigItem_ulines *) ulines->next)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_STATSULINE), me.name,
|
|
parv[0], ulines->servername);
|
|
}
|
|
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':
|
|
{
|
|
ConfigItem_deny_version *versions;
|
|
|
|
for (versions = conf_deny_version; versions; versions = (ConfigItem_deny_version *) versions->next) {
|
|
sendto_one(sptr, rpl_str(RPL_STATSVLINE), me.name, sptr->name,
|
|
versions->version, versions->flags, versions->mask);
|
|
}
|
|
break;
|
|
}
|
|
case 'V':
|
|
break;
|
|
case 'W':
|
|
case 'w':
|
|
calc_load(sptr, parv[0]);
|
|
break;
|
|
case 'X':
|
|
case 'x':
|
|
for (link_p = conf_link; link_p; link_p = (ConfigItem_link *) link_p->next)
|
|
{
|
|
if (!find_server_quick(link_p->servername))
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_STATSXLINE),
|
|
me.name, sptr->name, link_p->servername,
|
|
link_p->port);
|
|
}
|
|
}
|
|
break;
|
|
case 'Y':
|
|
case 'y':
|
|
{
|
|
ConfigItem_class *classes;
|
|
for (classes = conf_class; classes; classes = (ConfigItem_class *) classes->next) {
|
|
sendto_one(sptr, rpl_str(RPL_STATSYLINE),
|
|
me.name, sptr->name, classes->name, classes->pingfreq, classes->connfreq,
|
|
classes->maxclients, classes->sendq);
|
|
}
|
|
break;
|
|
}
|
|
case 'Z':
|
|
case 'z':
|
|
if (IsAnOper(sptr))
|
|
count_memory(sptr, parv[0]);
|
|
break;
|
|
default:
|
|
/* Display a help menu */
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"/Stats flags:");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"b - Send the badwords list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"C - Send the C/N line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"d - Send the d line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"D - Send the D line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"e - Send the e line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"E - Send the E line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"F - Send the dccdeny line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"G - Report TKL information (G:lines/Shuns)");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"H - Send the H/L line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"I - Send the I line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"K - Send the K/E/Z line list (Includes AKILLs)");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"L - Send Link information");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"M - Send list of how many times each command was used");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"n - Send the n line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"N - Send network configuration list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"O - Send the O line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"q - Send the SQLINE list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"Q - Send the Q line list");
|
|
#ifdef DEBUGMODE
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"R - Send the usage list");
|
|
#endif
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"s - Send the SCache and NS list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"S - Send the dynamic configuration list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"t - Send the T line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"t - Send connection information");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"u - Send server uptime and connection count");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"U - Send the U line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"v - Send the V line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"V - Send the vhost list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"W - Send load information");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"Y - Send the Y line list");
|
|
sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, parv[0],
|
|
"Z - Send memory usage information");
|
|
stat = '*';
|
|
break;
|
|
}
|
|
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
|
|
|
|
|
|
if (stat != '*')
|
|
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);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** m_summon
|
|
** parv[0] = sender prefix
|
|
*/
|
|
int m_summon(aClient *cptr, aClient *sptr, int parc, char *parv[])
|
|
{
|
|
/* /summon is old and out dated, we just return an error as
|
|
* required by RFC1459 -- codemastr
|
|
*/ sendto_one(sptr, err_str(ERR_SUMMONDISABLED), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
/*
|
|
** m_users
|
|
** parv[0] = sender prefix
|
|
** parv[1] = servername
|
|
*/ int m_users(aClient *cptr, aClient *sptr, int parc, char *parv[])
|
|
{
|
|
/* /users is out of date, just return an error as required by
|
|
* RFC1459 -- codemastr
|
|
*/ sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]);
|
|
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_umode(UMODE_HELPOP, "*** HelpOp -- 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_umode(UMODE_HELPOP, "*** HelpOp -- 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_umode(UMODE_HELPOP, "*** HelpOp -- 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[];
|
|
{
|
|
|
|
/* Doesn't work anyways --Stskeeps
|
|
|
|
if (parc > 2)
|
|
if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
|
|
!= HUNTED_ISME)
|
|
return 0;
|
|
*/
|
|
|
|
/* 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;
|
|
}
|
|
|
|
|
|
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);
|
|
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);
|
|
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;
|
|
ConfigItem_link *aconf;
|
|
ConfigItem_deny_link *deny;
|
|
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_quick(parv[1])))
|
|
{
|
|
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_link; aconf; aconf = (ConfigItem_link *) aconf->next)
|
|
if (!match(parv[1], aconf->servername))
|
|
break;
|
|
|
|
/* Checked first servernames, then try hostnames. */
|
|
|
|
if (!aconf)
|
|
{
|
|
sendto_one(sptr,
|
|
"NOTICE %s :*** Connect: Server %s is not configured for linking",
|
|
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 deny link */
|
|
for (deny = conf_deny_link; deny; deny = (ConfigItem_deny_link *) deny->next) {
|
|
if (deny->flag.type == CRULE_ALL && !match(deny->mask, aconf->servername)
|
|
&& crule_eval(deny->rule)) {
|
|
sendto_one(sptr,
|
|
"NOTICE %s :Connect: Disallowed by connection rule",
|
|
parv[0]);
|
|
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
|
|
}
|
|
/* Interesting */
|
|
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->servername, aconf->hostname);
|
|
break;
|
|
case -1:
|
|
sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
|
|
me.name, parv[0], aconf->servername);
|
|
break;
|
|
case -2:
|
|
sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
|
|
me.name, parv[0], aconf->servername);
|
|
break;
|
|
default:
|
|
sendto_one(sptr,
|
|
":%s NOTICE %s :*** Connection to %s failed: %s",
|
|
me.name, parv[0], aconf->servername, 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(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 */
|
|
svsmotd = read_file(VPATH, &svsmotd);
|
|
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 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) && !IsAnOper(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_OPER, "*** ChatOps -- from %s: %s",
|
|
parv[0], message);
|
|
sendto_umode(UMODE_LOCOP, "*** 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(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(sptr))
|
|
return -1;
|
|
|
|
/* if (hunt_server(cptr,sptr,":%s SVSKILL %s :%s",1,parc,parv) != HUNTED_ISME)
|
|
return 0;
|
|
*/
|
|
|
|
if (!(acptr = find_client(parv[1], NULL)))
|
|
return 0;
|
|
|
|
sendto_serv_butone_token(cptr, parv[0],
|
|
MSG_SVSKILL, TOK_SVSKILL, "%s :%s", 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[];
|
|
{
|
|
ConfigItem_admin *admin;
|
|
/* 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 (!conf_admin_tail)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOADMININFO),
|
|
me.name, parv[0], me.name);
|
|
return 0;
|
|
}
|
|
|
|
sendto_one(sptr, rpl_str(RPL_ADMINME), me.name, parv[0], me.name);
|
|
|
|
/* cycle through the list backwards */
|
|
for (admin = conf_admin_tail; admin;
|
|
admin = (ConfigItem_admin *) admin->prev)
|
|
{
|
|
if (!admin->next)
|
|
sendto_one(sptr, rpl_str(RPL_ADMINLOC1),
|
|
me.name, parv[0], admin->line);
|
|
else if (!admin->next->next)
|
|
sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
|
|
me.name, parv[0], admin->line);
|
|
else
|
|
sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
|
|
me.name, parv[0], admin->line);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** m_rehash
|
|
** remote rehash by binary
|
|
** now allows the -flags in remote rehash
|
|
** ugly code but it seems to work :) -- codemastr
|
|
** added -all and fixed up a few lines -- niquil (niquil@programmer.net)
|
|
*/
|
|
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(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
x = 0;
|
|
|
|
if (cptr != sptr)
|
|
{
|
|
#ifndef REMOTE_REHASH
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
#endif
|
|
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]);
|
|
return rehash(cptr, sptr,
|
|
(parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
|
|
}
|
|
parv[1] = parv[2];
|
|
}
|
|
else
|
|
{
|
|
if (find_server_quick(parv[1]))
|
|
{
|
|
if (parv[2])
|
|
{
|
|
if ((x =
|
|
hunt_server(cptr, sptr, ":%s REHASH %s %s",
|
|
1, parc, parv)) != HUNTED_ISME)
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ((x =
|
|
hunt_server(cptr, sptr, ":%s REHASH %s", 1,
|
|
parc, parv)) != HUNTED_ISME)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (!BadPtr(parv[1]))
|
|
{
|
|
|
|
if (!IsAdmin(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
if (*parv[1] == '-')
|
|
{
|
|
if (!_match("-all", parv[1]))
|
|
{
|
|
ConfigItem_tld *tlds;
|
|
aMotd *amotd;
|
|
sendto_ops("%sRehashing everything on the request of %s",
|
|
cptr != sptr ? "Remotely " : "",sptr->name);
|
|
#ifdef DEBUGMODE
|
|
sendto_ops("Rehashing opermotd [1/4]");
|
|
#endif
|
|
opermotd = (aMotd *) read_file(OPATH, &opermotd);
|
|
#ifdef DEBUGMODE
|
|
sendto_ops("Rehashing botmotd [2/4]");
|
|
#endif
|
|
botmotd = (aMotd *) read_file(BPATH, &botmotd);
|
|
#ifdef DEBUGMODE
|
|
sendto_ops("Rehashing motd [3/4]");
|
|
#endif
|
|
motd = (aMotd *) read_motd(MPATH);
|
|
rules = (aMotd *) read_rules(RPATH);
|
|
#ifdef DEBUGMODE
|
|
sendto_ops("Rehashing rules [4/4]");
|
|
#endif
|
|
for (tlds = conf_tld; tlds;
|
|
tlds = (ConfigItem_tld *) tlds->next)
|
|
{
|
|
while (tlds->motd)
|
|
{
|
|
amotd = tlds->motd->next;
|
|
MyFree(tlds->motd->line);
|
|
MyFree(tlds->motd);
|
|
tlds->motd = amotd;
|
|
}
|
|
tlds->motd = read_motd(tlds->motd_file);
|
|
while (tlds->rules)
|
|
{
|
|
amotd = tlds->rules->next;
|
|
MyFree(tlds->rules->line);
|
|
MyFree(tlds->rules);
|
|
tlds->rules = amotd;
|
|
}
|
|
tlds->rules =
|
|
read_rules(tlds->rules_file);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
if (!strnicmp("-gar", parv[1], 4))
|
|
{
|
|
loop.do_garbage_collect = 1;
|
|
return 0;
|
|
}
|
|
if (!_match("-o*motd", parv[1]))
|
|
{
|
|
sendto_ops
|
|
("%sRehashing OperMOTD on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
opermotd = (aMotd *) read_file(OPATH, &opermotd);
|
|
return 0;
|
|
}
|
|
if (!_match("-b*motd", parv[1]))
|
|
{
|
|
sendto_ops
|
|
("%sRehashing BotMOTD on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
botmotd = (aMotd *) read_file(BPATH, &botmotd);
|
|
return 0;
|
|
}
|
|
if (!strnicmp("-motd", parv[1], 5)
|
|
|| !strnicmp("-rules", parv[1], 6))
|
|
{
|
|
ConfigItem_tld *tlds;
|
|
aMotd *amotd;
|
|
sendto_ops
|
|
("%sRehashing all MOTDs and RULES on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
motd = (aMotd *) read_motd(MPATH);
|
|
rules = (aMotd *) read_rules(RPATH);
|
|
for (tlds = conf_tld; tlds;
|
|
tlds = (ConfigItem_tld *) tlds->next)
|
|
{
|
|
while (tlds->motd)
|
|
{
|
|
amotd = tlds->motd->next;
|
|
MyFree(tlds->motd->line);
|
|
MyFree(tlds->motd);
|
|
tlds->motd = amotd;
|
|
}
|
|
tlds->motd = read_motd(tlds->motd_file);
|
|
while (tlds->rules)
|
|
{
|
|
amotd = tlds->rules->next;
|
|
MyFree(tlds->rules->line);
|
|
MyFree(tlds->rules);
|
|
tlds->rules = amotd;
|
|
}
|
|
tlds->rules =
|
|
read_rules(tlds->rules_file);
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
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(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
if (parc > 3)
|
|
{
|
|
/* 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 = conf_drpass->restart))
|
|
{
|
|
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;
|
|
ConfigItem_class *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;
|
|
char *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 = acptr->class ? acptr->class->name : "default";
|
|
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 = conf_class; doall && cltmp; cltmp = (ConfigItem_class *) cltmp->next)
|
|
/* if (cltmp->clients > 0) */
|
|
sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
|
|
parv[0], cltmp->name ? cltmp->name : "[noname]", cltmp->clients);
|
|
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[])
|
|
{
|
|
ConfigItem_tld *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 = conf_tld; ptr; ptr = (ConfigItem_tld *) ptr->next)
|
|
{
|
|
if (!match(ptr->mask, cptr->user->realhost))
|
|
break;
|
|
}
|
|
|
|
if (ptr)
|
|
{
|
|
temp = ptr->motd;
|
|
tm = ptr->motd_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;
|
|
}
|
|
|
|
/*
|
|
* 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->line);
|
|
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();
|
|
AllocCpy(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->line);
|
|
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();
|
|
AllocCpy(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
|
|
* we can now use 1 function for multiple files -- codemastr
|
|
*/
|
|
|
|
aMotd *read_file(char *filename, aMotd **list)
|
|
{
|
|
|
|
int fd = open(filename, O_RDONLY);
|
|
aMotd *temp, *newmotd, *last, *old;
|
|
char line[82];
|
|
char *tmp;
|
|
int i;
|
|
|
|
if (fd == -1)
|
|
return NULL;
|
|
|
|
while (*list)
|
|
{
|
|
old = (*list)->next;
|
|
MyFree((*list)->line);
|
|
MyFree(*list);
|
|
*list = 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();
|
|
AllocCpy(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[])
|
|
{
|
|
ConfigItem_tld *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 = conf_tld; ptr; ptr = (ConfigItem_tld *) ptr->next)
|
|
{
|
|
if (!match(ptr->mask, cptr->user->realhost))
|
|
break;
|
|
}
|
|
|
|
if (ptr)
|
|
{
|
|
temp = ptr->rules;
|
|
|
|
}
|
|
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 = conf_drpass->die)) /* 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;
|
|
aClient *acptr;
|
|
Link *lp;
|
|
|
|
*p = '\0';
|
|
|
|
if (prompt_length > 60)
|
|
sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name,
|
|
prompt, server->name);
|
|
else
|
|
{
|
|
sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt,
|
|
length, server->name, server->serv->users,
|
|
(server->serv->numeric ? (char *)my_itoa(server->serv->
|
|
numeric) : ""));
|
|
cnt = 0;
|
|
}
|
|
|
|
if (prompt_length > 0)
|
|
{
|
|
p[-1] = ' ';
|
|
if (p[-2] == '`')
|
|
p[-2] = ' ';
|
|
}
|
|
if (prompt_length > 60)
|
|
return;
|
|
|
|
strcpy(p, "|-");
|
|
|
|
|
|
for (lp = Servers; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->value.cptr;
|
|
if (acptr->srvptr != server)
|
|
continue;
|
|
acptr->flags |= FLAGS_MAP;
|
|
cnt++;
|
|
}
|
|
|
|
for (lp = Servers; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->value.cptr;
|
|
if (IsULine(acptr) && HIDE_ULINES && !IsAnOper(cptr))
|
|
continue;
|
|
if (acptr->srvptr != server)
|
|
continue;
|
|
if (!acptr->flags & FLAGS_MAP)
|
|
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[];
|
|
{
|
|
Link *lp;
|
|
aClient *acptr;
|
|
int longest = strlen(me.name);
|
|
|
|
|
|
if (parc < 2)
|
|
parv[1] = "*";
|
|
for (lp = Servers; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->value.cptr;
|
|
if ((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
|