mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-02 19:33:13 +02:00
dddc8f07e4
- Server protocol: added PROTOCTL EATH=servername, which allows us to
authenticate the server very early in the handshake process. That way,
certain commands and PROTOCTL tokens can 'trust' the server.
See doc/technical/protoctl.txt for details.
- Server protocol: between new Unreal servers we now do the handshake a
little bit different, so it waits with sending the SERVER command until
the first PROTOCTL is received. Needed for next.
- Server protocol: added PROTOCTL SERVERS=1,2,3,4,etc by which a server can
inform the other server which servers (server numeric, actually) it has
linked. See doc/technical/protoctl.txt and next for details.
- When our server was trying to link to some server, and at the same time
another server was also trying to link with us, this would lead to a
server collision: the server would link (twice) ok at first, but then a
second later or so both would quit with 'Server Exists' with quite some
mess as a result. This isn't unique to Unreal, btw.
This happened more often when you had a low connfreq in your link blocks
(aka: quick reconnects), or had multiple hubs on autoconnect (with same
connfreq), or when you (re)started all servers at the same time.
This should now be solved by a new server handshake design, which detects
this race condition and solves it by closing one of the two (or more)
connections to avoid the issue.
This also means that it should now be safe to have multiple hubs with low
connfreq's (eg: 10s) without risking that your network falls apart.
This new server handshake (protocol updates, etc) was actually quite some
work, especially for something that only happened sporadically. I felt it
was needed though, because (re)linking stability is extremely important.
This new feature/design/fix requires extensive testing.
This feature can be disabled by: set { new-linking-protocol 0; };
1407 lines
34 KiB
C
1407 lines
34 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 CLEAN_COMPILE
|
|
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 "version.h"
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include "h.h"
|
|
#include "proto.h"
|
|
#include <string.h>
|
|
#ifdef USE_LIBCURL
|
|
#include <curl/curl.h>
|
|
#endif
|
|
#ifndef _WIN32
|
|
/* for uname(), is POSIX so should be OK... */
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
extern VOIDSIG s_die();
|
|
|
|
static char buf[BUFSIZE];
|
|
|
|
MODVAR 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 */
|
|
extern char *buildid;
|
|
aMotd *opermotd;
|
|
aMotd *rules;
|
|
aMotd *motd;
|
|
aMotd *svsmotd;
|
|
aMotd *botmotd;
|
|
aMotd *smotd;
|
|
struct tm motd_tm;
|
|
struct tm smotd_tm;
|
|
aMotd *read_file(char *filename, aMotd **list);
|
|
aMotd *read_file_ex(char *filename, aMotd **list, struct tm *);
|
|
extern aMotd *Find_file(char *, short);
|
|
|
|
#ifdef USE_SSL
|
|
extern void reinit_ssl(aClient *);
|
|
#endif
|
|
|
|
|
|
/*
|
|
** m_functions execute protocol messages on this server:
|
|
** CMD_FUNC(functionname) causes it to use the header
|
|
** int functionname (aClient *cptr,
|
|
** aClient *sptr, int parc, char *parv[])
|
|
**
|
|
**
|
|
** 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
|
|
|
|
#ifndef _WIN32
|
|
char *getosname(void)
|
|
{
|
|
static char buf[1024];
|
|
struct utsname osinf;
|
|
char *p;
|
|
|
|
memset(&osinf, 0, sizeof(osinf));
|
|
if (uname(&osinf) != 0)
|
|
return "<unknown>";
|
|
snprintf(buf, sizeof(buf), "%s %s %s %s %s",
|
|
osinf.sysname,
|
|
osinf.nodename,
|
|
osinf.release,
|
|
osinf.version,
|
|
osinf.machine);
|
|
/* get rid of cr/lf */
|
|
for (p=buf; *p; p++)
|
|
if ((*p == '\n') || (*p == '\r'))
|
|
{
|
|
*p = '\0';
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** m_version
|
|
** parv[0] = sender prefix
|
|
** parv[1] = remote server
|
|
*/
|
|
CMD_FUNC(m_version)
|
|
{
|
|
extern char serveropts[];
|
|
extern char *IsupportStrings[];
|
|
int reply, i;
|
|
|
|
/* Only allow remote VERSIONs if registered -- Syzop */
|
|
if (!IsPerson(sptr) && !IsServer(cptr))
|
|
goto normal;
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_VERSION, TOK_VERSION, ":%s", 1, parc,
|
|
parv) == HUNTED_ISME)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_VERSION), me.name,
|
|
parv[0], version, debugmode, me.name,
|
|
serveropts, extraflags ? extraflags : "",
|
|
tainted ? "3" : "",
|
|
(IsAnOper(sptr) ? MYOSNAME : "*"), UnrealProtocol);
|
|
#ifdef USE_SSL
|
|
if (IsAnOper(sptr))
|
|
sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, OPENSSL_VERSION_TEXT);
|
|
#endif
|
|
#ifdef ZIP_LINKS
|
|
if (IsAnOper(sptr))
|
|
sendto_one(sptr, ":%s NOTICE %s :zlib %s", me.name, sptr->name, zlibVersion());
|
|
#endif
|
|
#ifdef USE_LIBCURL
|
|
if (IsAnOper(sptr))
|
|
sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, curl_version());
|
|
#endif
|
|
if (MyClient(sptr))
|
|
normal:
|
|
reply = RPL_ISUPPORT;
|
|
else
|
|
reply = RPL_REMOTEISUPPORT;
|
|
/* Send the text */
|
|
for (i = 0; IsupportStrings[i]; i++)
|
|
sendto_one(sptr, rpl_str(reply), me.name, sptr->name,
|
|
IsupportStrings[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *num = NULL;
|
|
|
|
/*
|
|
* send_proto:
|
|
* sends PROTOCTL message to server, taking care of whether ZIP
|
|
* should be enabled or not.
|
|
*/
|
|
void send_proto(aClient *cptr, ConfigItem_link *aconf)
|
|
{
|
|
char buf[1024];
|
|
|
|
sprintf(buf, "CHANMODES=%s%s,%s%s,%s%s,%s%s NICKCHARS=%s",
|
|
CHPAR1, EXPAR1, CHPAR2, EXPAR2, CHPAR3, EXPAR3, CHPAR4, EXPAR4, langsinuse);
|
|
#ifdef ZIP_LINKS
|
|
if (aconf->options & CONNECT_ZIP)
|
|
{
|
|
sendto_one(cptr, "PROTOCTL %s ZIP %s", PROTOCTL_SERVER, buf);
|
|
} else {
|
|
#endif
|
|
sendto_one(cptr, "PROTOCTL %s %s", PROTOCTL_SERVER, buf);
|
|
#ifdef ZIP_LINKS
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#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(aClient *sptr)
|
|
{
|
|
sendto_one(sptr, ":%s %d %s :=-=-=-= %s =-=-=-=",
|
|
me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION);
|
|
sendto_one(sptr, ":%s %d %s :| This release was 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 :| Coders:", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * Syzop <syzop@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 :| Contributors:", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * aquanight <aquanight@unrealircd.com>",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * WolfSage <wolfsage@unrealircd.com>",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * Stealth, tabrisnet, Bock, fbi",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| RC Testers:", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * Bock, Apocalypse, StrawberryKittens, wax, Elemental,",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| Golden|Wolf, and everyone else who tested the RC's",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| Past UnrealIRCd3.2* coders/contributors:", me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * Stskeeps (ret. head coder / project leader)",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * codemastr (ret. u3.2 head coder)",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| * McSkaf, Zogg, NiQuiL, chasm, llthangel, nighthawk, ..",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :|", 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 report them at:",
|
|
me.name, RPL_INFO, sptr->name);
|
|
sendto_one(sptr, ":%s %d %s :| http://bugs.unrealircd.org/",
|
|
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, buildid);
|
|
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
|
|
*/
|
|
|
|
CMD_FUNC(m_info)
|
|
{
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_INFO, TOK_INFO, ":%s", 1, parc,
|
|
parv) == HUNTED_ISME)
|
|
{
|
|
m_info_send(sptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** m_dalinfo
|
|
** parv[0] = sender prefix
|
|
** parv[1] = servername
|
|
*/
|
|
CMD_FUNC(m_dalinfo)
|
|
{
|
|
char **text = dalinfotext;
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_DALINFO, TOK_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
|
|
*/
|
|
CMD_FUNC(m_license)
|
|
{
|
|
char **text = gnulicense;
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_LICENSE, TOK_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
|
|
*/
|
|
CMD_FUNC(m_credits)
|
|
{
|
|
char **text = unrealcredits;
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_CREDITS, TOK_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;
|
|
}
|
|
|
|
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;
|
|
/*
|
|
* This may seem like wack but remind this is only used
|
|
* in rows of get_client_name2's, so it's perfectly fair
|
|
*
|
|
*/
|
|
strcpy((char *)strrchr((char *)pointer, '.'), ".0]");
|
|
|
|
return pointer;
|
|
}
|
|
|
|
/*
|
|
** m_summon
|
|
** parv[0] = sender prefix
|
|
*/
|
|
CMD_FUNC(m_summon)
|
|
{
|
|
/* /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
|
|
*/
|
|
CMD_FUNC(m_users)
|
|
{
|
|
/* /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
|
|
*/
|
|
CMD_FUNC(m_error)
|
|
{
|
|
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(void)
|
|
{
|
|
free_str_list(helpign);
|
|
}
|
|
|
|
EVENT(save_tunefile)
|
|
{
|
|
FILE *tunefile;
|
|
|
|
tunefile = fopen(conf_files->tune_file, "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, "%d\n", IRCstats.me_max);
|
|
fclose(tunefile);
|
|
}
|
|
|
|
void load_tunefile(void)
|
|
{
|
|
FILE *tunefile;
|
|
char buf[1024];
|
|
|
|
tunefile = fopen(conf_files->tune_file, "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);
|
|
}
|
|
|
|
/** Rehash motd and rule files (motd_file/rules_file and all tld entries). */
|
|
void rehash_motdrules()
|
|
{
|
|
ConfigItem_tld *tlds;
|
|
|
|
motd = (aMotd *) read_file_ex(conf_files->motd_file, &motd, &motd_tm);
|
|
rules = (aMotd *) read_file(conf_files->rules_file, &rules);
|
|
smotd = (aMotd *) read_file_ex(conf_files->smotd_file, &smotd, &smotd_tm);
|
|
for (tlds = conf_tld; tlds; tlds = (ConfigItem_tld *) tlds->next)
|
|
{
|
|
tlds->motd = read_file_ex(tlds->motd_file, &tlds->motd, &tlds->motd_tm);
|
|
tlds->rules = read_file(tlds->rules_file, &tlds->rules);
|
|
if (tlds->smotd_file)
|
|
tlds->smotd = read_file_ex(tlds->smotd_file, &tlds->smotd, &tlds->smotd_tm);
|
|
if (tlds->opermotd_file)
|
|
tlds->opermotd = read_file(tlds->opermotd_file, &tlds->opermotd);
|
|
if (tlds->botmotd_file)
|
|
tlds->botmotd = read_file(tlds->botmotd_file, &tlds->botmotd);
|
|
}
|
|
}
|
|
|
|
void reread_motdsandrules()
|
|
{
|
|
motd = (aMotd *) read_file_ex(conf_files->motd_file, &motd, &motd_tm);
|
|
rules = (aMotd *) read_file(conf_files->rules_file, &rules);
|
|
smotd = (aMotd *) read_file_ex(conf_files->smotd_file, &smotd, &smotd_tm);
|
|
botmotd = (aMotd *) read_file(conf_files->botmotd_file, &botmotd);
|
|
opermotd = (aMotd *) read_file(conf_files->opermotd_file, &opermotd);
|
|
svsmotd = (aMotd *) read_file(conf_files->svsmotd_file, &svsmotd);
|
|
}
|
|
|
|
extern void reinit_resolver(aClient *sptr);
|
|
|
|
/*
|
|
** 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)
|
|
** fixed remote rehashing, but it's getting a bit weird code again -- Syzop
|
|
** removed '-all' code, this is now considered as '/rehash', this is ok
|
|
** since we rehash everything with simple '/rehash' now. Syzop/20040205
|
|
*/
|
|
CMD_FUNC(m_rehash)
|
|
{
|
|
int x;
|
|
|
|
if (MyClient(sptr) && !OPCanRehash(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
if (!MyClient(sptr) && !IsNetAdmin(sptr)
|
|
&& !IsULine(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
x = 0;
|
|
|
|
if ((parc < 3) || BadPtr(parv[2])) {
|
|
/* If the argument starts with a '-' (like -motd, -opermotd, etc) then it's
|
|
* assumed not to be a server. -- Syzop
|
|
*/
|
|
if (parv[1] && (parv[1][0] == '-'))
|
|
x = HUNTED_ISME;
|
|
else
|
|
x = hunt_server_token(cptr, sptr, MSG_REHASH, TOK_REHASH, "%s", 1, parc, parv);
|
|
} else {
|
|
x = hunt_server_token(cptr, sptr, MSG_REHASH, TOK_REHASH, "%s %s", 1, parc, parv);
|
|
}
|
|
if (x != HUNTED_ISME)
|
|
return 0; /* Now forwarded or server didnt exist */
|
|
|
|
if (cptr != sptr)
|
|
{
|
|
#ifndef REMOTE_REHASH
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
#endif
|
|
if (parv[2] == NULL)
|
|
{
|
|
if (loop.ircd_rehashing)
|
|
{
|
|
sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress",
|
|
me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
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]);
|
|
reread_motdsandrules();
|
|
return rehash(cptr, sptr,
|
|
(parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
|
|
}
|
|
parv[1] = parv[2];
|
|
}
|
|
|
|
if (!BadPtr(parv[1]) && stricmp(parv[1], "-all"))
|
|
{
|
|
|
|
if (!IsAdmin(sptr) && !IsCoAdmin(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
if (*parv[1] == '-')
|
|
{
|
|
if (!strnicmp("-gar", parv[1], 4))
|
|
{
|
|
loop.do_garbage_collect = 1;
|
|
RunHook3(HOOKTYPE_REHASHFLAG, cptr, sptr, parv[1]);
|
|
return 0;
|
|
}
|
|
if (!strnicmp("-dns", parv[1], 4))
|
|
{
|
|
reinit_resolver(sptr);
|
|
return 0;
|
|
}
|
|
if (!_match("-ssl*", parv[1]))
|
|
{
|
|
#ifdef USE_SSL
|
|
reinit_ssl(sptr);
|
|
#else
|
|
sendnotice(sptr, "SSL is not enabled on this server");
|
|
#endif
|
|
return 0;
|
|
}
|
|
if (!_match("-o*motd", parv[1]))
|
|
{
|
|
sendto_ops
|
|
("%sRehashing OperMOTD on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
if (cptr != sptr)
|
|
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing OperMOTD", me.name, sptr->name);
|
|
opermotd = (aMotd *) read_file(conf_files->opermotd_file, &opermotd);
|
|
RunHook3(HOOKTYPE_REHASHFLAG, cptr, sptr, parv[1]);
|
|
return 0;
|
|
}
|
|
if (!_match("-b*motd", parv[1]))
|
|
{
|
|
sendto_ops
|
|
("%sRehashing BotMOTD on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
if (cptr != sptr)
|
|
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing BotMOTD", me.name, sptr->name);
|
|
botmotd = (aMotd *) read_file(conf_files->botmotd_file, &botmotd);
|
|
RunHook3(HOOKTYPE_REHASHFLAG, cptr, sptr, parv[1]);
|
|
return 0;
|
|
}
|
|
if (!strnicmp("-motd", parv[1], 5)
|
|
|| !strnicmp("-rules", parv[1], 6))
|
|
{
|
|
sendto_ops
|
|
("%sRehashing all MOTDs and RULES on request of %s",
|
|
cptr != sptr ? "Remotely " : "",
|
|
sptr->name);
|
|
if (cptr != sptr)
|
|
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing all MOTDs and RULES", me.name, sptr->name);
|
|
rehash_motdrules();
|
|
RunHook3(HOOKTYPE_REHASHFLAG, cptr, sptr, parv[1]);
|
|
return 0;
|
|
}
|
|
RunHook3(HOOKTYPE_REHASHFLAG, cptr, sptr, parv[1]);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (loop.ircd_rehashing)
|
|
{
|
|
sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress",
|
|
me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
sendto_ops("%s is rehashing server config file", parv[0]);
|
|
}
|
|
|
|
/* Normal rehash, rehash motds&rules too, just like the on in the tld block will :p */
|
|
if (cptr == sptr)
|
|
sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
|
|
x = rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
|
|
reread_motdsandrules();
|
|
return x;
|
|
}
|
|
|
|
/*
|
|
** 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
|
|
*/
|
|
CMD_FUNC(m_restart)
|
|
{
|
|
char *reason = parv[1];
|
|
aClient *acptr;
|
|
int i;
|
|
/* Check permissions */
|
|
if (MyClient(sptr) && !OPCanRestart(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
if (!MyClient(sptr) && !IsNetAdmin(sptr) && !IsULine(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CHROOTDIR
|
|
sendnotice(sptr, "/RESTART does not work on chrooted servers");
|
|
return 0;
|
|
#endif
|
|
|
|
/* Syntax: /restart */
|
|
if (parc == 1)
|
|
{
|
|
if (conf_drpass)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RESTART");
|
|
return 0;
|
|
}
|
|
} else
|
|
if (parc >= 2)
|
|
{
|
|
/* Syntax: /restart <pass> [reason] */
|
|
if (conf_drpass)
|
|
{
|
|
int ret;
|
|
ret = Auth_Check(cptr, conf_drpass->restartauth, parv[1]);
|
|
if (ret == -1)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
if (ret < 1)
|
|
return 0;
|
|
reason = parv[2];
|
|
}
|
|
}
|
|
sendto_ops("Server is Restarting by request of %s", parv[0]);
|
|
|
|
for (i = 0; i <= LastSlot; i++)
|
|
{
|
|
if (!(acptr = local[i]))
|
|
continue;
|
|
if (IsClient(acptr))
|
|
sendto_one(acptr,
|
|
":%s %s %s :Server Restarting. %s",
|
|
me.name, IsWebTV(acptr) ? "PRIVMSG" : "NOTICE", acptr->name, sptr->name);
|
|
else if (IsServer(acptr))
|
|
sendto_one(acptr, ":%s ERROR :Restarted by %s: %s",
|
|
me.name, get_client_name(sptr, TRUE), reason ? reason : "No reason");
|
|
}
|
|
|
|
server_reboot(reason ? reason : "No reason");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Heavily modified from the ircu m_motd by codemastr
|
|
* Also svsmotd support added
|
|
*/
|
|
int short_motd(aClient *sptr) {
|
|
ConfigItem_tld *ptr;
|
|
aMotd *temp;
|
|
struct tm *tm = &smotd_tm;
|
|
char userhost[HOSTLEN + USERLEN + 6];
|
|
char is_short = 1;
|
|
strlcpy(userhost,make_user_host(sptr->user->username, sptr->user->realhost), sizeof userhost);
|
|
ptr = Find_tld(sptr, userhost);
|
|
|
|
if (ptr)
|
|
{
|
|
if (ptr->smotd)
|
|
{
|
|
temp = ptr->smotd;
|
|
tm = &ptr->smotd_tm;
|
|
}
|
|
else if (smotd)
|
|
temp = smotd;
|
|
else
|
|
{
|
|
temp = ptr->motd;
|
|
tm = &ptr->motd_tm;
|
|
is_short = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (smotd)
|
|
temp = smotd;
|
|
else
|
|
{
|
|
temp = motd;
|
|
tm = &motd_tm;
|
|
is_short = 0;
|
|
}
|
|
}
|
|
|
|
if (!temp)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOMOTD), me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
if (tm)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, sptr->name,
|
|
me.name);
|
|
sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name,
|
|
RPL_MOTD, sptr->name, tm->tm_mday, tm->tm_mon + 1,
|
|
1900 + tm->tm_year, tm->tm_hour, tm->tm_min);
|
|
}
|
|
if (is_short)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, sptr->name,
|
|
"This is the short MOTD. To view the complete MOTD type /motd");
|
|
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, sptr->name, "");
|
|
}
|
|
|
|
while (temp)
|
|
{
|
|
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, sptr->name,
|
|
temp->line);
|
|
temp = temp->next;
|
|
}
|
|
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Heavily modified from the ircu m_motd by codemastr
|
|
* Also svsmotd support added
|
|
*/
|
|
CMD_FUNC(m_motd)
|
|
{
|
|
ConfigItem_tld *ptr;
|
|
aMotd *temp, *temp2;
|
|
struct tm *tm = &motd_tm;
|
|
int svsnofile = 0;
|
|
char userhost[HOSTLEN + USERLEN + 6];
|
|
|
|
if (IsServer(sptr))
|
|
return 0;
|
|
if (hunt_server_token(cptr, sptr, MSG_MOTD, TOK_MOTD, ":%s", 1, parc, parv) !=
|
|
HUNTED_ISME)
|
|
return 0;
|
|
#ifndef TLINE_Remote
|
|
if (!MyConnect(sptr))
|
|
{
|
|
temp = motd;
|
|
goto playmotd;
|
|
}
|
|
#endif
|
|
strlcpy(userhost,make_user_host(cptr->user->username, cptr->user->realhost), sizeof userhost);
|
|
ptr = Find_tld(sptr, userhost);
|
|
|
|
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
|
|
*/
|
|
CMD_FUNC(m_opermotd)
|
|
{
|
|
aMotd *temp;
|
|
ConfigItem_tld *ptr;
|
|
char userhost[HOSTLEN + USERLEN + 6];
|
|
strlcpy(userhost,make_user_host(cptr->user->username, cptr->user->realhost), sizeof userhost);
|
|
ptr = Find_tld(sptr, userhost);
|
|
|
|
if (ptr)
|
|
{
|
|
if (ptr->opermotd)
|
|
temp = ptr->opermotd;
|
|
else
|
|
temp = opermotd;
|
|
}
|
|
else
|
|
temp = opermotd;
|
|
|
|
if (!IsAnOper(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
if (!temp)
|
|
{
|
|
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],
|
|
"IRC Operator Message of the Day");
|
|
|
|
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
|
|
* we can now use 1 function for multiple files -- codemastr
|
|
* Merged read_motd/read_rules stuff into this -- Syzop
|
|
*/
|
|
|
|
/** Read motd-like file, used for rules/motd/botmotd/opermotd/etc.
|
|
* @param filename Filename of file to read.
|
|
* @param list Reference to motd pointer (used for freeing if needed, can be NULL)
|
|
* @returns Pointer to MOTD or NULL if reading failed.
|
|
*/
|
|
aMotd *read_file(char *filename, aMotd **list)
|
|
{
|
|
return read_file_ex(filename, list, NULL);
|
|
}
|
|
|
|
void free_motd(aMotd *m)
|
|
{
|
|
aMotd *next;
|
|
|
|
for (; m; m = next)
|
|
{
|
|
next = m->next;
|
|
MyFree(m->line);
|
|
MyFree(m);
|
|
}
|
|
}
|
|
|
|
/** Read motd-like file, used for rules/motd/botmotd/opermotd/etc.
|
|
* @param filename Filename of file to read.
|
|
* @param list Reference to motd pointer (used for freeing if needed, NULL allowed)
|
|
* @param t Pointer to struct tm to store filedatetime info in (NULL allowed)
|
|
* @returns Pointer to MOTD or NULL if reading failed.
|
|
*/
|
|
aMotd *read_file_ex(char *filename, aMotd **list, struct tm *t)
|
|
{
|
|
|
|
int fd = open(filename, O_RDONLY);
|
|
aMotd *temp, *newmotd, *last, *old;
|
|
char line[82];
|
|
char *tmp;
|
|
int i;
|
|
|
|
if (fd == -1)
|
|
return NULL;
|
|
|
|
if (list)
|
|
{
|
|
free_motd(*list);
|
|
*list = NULL;
|
|
}
|
|
|
|
if (t)
|
|
{
|
|
struct tm *ttmp;
|
|
struct stat sb;
|
|
if (!fstat(fd, &sb))
|
|
{
|
|
ttmp = localtime(&sb.st_mtime);
|
|
memcpy(t, ttmp, sizeof(struct tm));
|
|
} else {
|
|
/* Sure, fstat() shouldn't fail, but... */
|
|
memset(t, 0, sizeof(struct tm));
|
|
}
|
|
}
|
|
|
|
(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
|
|
*/
|
|
CMD_FUNC(m_botmotd)
|
|
{
|
|
aMotd *temp;
|
|
ConfigItem_tld *ptr;
|
|
char userhost[HOSTLEN + USERLEN + 6];
|
|
|
|
if (hunt_server_token(cptr, sptr, MSG_BOTMOTD, TOK_BOTMOTD, ":%s", 1, parc,
|
|
parv) != HUNTED_ISME)
|
|
return 0;
|
|
|
|
if (!IsPerson(sptr))
|
|
return 0;
|
|
|
|
strlcpy(userhost,make_user_host(sptr->user->username, sptr->user->realhost), sizeof userhost);
|
|
ptr = Find_tld(sptr, userhost);
|
|
|
|
if (ptr)
|
|
{
|
|
if (ptr->botmotd)
|
|
temp = ptr->botmotd;
|
|
else
|
|
temp = botmotd;
|
|
}
|
|
else
|
|
temp = botmotd;
|
|
|
|
if (!temp)
|
|
{
|
|
sendto_one(sptr, ":%s NOTICE %s :BOTMOTD File not found",
|
|
me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
sendto_one(sptr, ":%s NOTICE %s :- %s Bot Message of the Day - ",
|
|
me.name, sptr->name, me.name);
|
|
|
|
while (temp)
|
|
{
|
|
sendto_one(sptr, ":%s NOTICE %s :- %s", me.name, sptr->name, temp->line);
|
|
temp = temp->next;
|
|
}
|
|
sendto_one(sptr, ":%s NOTICE %s :End of /BOTMOTD command.", me.name, sptr->name);
|
|
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...
|
|
*/
|
|
CMD_FUNC(m_die)
|
|
{
|
|
aClient *acptr;
|
|
int i;
|
|
if (!MyClient(sptr) || !OPCanDie(sptr))
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
|
|
return 0;
|
|
}
|
|
|
|
if (conf_drpass) /* 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;
|
|
}
|
|
i = Auth_Check(cptr, conf_drpass->dieauth, parv[1]);
|
|
if (i == -1)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name,
|
|
parv[0]);
|
|
return 0;
|
|
}
|
|
if (i < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Let the +s know what is going on */
|
|
sendto_ops("Server Terminating by request of %s", parv[0]);
|
|
|
|
for (i = 0; i <= LastSlot; i++)
|
|
{
|
|
if (!(acptr = local[i]))
|
|
continue;
|
|
if (IsClient(acptr))
|
|
sendto_one(acptr,
|
|
":%s %s %s :Server Terminating. %s",
|
|
me.name, IsWebTV(acptr) ? "PRIVMSG" : "NOTICE", acptr->name, sptr->name);
|
|
else if (IsServer(acptr))
|
|
sendto_one(acptr, ":%s ERROR :Terminated by %s",
|
|
me.name, get_client_name(sptr, TRUE));
|
|
}
|
|
(void)s_die();
|
|
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 <= LastSlot; i++)
|
|
{
|
|
if (!(acptr = local[i]))
|
|
continue;
|
|
if (IsClient(acptr))
|
|
sendto_one(acptr,
|
|
":%s %s %s :Server Terminated by local console",
|
|
me.name, IsWebTV(acptr) ? "PRIVMSG" : "NOTICE", acptr->name);
|
|
else if (IsServer(acptr))
|
|
sendto_one(acptr,
|
|
":%s ERROR :Terminated by local console", me.name);
|
|
}
|
|
(void)s_die();
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
aClient *find_match_server(char *mask)
|
|
{
|
|
aClient *acptr;
|
|
|
|
if (BadPtr(mask))
|
|
return NULL;
|
|
for (acptr = client, collapse(mask); acptr; acptr = acptr->next)
|
|
{
|
|
if (!IsServer(acptr) && !IsMe(acptr))
|
|
continue;
|
|
if (!match(mask, acptr->name))
|
|
break;
|
|
continue;
|
|
}
|
|
return acptr;
|
|
}
|
|
|
|
aPendingNet *pendingnet = NULL;
|
|
|
|
void add_pending_net(aClient *sptr, char *str)
|
|
{
|
|
aPendingNet *e = NULL;
|
|
int num = 1;
|
|
char *p, *name;
|
|
|
|
if (BadPtr(str) || !sptr)
|
|
return;
|
|
|
|
/* First, count them */
|
|
for (p = str; *p; p++)
|
|
if (*p == ',')
|
|
num++;
|
|
|
|
/* Allocate */
|
|
e = MyMallocEx(sizeof(aPendingNet) + (sizeof(int) * num));
|
|
|
|
e->numservers = num;
|
|
e->sptr = sptr;
|
|
|
|
/* Fill in */
|
|
num = 0;
|
|
for (name = strtoken(&p, str, ","); name; name = strtoken(&p, NULL, ","))
|
|
{
|
|
if (!*name)
|
|
continue;
|
|
|
|
/* skip any non-digit prefixes, if necessary. Possibly needed in the future. */
|
|
while (*name && !isdigit(*name))
|
|
name++;
|
|
|
|
e->servers[num++] = atoi(name);
|
|
}
|
|
|
|
AddListItem(e, pendingnet);
|
|
}
|
|
|
|
void free_pending_net(aClient *sptr)
|
|
{
|
|
aPendingNet *e, *e_next;
|
|
|
|
for (e = pendingnet; e; e = e_next)
|
|
{
|
|
e_next = e->next;
|
|
if (e->sptr == sptr)
|
|
{
|
|
DelListItem(e, pendingnet);
|
|
MyFree(e);
|
|
/* Don't break, there can be multiple objects */
|
|
}
|
|
}
|
|
}
|
|
|
|
aPendingNet *find_pending_net_by_numeric_butone(int numeric, aClient *exempt)
|
|
{
|
|
aPendingNet *e;
|
|
int i;
|
|
|
|
if (numeric <= 0)
|
|
return NULL;
|
|
|
|
for (e = pendingnet; e; e = e->next)
|
|
{
|
|
if (e->sptr == exempt)
|
|
continue;
|
|
for (i = 0; i < e->numservers; i++)
|
|
if (e->servers[i] == numeric)
|
|
return e;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/** Search the pending connections list for any identical numerics */
|
|
aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, int *numeric)
|
|
{
|
|
aPendingNet *e, *other;
|
|
int i;
|
|
|
|
*srv = NULL;
|
|
*numeric = 0;
|
|
|
|
for (e = pendingnet; e; e = e->next)
|
|
{
|
|
if (e->sptr != cptr)
|
|
continue;
|
|
/* Ok, found myself */
|
|
for (i = 0; i < e->numservers; i++)
|
|
{
|
|
int curr_numeric = e->servers[i];
|
|
other = find_pending_net_by_numeric_butone(curr_numeric, cptr);
|
|
if (other)
|
|
{
|
|
*srv = e->sptr;
|
|
*numeric = curr_numeric;
|
|
return other->sptr; /* Found another (pending) server with identical numeric */
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
aClient *find_non_pending_net_duplicates(aClient *cptr)
|
|
{
|
|
aPendingNet *e;
|
|
int i;
|
|
aClient *acptr;
|
|
|
|
for (e = pendingnet; e; e = e->next)
|
|
{
|
|
if (e->sptr != cptr)
|
|
continue;
|
|
/* Ok, found myself */
|
|
for (i = 0; i < e->numservers; i++)
|
|
{
|
|
int numeric = e->servers[i];
|
|
acptr = find_server_by_numeric(numeric);
|
|
if (acptr)
|
|
return acptr; /* Found another (fully CONNECTED) server with identical numeric */
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|