mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-02 04:26:38 +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; };
9904 lines
250 KiB
C
9904 lines
250 KiB
C
/*
|
|
* Unreal Internet Relay Chat Daemon, src/s_conf.c
|
|
* (C) 1998-2000 Chris Behrens & Fred Jacobs (comstud, moogle)
|
|
* (C) 2000-2002 Carsten V. Munk and the UnrealIRCd Team
|
|
*
|
|
* 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.
|
|
*/
|
|
#include "struct.h"
|
|
#include "url.h"
|
|
#include "common.h"
|
|
#include "sys.h"
|
|
#include "numeric.h"
|
|
#include "channel.h"
|
|
#include "macros.h"
|
|
#include <fcntl.h>
|
|
#ifndef _WIN32
|
|
#include <sys/socket.h>
|
|
#include <sys/wait.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#ifdef __hpux
|
|
#include "inet.h"
|
|
#endif
|
|
#if defined(PCS) || defined(AIX) || defined(SVR3)
|
|
#include <time.h>
|
|
#endif
|
|
#include <string.h>
|
|
#ifdef GLOBH
|
|
#include <glob.h>
|
|
#endif
|
|
#ifdef STRIPBADWORDS
|
|
#include "badwords.h"
|
|
#endif
|
|
#include "h.h"
|
|
#include "inet.h"
|
|
#include "proto.h"
|
|
#ifdef _WIN32
|
|
#undef GLOBH
|
|
#endif
|
|
#include "badwords.h"
|
|
|
|
#define ircstrdup(x,y) do { if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y); } while(0)
|
|
#define ircfree(x) do { if (x) MyFree(x); x = NULL; } while(0)
|
|
|
|
/*
|
|
* Some typedefs..
|
|
*/
|
|
typedef struct _confcommand ConfigCommand;
|
|
struct _confcommand
|
|
{
|
|
char *name;
|
|
int (*conffunc)(ConfigFile *conf, ConfigEntry *ce);
|
|
int (*testfunc)(ConfigFile *conf, ConfigEntry *ce);
|
|
};
|
|
|
|
typedef struct _conf_operflag OperFlag;
|
|
struct _conf_operflag
|
|
{
|
|
long flag;
|
|
char *name;
|
|
};
|
|
|
|
|
|
/* Config commands */
|
|
|
|
static int _conf_admin (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_me (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_files (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_oper (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_class (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_drpass (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_ulines (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_include (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_tld (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_listen (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_allow (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_except (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_vhost (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_link (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_ban (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_set (ConfigFile *conf, ConfigEntry *ce);
|
|
#ifdef STRIPBADWORDS
|
|
static int _conf_badword (ConfigFile *conf, ConfigEntry *ce);
|
|
#endif
|
|
static int _conf_deny (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_deny_dcc (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_deny_link (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_deny_channel (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_deny_version (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_allow_channel (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_allow_dcc (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_loadmodule (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_log (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_alias (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_help (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_offchans (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_spamfilter (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _conf_cgiirc (ConfigFile *conf, ConfigEntry *ce);
|
|
|
|
/*
|
|
* Validation commands
|
|
*/
|
|
|
|
static int _test_admin (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_me (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_files (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_oper (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_class (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_drpass (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_ulines (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_include (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_tld (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_listen (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_allow (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_except (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_vhost (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_link (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_ban (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_set (ConfigFile *conf, ConfigEntry *ce);
|
|
#ifdef STRIPBADWORDS
|
|
static int _test_badword (ConfigFile *conf, ConfigEntry *ce);
|
|
#endif
|
|
static int _test_deny (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_allow_channel (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_allow_dcc (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_loadmodule (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_log (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_alias (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_help (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_offchans (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_spamfilter (ConfigFile *conf, ConfigEntry *ce);
|
|
static int _test_cgiirc (ConfigFile *conf, ConfigEntry *ce);
|
|
|
|
/* This MUST be alphabetized */
|
|
static ConfigCommand _ConfigCommands[] = {
|
|
{ "admin", _conf_admin, _test_admin },
|
|
{ "alias", _conf_alias, _test_alias },
|
|
{ "allow", _conf_allow, _test_allow },
|
|
#ifdef STRIPBADWORDS
|
|
{ "badword", _conf_badword, _test_badword },
|
|
#endif
|
|
{ "ban", _conf_ban, _test_ban },
|
|
{ "cgiirc", _conf_cgiirc, _test_cgiirc },
|
|
{ "class", _conf_class, _test_class },
|
|
{ "deny", _conf_deny, _test_deny },
|
|
{ "drpass", _conf_drpass, _test_drpass },
|
|
{ "except", _conf_except, _test_except },
|
|
{ "files", _conf_files, _test_files },
|
|
{ "help", _conf_help, _test_help },
|
|
{ "include", NULL, _test_include },
|
|
{ "link", _conf_link, _test_link },
|
|
{ "listen", _conf_listen, _test_listen },
|
|
{ "loadmodule", NULL, _test_loadmodule},
|
|
{ "log", _conf_log, _test_log },
|
|
{ "me", _conf_me, _test_me },
|
|
{ "official-channels", _conf_offchans, _test_offchans },
|
|
{ "oper", _conf_oper, _test_oper },
|
|
{ "set", _conf_set, _test_set },
|
|
{ "spamfilter", _conf_spamfilter, _test_spamfilter },
|
|
{ "tld", _conf_tld, _test_tld },
|
|
{ "ulines", _conf_ulines, _test_ulines },
|
|
{ "vhost", _conf_vhost, _test_vhost },
|
|
};
|
|
|
|
static int _OldOperFlags[] = {
|
|
OFLAG_LOCAL, 'o',
|
|
OFLAG_GLOBAL, 'O',
|
|
OFLAG_REHASH, 'r',
|
|
OFLAG_DIE, 'D',
|
|
OFLAG_RESTART, 'R',
|
|
OFLAG_HELPOP, 'h',
|
|
OFLAG_GLOBOP, 'g',
|
|
OFLAG_WALLOP, 'w',
|
|
OFLAG_LOCOP, 'l',
|
|
OFLAG_LROUTE, 'c',
|
|
OFLAG_GROUTE, 'L',
|
|
OFLAG_LKILL, 'k',
|
|
OFLAG_GKILL, 'K',
|
|
OFLAG_KLINE, 'b',
|
|
OFLAG_UNKLINE, 'B',
|
|
OFLAG_LNOTICE, 'n',
|
|
OFLAG_GNOTICE, 'G',
|
|
OFLAG_ADMIN_, 'A',
|
|
OFLAG_SADMIN_, 'a',
|
|
OFLAG_NADMIN, 'N',
|
|
OFLAG_COADMIN, 'C',
|
|
OFLAG_ZLINE, 'z',
|
|
OFLAG_WHOIS, 'W',
|
|
OFLAG_HIDE, 'H',
|
|
OFLAG_TKL, 't',
|
|
OFLAG_GZL, 'Z',
|
|
OFLAG_OVERRIDE, 'v',
|
|
OFLAG_UMODEQ, 'q',
|
|
OFLAG_DCCDENY, 'd',
|
|
OFLAG_ADDLINE, 'X',
|
|
0, 0
|
|
};
|
|
|
|
/* This MUST be alphabetized */
|
|
static OperFlag _OperFlags[] = {
|
|
{ OFLAG_ADMIN_, "admin"},
|
|
{ OFLAG_ADDLINE, "can_addline"},
|
|
{ OFLAG_DCCDENY, "can_dccdeny"},
|
|
{ OFLAG_DIE, "can_die" },
|
|
{ OFLAG_TKL, "can_gkline"},
|
|
{ OFLAG_GKILL, "can_globalkill" },
|
|
{ OFLAG_GNOTICE, "can_globalnotice" },
|
|
{ OFLAG_GROUTE, "can_globalroute" },
|
|
{ OFLAG_GLOBOP, "can_globops" },
|
|
{ OFLAG_GZL, "can_gzline"},
|
|
{ OFLAG_KLINE, "can_kline" },
|
|
{ OFLAG_LKILL, "can_localkill" },
|
|
{ OFLAG_LNOTICE, "can_localnotice" },
|
|
{ OFLAG_LROUTE, "can_localroute" },
|
|
{ OFLAG_OVERRIDE, "can_override" },
|
|
{ OFLAG_REHASH, "can_rehash" },
|
|
{ OFLAG_RESTART, "can_restart" },
|
|
{ OFLAG_UMODEQ, "can_setq" },
|
|
{ OFLAG_UNKLINE, "can_unkline" },
|
|
{ OFLAG_WALLOP, "can_wallops" },
|
|
{ OFLAG_ZLINE, "can_zline"},
|
|
{ OFLAG_COADMIN_, "coadmin"},
|
|
{ OFLAG_HIDE, "get_host"},
|
|
{ OFLAG_WHOIS, "get_umodew"},
|
|
{ OFLAG_GLOBAL, "global" },
|
|
{ OFLAG_HELPOP, "helpop" },
|
|
{ OFLAG_LOCAL, "local" },
|
|
{ OFLAG_LOCOP, "locop"},
|
|
{ OFLAG_NADMIN, "netadmin"},
|
|
{ OFLAG_SADMIN_, "services-admin"},
|
|
};
|
|
|
|
/* This MUST be alphabetized */
|
|
static OperFlag _ListenerFlags[] = {
|
|
{ LISTENER_CLIENTSONLY, "clientsonly"},
|
|
{ LISTENER_JAVACLIENT, "java"},
|
|
{ LISTENER_MASK, "mask"},
|
|
{ LISTENER_REMOTEADMIN, "remoteadmin"},
|
|
{ LISTENER_SERVERSONLY, "serversonly"},
|
|
{ LISTENER_SSL, "ssl"},
|
|
{ LISTENER_NORMAL, "standard"},
|
|
};
|
|
|
|
/* This MUST be alphabetized */
|
|
static OperFlag _LinkFlags[] = {
|
|
{ CONNECT_AUTO, "autoconnect" },
|
|
{ CONNECT_NODNSCACHE, "nodnscache" },
|
|
{ CONNECT_NOHOSTCHECK, "nohostcheck" },
|
|
{ CONNECT_QUARANTINE, "quarantine"},
|
|
{ CONNECT_SSL, "ssl" },
|
|
{ CONNECT_ZIP, "zip" },
|
|
};
|
|
|
|
/* This MUST be alphabetized */
|
|
static OperFlag _LogFlags[] = {
|
|
{ LOG_CHGCMDS, "chg-commands" },
|
|
{ LOG_CLIENT, "connects" },
|
|
{ LOG_ERROR, "errors" },
|
|
{ LOG_KILL, "kills" },
|
|
{ LOG_KLINE, "kline" },
|
|
{ LOG_OPER, "oper" },
|
|
{ LOG_OVERRIDE, "oper-override" },
|
|
{ LOG_SACMDS, "sadmin-commands" },
|
|
{ LOG_SERVER, "server-connects" },
|
|
{ LOG_SPAMFILTER, "spamfilter" },
|
|
{ LOG_TKL, "tkl" },
|
|
};
|
|
|
|
/* This MUST be alphabetized */
|
|
static OperFlag ExceptTklFlags[] = {
|
|
{ TKL_GLOBAL|TKL_KILL, "gline" },
|
|
{ TKL_GLOBAL|TKL_NICK, "gqline" },
|
|
{ TKL_GLOBAL|TKL_ZAP, "gzline" },
|
|
{ TKL_NICK, "qline" },
|
|
{ TKL_GLOBAL|TKL_SHUN, "shun" }
|
|
};
|
|
|
|
#ifdef USE_SSL
|
|
/* This MUST be alphabetized */
|
|
static OperFlag _SSLFlags[] = {
|
|
{ SSLFLAG_FAILIFNOCERT, "fail-if-no-clientcert" },
|
|
{ SSLFLAG_DONOTACCEPTSELFSIGNED, "no-self-signed" },
|
|
{ SSLFLAG_VERIFYCERT, "verify-certificate" },
|
|
{ SSLFLAG_NOSTARTTLS, "no-starttls" }
|
|
};
|
|
#endif
|
|
|
|
struct {
|
|
unsigned conf_me : 1;
|
|
unsigned conf_admin : 1;
|
|
unsigned conf_listen : 1;
|
|
} requiredstuff;
|
|
struct SetCheck settings;
|
|
/*
|
|
* Utilities
|
|
*/
|
|
|
|
void ipport_seperate(char *string, char **ip, char **port);
|
|
void port_range(char *string, int *start, int *end);
|
|
long config_checkval(char *value, unsigned short flags);
|
|
|
|
/*
|
|
* Parser
|
|
*/
|
|
|
|
ConfigFile *config_load(char *filename);
|
|
void config_free(ConfigFile *cfptr);
|
|
static ConfigFile *config_parse(char *filename, char *confdata);
|
|
static void config_entry_free(ConfigEntry *ceptr);
|
|
ConfigEntry *config_find_entry(ConfigEntry *ce, char *name);
|
|
/*
|
|
* Error handling
|
|
*/
|
|
|
|
void config_warn(char *format, ...);
|
|
void config_error(char *format, ...);
|
|
void config_status(char *format, ...);
|
|
void config_progress(char *format, ...);
|
|
|
|
#ifdef _WIN32
|
|
extern void win_log(char *format, ...);
|
|
extern void win_error();
|
|
#endif
|
|
extern void add_entropy_configfile(struct stat st, char *buf);
|
|
extern void unload_all_unused_snomasks();
|
|
extern void unload_all_unused_umodes();
|
|
extern void unload_all_unused_extcmodes(void);
|
|
|
|
extern int charsys_test_language(char *name);
|
|
extern void charsys_add_language(char *name);
|
|
extern void charsys_reset_pretest(void);
|
|
int charsys_postconftest(void);
|
|
void charsys_finish(void);
|
|
void delete_cgiircblock(ConfigItem_cgiirc *e);
|
|
|
|
/*
|
|
* Config parser (IRCd)
|
|
*/
|
|
int init_conf(char *rootconf, int rehash);
|
|
int load_conf(char *filename);
|
|
void config_rehash();
|
|
int config_run();
|
|
/*
|
|
* Configuration linked lists
|
|
*/
|
|
ConfigItem_me *conf_me = NULL;
|
|
ConfigItem_files *conf_files = NULL;
|
|
ConfigItem_class *conf_class = NULL;
|
|
ConfigItem_class *default_class = NULL;
|
|
ConfigItem_admin *conf_admin = NULL;
|
|
ConfigItem_admin *conf_admin_tail = NULL;
|
|
ConfigItem_drpass *conf_drpass = NULL;
|
|
ConfigItem_ulines *conf_ulines = NULL;
|
|
ConfigItem_tld *conf_tld = NULL;
|
|
ConfigItem_oper *conf_oper = NULL;
|
|
ConfigItem_listen *conf_listen = NULL;
|
|
ConfigItem_allow *conf_allow = NULL;
|
|
ConfigItem_except *conf_except = NULL;
|
|
ConfigItem_vhost *conf_vhost = NULL;
|
|
ConfigItem_link *conf_link = NULL;
|
|
ConfigItem_cgiirc *conf_cgiirc = NULL;
|
|
ConfigItem_ban *conf_ban = NULL;
|
|
ConfigItem_deny_dcc *conf_deny_dcc = NULL;
|
|
ConfigItem_deny_channel *conf_deny_channel = NULL;
|
|
ConfigItem_allow_channel *conf_allow_channel = NULL;
|
|
ConfigItem_allow_dcc *conf_allow_dcc = NULL;
|
|
ConfigItem_deny_link *conf_deny_link = NULL;
|
|
ConfigItem_deny_version *conf_deny_version = NULL;
|
|
ConfigItem_log *conf_log = NULL;
|
|
ConfigItem_alias *conf_alias = NULL;
|
|
ConfigItem_include *conf_include = NULL;
|
|
ConfigItem_help *conf_help = NULL;
|
|
#ifdef STRIPBADWORDS
|
|
ConfigItem_badword *conf_badword_channel = NULL;
|
|
ConfigItem_badword *conf_badword_message = NULL;
|
|
ConfigItem_badword *conf_badword_quit = NULL;
|
|
#endif
|
|
ConfigItem_offchans *conf_offchans = NULL;
|
|
|
|
aConfiguration iConf;
|
|
MODVAR aConfiguration tempiConf;
|
|
MODVAR ConfigFile *conf = NULL;
|
|
|
|
MODVAR int config_error_flag = 0;
|
|
int config_verbose = 0;
|
|
|
|
void add_include(char *);
|
|
#ifdef USE_LIBCURL
|
|
void add_remote_include(char *, char *, int, char *);
|
|
int remote_include(ConfigEntry *ce);
|
|
#endif
|
|
void unload_notloaded_includes(void);
|
|
void load_includes(void);
|
|
void unload_loaded_includes(void);
|
|
int rehash_internal(aClient *cptr, aClient *sptr, int sig);
|
|
|
|
|
|
/* Pick out the ip address and the port number from a string.
|
|
* The string syntax is: ip:port. ip must be enclosed in brackets ([]) if its an ipv6
|
|
* address because they contain colon (:) separators. The ip part is optional. If the string
|
|
* contains a single number its assumed to be a port number.
|
|
*
|
|
* Returns with ip pointing to the ip address (if one was specified), a "*" (if only a port
|
|
* was specified), or an empty string if there was an error. port is returned pointing to the
|
|
* port number if one was specified, otherwise it points to a empty string.
|
|
*/
|
|
void ipport_seperate(char *string, char **ip, char **port)
|
|
{
|
|
char *f;
|
|
|
|
/* assume failure */
|
|
*ip = *port = "";
|
|
|
|
/* sanity check */
|
|
if (string && strlen(string) > 0)
|
|
{
|
|
/* handle ipv6 type of ip address */
|
|
if (*string == '[')
|
|
{
|
|
if ((f = strrchr(string, ']')))
|
|
{
|
|
*ip = string + 1; /* skip [ */
|
|
*f = '\0'; /* terminate the ip string */
|
|
/* next char must be a : if a port was specified */
|
|
if (*++f == ':')
|
|
{
|
|
*port = ++f;
|
|
}
|
|
}
|
|
}
|
|
/* handle ipv4 and port */
|
|
else if ((f = strchr(string, ':')))
|
|
{
|
|
/* we found a colon... we may have ip:port or just :port */
|
|
if (f == string)
|
|
{
|
|
/* we have just :port */
|
|
*ip = "*";
|
|
}
|
|
else
|
|
{
|
|
/* we have ip:port */
|
|
*ip = string;
|
|
*f = '\0';
|
|
}
|
|
*port = ++f;
|
|
}
|
|
/* no ip was specified, just a port number */
|
|
else if (!strcmp(string, my_itoa(atoi(string))))
|
|
{
|
|
*ip = "*";
|
|
*port = string;
|
|
}
|
|
}
|
|
}
|
|
|
|
void port_range(char *string, int *start, int *end)
|
|
{
|
|
char *c = strchr(string, '-');
|
|
if (!c)
|
|
{
|
|
int tmp = atoi(string);
|
|
*start = tmp;
|
|
*end = tmp;
|
|
return;
|
|
}
|
|
*c = '\0';
|
|
*start = atoi(string);
|
|
*end = atoi((c+1));
|
|
}
|
|
|
|
/** Parses '5:60s' config values.
|
|
* orig: original string
|
|
* times: pointer to int, first value (before the :)
|
|
* period: pointer to int, second value (after the :) in seconds
|
|
* RETURNS: 0 for parse error, 1 if ok.
|
|
* REMARK: times&period should be ints!
|
|
*/
|
|
int config_parse_flood(char *orig, int *times, int *period)
|
|
{
|
|
char *x;
|
|
|
|
*times = *period = 0;
|
|
x = strchr(orig, ':');
|
|
/* 'blah', ':blah', '1:' */
|
|
if (!x || (x == orig) || (*(x+1) == '\0'))
|
|
return 0;
|
|
|
|
*x = '\0';
|
|
*times = atoi(orig);
|
|
*period = config_checkval(x+1, CFG_TIME);
|
|
*x = ':'; /* restore */
|
|
return 1;
|
|
}
|
|
|
|
long config_checkval(char *orig, unsigned short flags) {
|
|
char *value;
|
|
char *text;
|
|
long ret = 0;
|
|
|
|
value = strdup(orig);
|
|
|
|
if (flags == CFG_YESNO) {
|
|
for (text = value; *text; text++) {
|
|
if (!isalnum(*text))
|
|
continue;
|
|
if (tolower(*text) == 'y' || (tolower(*text) == 'o' &&
|
|
tolower(*(text+1)) == 'n') || *text == '1' || tolower(*text) == 't') {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (flags == CFG_SIZE) {
|
|
int mfactor = 1;
|
|
char *sz;
|
|
for (text = value; *text; text++) {
|
|
if (isalpha(*text)) {
|
|
if (tolower(*text) == 'k')
|
|
mfactor = 1024;
|
|
else if (tolower(*text) == 'm')
|
|
mfactor = 1048576;
|
|
else if (tolower(*text) == 'g')
|
|
mfactor = 1073741824;
|
|
else
|
|
mfactor = 1;
|
|
sz = text;
|
|
while (isalpha(*text))
|
|
text++;
|
|
|
|
*sz-- = 0;
|
|
while (sz-- > value && *sz) {
|
|
if (isspace(*sz))
|
|
*sz = 0;
|
|
if (!isdigit(*sz))
|
|
break;
|
|
}
|
|
ret += atoi(sz+1)*mfactor;
|
|
if (*text == '\0') {
|
|
text++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
mfactor = 1;
|
|
sz = text;
|
|
sz--;
|
|
while (sz-- > value) {
|
|
if (isspace(*sz))
|
|
*sz = 0;
|
|
if (!isdigit(*sz))
|
|
break;
|
|
}
|
|
ret += atoi(sz+1)*mfactor;
|
|
}
|
|
else if (flags == CFG_TIME) {
|
|
int mfactor = 1;
|
|
char *sz;
|
|
for (text = value; *text; text++) {
|
|
if (isalpha(*text)) {
|
|
if (tolower(*text) == 'w')
|
|
mfactor = 604800;
|
|
else if (tolower(*text) == 'd')
|
|
mfactor = 86400;
|
|
else if (tolower(*text) == 'h')
|
|
mfactor = 3600;
|
|
else if (tolower(*text) == 'm')
|
|
mfactor = 60;
|
|
else
|
|
mfactor = 1;
|
|
sz = text;
|
|
while (isalpha(*text))
|
|
text++;
|
|
|
|
*sz-- = 0;
|
|
while (sz-- > value && *sz) {
|
|
if (isspace(*sz))
|
|
*sz = 0;
|
|
if (!isdigit(*sz))
|
|
break;
|
|
}
|
|
ret += atoi(sz+1)*mfactor;
|
|
if (*text == '\0') {
|
|
text++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
mfactor = 1;
|
|
sz = text;
|
|
sz--;
|
|
while (sz-- > value) {
|
|
if (isspace(*sz))
|
|
*sz = 0;
|
|
if (!isdigit(*sz))
|
|
break;
|
|
}
|
|
ret += atoi(sz+1)*mfactor;
|
|
}
|
|
free(value);
|
|
return ret;
|
|
}
|
|
|
|
int iplist_onlist(IPList *iplist, char *ip)
|
|
{
|
|
IPList *e;
|
|
|
|
for (e = iplist; e; e = e->next)
|
|
if (!match(e->mask, ip))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void set_channelmodes(char *modes, struct ChMode *store, int warn)
|
|
{
|
|
aCtab *tab;
|
|
char *params = strchr(modes, ' ');
|
|
char *parambuf = NULL;
|
|
char *param = NULL;
|
|
char *save = NULL;
|
|
|
|
warn = 0; // warn is broken
|
|
|
|
if (params)
|
|
{
|
|
params++;
|
|
parambuf = MyMalloc(strlen(params)+1);
|
|
strcpy(parambuf, params);
|
|
param = strtoken(&save, parambuf, " ");
|
|
}
|
|
|
|
for (; *modes && *modes != ' '; modes++)
|
|
{
|
|
if (*modes == '+')
|
|
continue;
|
|
if (*modes == '-')
|
|
/* When a channel is created it has no modes, so just ignore if the
|
|
* user asks us to unset anything -- codemastr
|
|
*/
|
|
{
|
|
while (*modes && *modes != '+')
|
|
modes++;
|
|
continue;
|
|
}
|
|
switch (*modes)
|
|
{
|
|
case 'f':
|
|
{
|
|
#ifdef NEWCHFLOODPROT
|
|
char *myparam = param;
|
|
|
|
ChanFloodProt newf;
|
|
|
|
memset(&newf, 0, sizeof(newf));
|
|
if (!myparam)
|
|
break;
|
|
/* Go to next parameter */
|
|
param = strtoken(&save, NULL, " ");
|
|
|
|
if (myparam[0] != '[')
|
|
{
|
|
if (warn)
|
|
config_status("set::modes-on-join: please use the new +f format: '10:5' becomes '[10t]:5' "
|
|
"and '*10:5' becomes '[10t#b]:5'.");
|
|
} else
|
|
{
|
|
char xbuf[256], c, a, *p, *p2, *x = xbuf+1;
|
|
int v;
|
|
unsigned short breakit;
|
|
unsigned char r;
|
|
|
|
/* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */
|
|
strlcpy(xbuf, myparam, sizeof(xbuf));
|
|
p2 = strchr(xbuf+1, ']');
|
|
if (!p2)
|
|
break;
|
|
*p2 = '\0';
|
|
if (*(p2+1) != ':')
|
|
break;
|
|
breakit = 0;
|
|
for (x = strtok(xbuf+1, ","); x; x = strtok(NULL, ","))
|
|
{
|
|
/* <number><1 letter>[optional: '#'+1 letter] */
|
|
p = x;
|
|
while(isdigit(*p)) { p++; }
|
|
if ((*p == '\0') ||
|
|
!((*p == 'c') || (*p == 'j') || (*p == 'k') ||
|
|
(*p == 'm') || (*p == 'n') || (*p == 't')))
|
|
break;
|
|
c = *p;
|
|
*p = '\0';
|
|
v = atoi(x);
|
|
if ((v < 1) || (v > 999)) /* out of range... */
|
|
break;
|
|
p++;
|
|
a = '\0';
|
|
r = 0;
|
|
if (*p != '\0')
|
|
{
|
|
if (*p == '#')
|
|
{
|
|
p++;
|
|
a = *p;
|
|
p++;
|
|
if (*p != '\0')
|
|
{
|
|
int tv;
|
|
tv = atoi(p);
|
|
if (tv <= 0)
|
|
tv = 0; /* (ignored) */
|
|
if (tv > 255)
|
|
tv = 255; /* set to max */
|
|
r = tv;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(c)
|
|
{
|
|
case 'c':
|
|
newf.l[FLD_CTCP] = v;
|
|
if ((a == 'm') || (a == 'M'))
|
|
newf.a[FLD_CTCP] = a;
|
|
else
|
|
newf.a[FLD_CTCP] = 'C';
|
|
newf.r[FLD_CTCP] = r;
|
|
break;
|
|
case 'j':
|
|
newf.l[FLD_JOIN] = v;
|
|
if (a == 'R')
|
|
newf.a[FLD_JOIN] = a;
|
|
else
|
|
newf.a[FLD_JOIN] = 'i';
|
|
newf.r[FLD_JOIN] = r;
|
|
break;
|
|
case 'k':
|
|
newf.l[FLD_KNOCK] = v;
|
|
newf.a[FLD_KNOCK] = 'K';
|
|
newf.r[FLD_KNOCK] = r;
|
|
break;
|
|
case 'm':
|
|
newf.l[FLD_MSG] = v;
|
|
if (a == 'M')
|
|
newf.a[FLD_MSG] = a;
|
|
else
|
|
newf.a[FLD_MSG] = 'm';
|
|
newf.r[FLD_MSG] = r;
|
|
break;
|
|
case 'n':
|
|
newf.l[FLD_NICK] = v;
|
|
newf.a[FLD_NICK] = 'N';
|
|
newf.r[FLD_NICK] = r;
|
|
break;
|
|
case 't':
|
|
newf.l[FLD_TEXT] = v;
|
|
if (a == 'b')
|
|
newf.a[FLD_TEXT] = 'b';
|
|
/** newf.r[FLD_TEXT] ** not supported */
|
|
break;
|
|
default:
|
|
breakit=1;
|
|
break;
|
|
}
|
|
if (breakit)
|
|
break;
|
|
} /* for strtok.. */
|
|
if (breakit)
|
|
break;
|
|
/* parse 'per' */
|
|
p2++;
|
|
if (*p2 != ':')
|
|
break;
|
|
p2++;
|
|
if (!*p2)
|
|
break;
|
|
v = atoi(p2);
|
|
if ((v < 1) || (v > 999)) /* 'per' out of range */
|
|
break;
|
|
newf.per = v;
|
|
/* Is anything turned on? (to stop things like '+f []:15' */
|
|
breakit = 1;
|
|
for (v=0; v < NUMFLD; v++)
|
|
if (newf.l[v])
|
|
breakit=0;
|
|
if (breakit)
|
|
break;
|
|
|
|
/* w00t, we passed... */
|
|
memcpy(&store->floodprot, &newf, sizeof(newf));
|
|
store->mode |= MODE_FLOODLIMIT;
|
|
break;
|
|
}
|
|
#else
|
|
char *myparam = param;
|
|
char kmode = 0;
|
|
char *xp;
|
|
int msgs=0, per=0;
|
|
int hascolon = 0;
|
|
if (!myparam)
|
|
break;
|
|
/* Go to next parameter */
|
|
param = strtoken(&save, NULL, " ");
|
|
|
|
if (*myparam == '*')
|
|
kmode = 1;
|
|
for (xp = myparam; *xp; xp++)
|
|
{
|
|
if (*xp == ':')
|
|
{
|
|
hascolon++;
|
|
continue;
|
|
}
|
|
if (((*xp < '0') || (*xp > '9')) && *xp != '*')
|
|
break;
|
|
if (*xp == '*' && *myparam != '*')
|
|
break;
|
|
}
|
|
if (hascolon != 1)
|
|
break;
|
|
xp = strchr(myparam, ':');
|
|
*xp = 0;
|
|
msgs = atoi((*myparam == '*') ? (myparam+1) : myparam);
|
|
xp++;
|
|
per = atoi(xp);
|
|
xp--;
|
|
*xp = ':';
|
|
if (msgs == 0 || msgs > 500 || per == 0 || per > 500)
|
|
break;
|
|
store->msgs = msgs;
|
|
store->per = per;
|
|
store->kmode = kmode;
|
|
store->mode |= MODE_FLOODLIMIT;
|
|
#endif
|
|
break;
|
|
}
|
|
default:
|
|
for (tab = &cFlagTab[0]; tab->mode; tab++)
|
|
{
|
|
if (tab->flag == *modes)
|
|
{
|
|
if (tab->parameters)
|
|
{
|
|
/* INCOMPATIBLE */
|
|
break;
|
|
}
|
|
store->mode |= tab->mode;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef EXTCMODE
|
|
/* Try extcmodes */
|
|
if (!tab->mode)
|
|
{
|
|
int i;
|
|
for (i=0; i <= Channelmode_highest; i++)
|
|
{
|
|
if (!(Channelmode_Table[i].flag))
|
|
continue;
|
|
if (*modes == Channelmode_Table[i].flag)
|
|
{
|
|
if (Channelmode_Table[i].paracount)
|
|
{
|
|
if (!param)
|
|
break;
|
|
param = Channelmode_Table[i].conv_param(param);
|
|
if (!param)
|
|
break; /* invalid parameter fmt, do not set mode. */
|
|
store->extparams[i] = strdup(param);
|
|
/* Get next parameter */
|
|
param = strtoken(&save, NULL, " ");
|
|
}
|
|
store->extmodes |= Channelmode_Table[i].mode;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if (parambuf)
|
|
free(parambuf);
|
|
}
|
|
|
|
void chmode_str(struct ChMode modes, char *mbuf, char *pbuf)
|
|
{
|
|
aCtab *tab;
|
|
int i;
|
|
*pbuf = 0;
|
|
*mbuf++ = '+';
|
|
for (tab = &cFlagTab[0]; tab->mode; tab++)
|
|
{
|
|
if (modes.mode & tab->mode)
|
|
{
|
|
if (!tab->parameters)
|
|
*mbuf++ = tab->flag;
|
|
}
|
|
}
|
|
#ifdef EXTCMODE
|
|
for (i=0; i <= Channelmode_highest; i++)
|
|
{
|
|
if (!(Channelmode_Table[i].flag))
|
|
continue;
|
|
|
|
if (modes.extmodes & Channelmode_Table[i].mode)
|
|
{
|
|
*mbuf++ = Channelmode_Table[i].flag;
|
|
if (Channelmode_Table[i].paracount)
|
|
{
|
|
strcat(pbuf, modes.extparams[i]);
|
|
strcat(pbuf, " ");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef NEWCHFLOODPROT
|
|
if (modes.floodprot.per)
|
|
{
|
|
*mbuf++ = 'f';
|
|
strcat(pbuf, channel_modef_string(&modes.floodprot));
|
|
}
|
|
#else
|
|
if (modes.per)
|
|
{
|
|
*mbuf++ = 'f';
|
|
if (modes.kmode)
|
|
strcat(pbuf, "*");
|
|
strcat(pbuf, my_itoa(modes.msgs));
|
|
strcat(pbuf, ":");
|
|
strcat(pbuf, my_itoa(modes.per));
|
|
}
|
|
#endif
|
|
*mbuf++=0;
|
|
}
|
|
|
|
int channellevel_to_int(char *s)
|
|
{
|
|
/* Requested at http://bugs.unrealircd.org/view.php?id=3852 */
|
|
if (!strcmp(s, "none"))
|
|
return CHFL_DEOPPED;
|
|
if (!strcmp(s, "voice"))
|
|
return CHFL_VOICE;
|
|
if (!strcmp(s, "halfop"))
|
|
return CHFL_HALFOP;
|
|
if (!strcmp(s, "op") || !strcmp(s, "chanop"))
|
|
return CHFL_CHANOP;
|
|
if (!strcmp(s, "protect") || !strcmp(s, "chanprot"))
|
|
#ifdef PREFIX_AQ
|
|
return CHFL_CHANPROT;
|
|
#else
|
|
return CHFL_CHANOP|CHFL_CHANPROT;
|
|
#endif
|
|
if (!strcmp(s, "owner") || !strcmp(s, "chanowner"))
|
|
#ifdef PREFIX_AQ
|
|
return CHFL_CHANOWNER;
|
|
#else
|
|
return CHFL_CHANOP|CHFL_CHANOWNER;
|
|
#endif
|
|
|
|
return 0; /* unknown or unsupported */
|
|
}
|
|
|
|
/* Channel flag (eg: CHFL_CHANOWNER) to SJOIN symbol (eg: *).
|
|
* WARNING: Do not confuse SJOIN symbols with prefixes in /NAMES!
|
|
*/
|
|
char *chfl_to_sjoin_symbol(int s)
|
|
{
|
|
switch(s)
|
|
{
|
|
case CHFL_VOICE:
|
|
return "+";
|
|
case CHFL_HALFOP:
|
|
return "%";
|
|
case CHFL_CHANOP:
|
|
return "@";
|
|
case CHFL_CHANPROT:
|
|
#ifdef PREFIX_AQ
|
|
return "~";
|
|
#else
|
|
return "~@";
|
|
#endif
|
|
case CHFL_CHANOWNER:
|
|
#ifdef PREFIX_AQ
|
|
return "*";
|
|
#else
|
|
return "*@";
|
|
#endif
|
|
case CHFL_DEOPPED:
|
|
default:
|
|
return "";
|
|
}
|
|
/* NOT REACHED */
|
|
}
|
|
|
|
char chfl_to_chanmode(int s)
|
|
{
|
|
switch(s)
|
|
{
|
|
case CHFL_VOICE:
|
|
return 'v';
|
|
case CHFL_HALFOP:
|
|
return 'h';
|
|
case CHFL_CHANOP:
|
|
return 'o';
|
|
case CHFL_CHANPROT:
|
|
return 'a';
|
|
case CHFL_CHANOWNER:
|
|
return 'q';
|
|
case CHFL_DEOPPED:
|
|
default:
|
|
return '\0';
|
|
}
|
|
/* NOT REACHED */
|
|
}
|
|
|
|
ConfigFile *config_load(char *filename)
|
|
{
|
|
struct stat sb;
|
|
int fd;
|
|
int ret;
|
|
char *buf = NULL;
|
|
ConfigFile *cfptr;
|
|
|
|
#ifndef _WIN32
|
|
fd = open(filename, O_RDONLY);
|
|
#else
|
|
fd = open(filename, O_RDONLY|O_BINARY);
|
|
#endif
|
|
if (fd == -1)
|
|
{
|
|
config_error("Couldn't open \"%s\": %s\n", filename, strerror(errno));
|
|
return NULL;
|
|
}
|
|
if (fstat(fd, &sb) == -1)
|
|
{
|
|
config_error("Couldn't fstat \"%s\": %s\n", filename, strerror(errno));
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
if (!sb.st_size)
|
|
{
|
|
/* Workaround for empty files */
|
|
cfptr = config_parse(filename, " ");
|
|
return cfptr;
|
|
}
|
|
buf = MyMalloc(sb.st_size+1);
|
|
if (buf == NULL)
|
|
{
|
|
config_error("Out of memory trying to load \"%s\"\n", filename);
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
ret = read(fd, buf, sb.st_size);
|
|
if (ret != sb.st_size)
|
|
{
|
|
config_error("Error reading \"%s\": %s\n", filename,
|
|
ret == -1 ? strerror(errno) : strerror(EFAULT));
|
|
free(buf);
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
/* Just me or could this cause memory corrupted when ret <0 ? */
|
|
buf[ret] = '\0';
|
|
close(fd);
|
|
add_entropy_configfile(sb, buf);
|
|
cfptr = config_parse(filename, buf);
|
|
free(buf);
|
|
return cfptr;
|
|
}
|
|
|
|
void config_free(ConfigFile *cfptr)
|
|
{
|
|
ConfigFile *nptr;
|
|
|
|
for(;cfptr;cfptr=nptr)
|
|
{
|
|
nptr = cfptr->cf_next;
|
|
if (cfptr->cf_entries)
|
|
config_entry_free(cfptr->cf_entries);
|
|
if (cfptr->cf_filename)
|
|
free(cfptr->cf_filename);
|
|
free(cfptr);
|
|
}
|
|
}
|
|
|
|
/* This is the internal parser, made by Chris Behrens & Fred Jacobs */
|
|
static ConfigFile *config_parse(char *filename, char *confdata)
|
|
{
|
|
char *ptr;
|
|
char *start;
|
|
int linenumber = 1;
|
|
ConfigEntry *curce;
|
|
ConfigEntry **lastce;
|
|
ConfigEntry *cursection;
|
|
|
|
ConfigFile *curcf;
|
|
ConfigFile *lastcf;
|
|
|
|
lastcf = curcf = MyMalloc(sizeof(ConfigFile));
|
|
memset(curcf, 0, sizeof(ConfigFile));
|
|
curcf->cf_filename = strdup(filename);
|
|
lastce = &(curcf->cf_entries);
|
|
curce = NULL;
|
|
cursection = NULL;
|
|
/* Replace \r's with spaces .. ugly ugly -Stskeeps */
|
|
for (ptr=confdata; *ptr; ptr++)
|
|
if (*ptr == '\r')
|
|
*ptr = ' ';
|
|
|
|
for(ptr=confdata;*ptr;ptr++)
|
|
{
|
|
switch(*ptr)
|
|
{
|
|
case ';':
|
|
if (!curce)
|
|
{
|
|
config_status("%s:%i Ignoring extra semicolon\n",
|
|
filename, linenumber);
|
|
break;
|
|
}
|
|
*lastce = curce;
|
|
lastce = &(curce->ce_next);
|
|
curce->ce_fileposend = (ptr - confdata);
|
|
curce = NULL;
|
|
break;
|
|
case '{':
|
|
if (!curce)
|
|
{
|
|
config_status("%s:%i: No name for section start\n",
|
|
filename, linenumber);
|
|
continue;
|
|
}
|
|
else if (curce->ce_entries)
|
|
{
|
|
config_status("%s:%i: Ignoring extra section start\n",
|
|
filename, linenumber);
|
|
continue;
|
|
}
|
|
curce->ce_sectlinenum = linenumber;
|
|
lastce = &(curce->ce_entries);
|
|
cursection = curce;
|
|
curce = NULL;
|
|
break;
|
|
case '}':
|
|
if (curce)
|
|
{
|
|
config_error("%s:%i: Missing semicolon before close brace\n",
|
|
filename, linenumber);
|
|
config_entry_free(curce);
|
|
config_free(curcf);
|
|
|
|
return NULL;
|
|
}
|
|
else if (!cursection)
|
|
{
|
|
config_status("%s:%i: Ignoring extra close brace\n",
|
|
filename, linenumber);
|
|
continue;
|
|
}
|
|
curce = cursection;
|
|
cursection->ce_fileposend = (ptr - confdata);
|
|
cursection = cursection->ce_prevlevel;
|
|
if (!cursection)
|
|
lastce = &(curcf->cf_entries);
|
|
else
|
|
lastce = &(cursection->ce_entries);
|
|
for(;*lastce;lastce = &((*lastce)->ce_next))
|
|
continue;
|
|
break;
|
|
case '#':
|
|
ptr++;
|
|
while(*ptr && (*ptr != '\n'))
|
|
ptr++;
|
|
if (!*ptr)
|
|
break;
|
|
ptr--;
|
|
continue;
|
|
case '/':
|
|
if (*(ptr+1) == '/')
|
|
{
|
|
ptr += 2;
|
|
while(*ptr && (*ptr != '\n'))
|
|
ptr++;
|
|
if (!*ptr)
|
|
break;
|
|
ptr--; /* grab the \n on next loop thru */
|
|
continue;
|
|
}
|
|
else if (*(ptr+1) == '*')
|
|
{
|
|
int commentstart = linenumber;
|
|
int commentlevel = 1;
|
|
|
|
for(ptr+=2;*ptr;ptr++)
|
|
{
|
|
if ((*ptr == '/') && (*(ptr+1) == '*'))
|
|
{
|
|
commentlevel++;
|
|
ptr++;
|
|
}
|
|
|
|
else if ((*ptr == '*') && (*(ptr+1) == '/'))
|
|
{
|
|
commentlevel--;
|
|
ptr++;
|
|
}
|
|
|
|
else if (*ptr == '\n')
|
|
linenumber++;
|
|
|
|
if (!commentlevel)
|
|
break;
|
|
}
|
|
if (!*ptr)
|
|
{
|
|
config_error("%s:%i Comment on this line does not end\n",
|
|
filename, commentstart);
|
|
config_entry_free(curce);
|
|
config_free(curcf);
|
|
return NULL;
|
|
}
|
|
}
|
|
break;
|
|
case '\"':
|
|
if (curce && curce->ce_varlinenum != linenumber && cursection)
|
|
{
|
|
config_warn("%s:%i: Missing semicolon at end of line\n",
|
|
filename, curce->ce_varlinenum);
|
|
|
|
*lastce = curce;
|
|
lastce = &(curce->ce_next);
|
|
curce->ce_fileposend = (ptr - confdata);
|
|
curce = NULL;
|
|
}
|
|
|
|
start = ++ptr;
|
|
for(;*ptr;ptr++)
|
|
{
|
|
if ((*ptr == '\\'))
|
|
{
|
|
|
|
if (*(ptr+1) == '\\' || *(ptr+1) == '\"')
|
|
{
|
|
char *tptr = ptr;
|
|
while((*tptr = *(tptr+1)))
|
|
tptr++;
|
|
}
|
|
}
|
|
else if ((*ptr == '\"') || (*ptr == '\n'))
|
|
break;
|
|
}
|
|
if (!*ptr || (*ptr == '\n'))
|
|
{
|
|
config_error("%s:%i: Unterminated quote found\n",
|
|
filename, linenumber);
|
|
config_entry_free(curce);
|
|
config_free(curcf);
|
|
return NULL;
|
|
}
|
|
if (curce)
|
|
{
|
|
if (curce->ce_vardata)
|
|
{
|
|
config_status("%s:%i: Ignoring extra data\n",
|
|
filename, linenumber);
|
|
}
|
|
else
|
|
{
|
|
curce->ce_vardata = MyMalloc(ptr-start+1);
|
|
strncpy(curce->ce_vardata, start, ptr-start);
|
|
curce->ce_vardata[ptr-start] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curce = MyMalloc(sizeof(ConfigEntry));
|
|
memset(curce, 0, sizeof(ConfigEntry));
|
|
curce->ce_varname = MyMalloc((ptr-start)+1);
|
|
strncpy(curce->ce_varname, start, ptr-start);
|
|
curce->ce_varname[ptr-start] = '\0';
|
|
curce->ce_varlinenum = linenumber;
|
|
curce->ce_fileptr = curcf;
|
|
curce->ce_prevlevel = cursection;
|
|
curce->ce_fileposstart = (start - confdata);
|
|
}
|
|
break;
|
|
case '\n':
|
|
linenumber++;
|
|
/* fall through */
|
|
case '\t':
|
|
case ' ':
|
|
case '=':
|
|
case '\r':
|
|
break;
|
|
default:
|
|
if ((*ptr == '*') && (*(ptr+1) == '/'))
|
|
{
|
|
config_status("%s:%i Ignoring extra end comment\n",
|
|
filename, linenumber);
|
|
ptr++;
|
|
break;
|
|
}
|
|
start = ptr;
|
|
for(;*ptr;ptr++)
|
|
{
|
|
if ((*ptr == ' ') || (*ptr == '=') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == ';'))
|
|
break;
|
|
}
|
|
if (!*ptr)
|
|
{
|
|
if (curce)
|
|
config_error("%s: Unexpected EOF for variable starting at %i\n",
|
|
filename, curce->ce_varlinenum);
|
|
else if (cursection)
|
|
config_error("%s: Unexpected EOF for section starting at %i\n",
|
|
filename, cursection->ce_sectlinenum);
|
|
else
|
|
config_error("%s: Unexpected EOF.\n", filename);
|
|
config_entry_free(curce);
|
|
config_free(curcf);
|
|
return NULL;
|
|
}
|
|
if (curce)
|
|
{
|
|
if (curce->ce_vardata)
|
|
{
|
|
config_status("%s:%i: Ignoring extra data\n",
|
|
filename, linenumber);
|
|
}
|
|
else
|
|
{
|
|
curce->ce_vardata = MyMalloc(ptr-start+1);
|
|
strncpy(curce->ce_vardata, start, ptr-start);
|
|
curce->ce_vardata[ptr-start] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curce = MyMalloc(sizeof(ConfigEntry));
|
|
memset(curce, 0, sizeof(ConfigEntry));
|
|
curce->ce_varname = MyMalloc((ptr-start)+1);
|
|
strncpy(curce->ce_varname, start, ptr-start);
|
|
curce->ce_varname[ptr-start] = '\0';
|
|
curce->ce_varlinenum = linenumber;
|
|
curce->ce_fileptr = curcf;
|
|
curce->ce_prevlevel = cursection;
|
|
curce->ce_fileposstart = (start - confdata);
|
|
}
|
|
if ((*ptr == ';') || (*ptr == '\n'))
|
|
ptr--;
|
|
break;
|
|
} /* switch */
|
|
if (!*ptr) /* This IS possible. -- Syzop */
|
|
break;
|
|
} /* for */
|
|
if (curce)
|
|
{
|
|
config_error("%s: Unexpected EOF for variable starting on line %i\n",
|
|
filename, curce->ce_varlinenum);
|
|
config_entry_free(curce);
|
|
config_free(curcf);
|
|
return NULL;
|
|
}
|
|
else if (cursection)
|
|
{
|
|
config_error("%s: Unexpected EOF for section starting on line %i\n",
|
|
filename, cursection->ce_sectlinenum);
|
|
config_free(curcf);
|
|
return NULL;
|
|
}
|
|
return curcf;
|
|
}
|
|
|
|
static void config_entry_free(ConfigEntry *ceptr)
|
|
{
|
|
ConfigEntry *nptr;
|
|
|
|
for(;ceptr;ceptr=nptr)
|
|
{
|
|
nptr = ceptr->ce_next;
|
|
if (ceptr->ce_entries)
|
|
config_entry_free(ceptr->ce_entries);
|
|
if (ceptr->ce_varname)
|
|
free(ceptr->ce_varname);
|
|
if (ceptr->ce_vardata)
|
|
free(ceptr->ce_vardata);
|
|
free(ceptr);
|
|
}
|
|
}
|
|
|
|
ConfigEntry *config_find_entry(ConfigEntry *ce, char *name)
|
|
{
|
|
ConfigEntry *cep;
|
|
|
|
for (cep = ce; cep; cep = cep->ce_next)
|
|
if (cep->ce_varname && !strcmp(cep->ce_varname, name))
|
|
break;
|
|
return cep;
|
|
}
|
|
|
|
void config_error(char *format, ...)
|
|
{
|
|
va_list ap;
|
|
char buffer[1024];
|
|
char *ptr;
|
|
|
|
va_start(ap, format);
|
|
vsprintf(buffer, format, ap);
|
|
va_end(ap);
|
|
if ((ptr = strchr(buffer, '\n')) != NULL)
|
|
*ptr = '\0';
|
|
if (!loop.ircd_booted)
|
|
#ifndef _WIN32
|
|
fprintf(stderr, "[error] %s\n", buffer);
|
|
#else
|
|
win_log("[error] %s", buffer);
|
|
#endif
|
|
else
|
|
ircd_log(LOG_ERROR, "config error: %s", buffer);
|
|
sendto_realops("error: %s", buffer);
|
|
/* We cannot live with this */
|
|
config_error_flag = 1;
|
|
}
|
|
|
|
static void inline config_error_missing(const char *filename, int line, const char *entry)
|
|
{
|
|
config_error("%s:%d: %s is missing", filename, line, entry);
|
|
}
|
|
|
|
static void inline config_error_unknown(const char *filename, int line, const char *block,
|
|
const char *entry)
|
|
{
|
|
config_error("%s:%d: Unknown directive '%s::%s'", filename, line, block, entry);
|
|
}
|
|
|
|
static void inline config_error_unknownflag(const char *filename, int line, const char *block,
|
|
const char *entry)
|
|
{
|
|
config_error("%s:%d: Unknown %s flag '%s'", filename, line, block, entry);
|
|
}
|
|
|
|
static void inline config_error_unknownopt(const char *filename, int line, const char *block,
|
|
const char *entry)
|
|
{
|
|
config_error("%s:%d: Unknown %s option '%s'", filename, line, block, entry);
|
|
}
|
|
|
|
static void inline config_error_noname(const char *filename, int line, const char *block)
|
|
{
|
|
config_error("%s:%d: %s block has no name", filename, line, block);
|
|
}
|
|
|
|
static void inline config_error_blank(const char *filename, int line, const char *block)
|
|
{
|
|
config_error("%s:%d: Blank %s entry", filename, line, block);
|
|
}
|
|
|
|
static void inline config_error_empty(const char *filename, int line, const char *block,
|
|
const char *entry)
|
|
{
|
|
config_error("%s:%d: %s::%s specified without a value",
|
|
filename, line, block, entry);
|
|
}
|
|
|
|
/* Like above */
|
|
void config_status(char *format, ...)
|
|
{
|
|
va_list ap;
|
|
char buffer[1024];
|
|
char *ptr;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(buffer, 1023, format, ap);
|
|
va_end(ap);
|
|
if ((ptr = strchr(buffer, '\n')) != NULL)
|
|
*ptr = '\0';
|
|
if (!loop.ircd_booted)
|
|
#ifndef _WIN32
|
|
fprintf(stderr, "* %s\n", buffer);
|
|
#else
|
|
win_log("* %s", buffer);
|
|
#endif
|
|
sendto_realops("%s", buffer);
|
|
}
|
|
|
|
void config_warn(char *format, ...)
|
|
{
|
|
va_list ap;
|
|
char buffer[1024];
|
|
char *ptr;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(buffer, 1023, format, ap);
|
|
va_end(ap);
|
|
if ((ptr = strchr(buffer, '\n')) != NULL)
|
|
*ptr = '\0';
|
|
if (!loop.ircd_booted)
|
|
#ifndef _WIN32
|
|
fprintf(stderr, "[warning] %s\n", buffer);
|
|
#else
|
|
win_log("[warning] %s", buffer);
|
|
#endif
|
|
sendto_realops("[warning] %s", buffer);
|
|
}
|
|
|
|
static void inline config_warn_duplicate(const char *filename, int line, const char *entry)
|
|
{
|
|
config_warn("%s:%d: Duplicate %s directive", filename, line, entry);
|
|
}
|
|
|
|
/* returns 1 if the test fails */
|
|
int config_test_openfile(ConfigEntry *cep, int flags, mode_t mode, const char *entry, int fatal)
|
|
{
|
|
int fd;
|
|
|
|
if(!cep->ce_vardata)
|
|
{
|
|
if(fatal)
|
|
config_error("%s:%i: %s: <no file specified>: no file specified",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
entry);
|
|
else
|
|
|
|
config_warn("%s:%i: %s: <no file specified>: no file specified",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
entry);
|
|
return 1;
|
|
}
|
|
/*
|
|
* Make sure that files are created with the correct mode. This is
|
|
* because we don't feel like unlink()ing them...which would require
|
|
* stat()ing them to make sure that we don't delete existing ones
|
|
* and that we deal with all of the bugs that come with complexity.
|
|
* The only files we may be creating are the tunefile and pidfile so far.
|
|
*/
|
|
if(flags & O_CREAT)
|
|
fd = open(cep->ce_vardata, flags, mode);
|
|
else
|
|
fd = open(cep->ce_vardata, flags);
|
|
if(fd == -1)
|
|
{
|
|
if(fatal)
|
|
config_error("%s:%i: %s: %s: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
entry,
|
|
cep->ce_vardata,
|
|
strerror(errno));
|
|
else
|
|
config_warn("%s:%i: %s: %s: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
entry,
|
|
cep->ce_vardata,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
void config_progress(char *format, ...)
|
|
{
|
|
va_list ap;
|
|
char buffer[1024];
|
|
char *ptr;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(buffer, 1023, format, ap);
|
|
va_end(ap);
|
|
if ((ptr = strchr(buffer, '\n')) != NULL)
|
|
*ptr = '\0';
|
|
if (!loop.ircd_booted)
|
|
#ifndef _WIN32
|
|
fprintf(stderr, "* %s\n", buffer);
|
|
#else
|
|
win_log("* %s", buffer);
|
|
#endif
|
|
sendto_realops("%s", buffer);
|
|
}
|
|
|
|
static int inline config_is_blankorempty(ConfigEntry *cep, const char *block)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block);
|
|
return 1;
|
|
}
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block,
|
|
cep->ce_varname);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ConfigCommand *config_binary_search(char *cmd) {
|
|
int start = 0;
|
|
int stop = ARRAY_SIZEOF(_ConfigCommands)-1;
|
|
int mid;
|
|
while (start <= stop) {
|
|
mid = (start+stop)/2;
|
|
if (smycmp(cmd,_ConfigCommands[mid].name) < 0) {
|
|
stop = mid-1;
|
|
}
|
|
else if (strcmp(cmd,_ConfigCommands[mid].name) == 0) {
|
|
return &_ConfigCommands[mid];
|
|
}
|
|
else
|
|
start = mid+1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void free_iConf(aConfiguration *i)
|
|
{
|
|
ircfree(i->name_server);
|
|
ircfree(i->kline_address);
|
|
ircfree(i->gline_address);
|
|
ircfree(i->auto_join_chans);
|
|
ircfree(i->oper_auto_join_chans);
|
|
ircfree(i->oper_only_stats);
|
|
ircfree(i->channel_command_prefix);
|
|
ircfree(i->oper_snomask);
|
|
ircfree(i->user_snomask);
|
|
ircfree(i->egd_path);
|
|
ircfree(i->static_quit);
|
|
#ifdef USE_SSL
|
|
ircfree(i->x_server_cert_pem);
|
|
ircfree(i->x_server_key_pem);
|
|
ircfree(i->x_server_cipher_list);
|
|
ircfree(i->trusted_ca_file);
|
|
#endif
|
|
ircfree(i->restrict_usermodes);
|
|
ircfree(i->restrict_channelmodes);
|
|
ircfree(i->restrict_extendedbans);
|
|
ircfree(i->network.x_ircnetwork);
|
|
ircfree(i->network.x_ircnet005);
|
|
ircfree(i->network.x_defserv);
|
|
ircfree(i->network.x_services_name);
|
|
ircfree(i->network.x_oper_host);
|
|
ircfree(i->network.x_admin_host);
|
|
ircfree(i->network.x_locop_host);
|
|
ircfree(i->network.x_sadmin_host);
|
|
ircfree(i->network.x_netadmin_host);
|
|
ircfree(i->network.x_coadmin_host);
|
|
ircfree(i->network.x_hidden_host);
|
|
ircfree(i->network.x_prefix_quit);
|
|
ircfree(i->network.x_helpchan);
|
|
ircfree(i->network.x_stats_server);
|
|
ircfree(i->spamfilter_ban_reason);
|
|
ircfree(i->spamfilter_virus_help_channel);
|
|
ircfree(i->spamexcept_line);
|
|
}
|
|
|
|
int config_test();
|
|
|
|
void config_setdefaultsettings(aConfiguration *i)
|
|
{
|
|
i->unknown_flood_amount = 4;
|
|
i->unknown_flood_bantime = 600;
|
|
i->oper_snomask = strdup(SNO_DEFOPER);
|
|
i->ident_read_timeout = 30;
|
|
i->ident_connect_timeout = 10;
|
|
i->nick_count = 3; i->nick_period = 60; /* nickflood protection: max 3 per 60s */
|
|
#ifdef NO_FLOOD_AWAY
|
|
i->away_count = 4; i->away_period = 120; /* awayflood protection: max 4 per 120s */
|
|
#endif
|
|
#ifdef NEWCHFLOODPROT
|
|
i->modef_default_unsettime = 0;
|
|
i->modef_max_unsettime = 60; /* 1 hour seems enough :p */
|
|
#endif
|
|
i->ban_version_tkl_time = 86400; /* 1d */
|
|
i->spamfilter_ban_time = 86400; /* 1d */
|
|
i->spamfilter_ban_reason = strdup("Spam/advertising");
|
|
i->spamfilter_virus_help_channel = strdup("#help");
|
|
i->spamfilter_detectslow_warn = 250;
|
|
i->spamfilter_detectslow_fatal = 500;
|
|
i->maxdccallow = 10;
|
|
i->channel_command_prefix = strdup("`!.");
|
|
i->check_target_nick_bans = 1;
|
|
i->maxbans = 60;
|
|
i->maxbanlength = 2048;
|
|
i->timesynch_enabled = 1;
|
|
i->timesynch_timeout = 3;
|
|
i->timesynch_server = strdup("193.67.79.202,192.43.244.18,128.250.36.3"); /* nlnet (EU), NIST (US), uni melbourne (AU). All open acces, nonotify, nodns. */
|
|
i->name_server = strdup("127.0.0.1"); /* default, especially needed for w2003+ in some rare cases */
|
|
i->level_on_join = CHFL_CHANOP;
|
|
i->watch_away_notification = 1;
|
|
i->new_linking_protocol = 1;
|
|
}
|
|
|
|
/* 1: needed for set::options::allow-part-if-shunned,
|
|
* we can't just make it M_SHUN and do a ALLOW_PART_IF_SHUNNED in
|
|
* m_part itself because that will also block internal calls (like sapart). -- Syzop
|
|
* 2: now also used by spamfilter entries added by config...
|
|
* we got a chicken-and-egg problem here.. antries added without reason or ban-time
|
|
* field should use the config default (set::spamfilter::ban-reason/ban-time) but
|
|
* this isn't (or might not) be known yet when parsing spamfilter entries..
|
|
* so we do a VERY UGLY mass replace here.. unless someone else has a better idea.
|
|
*/
|
|
static void do_weird_shun_stuff()
|
|
{
|
|
aCommand *cmptr;
|
|
aTKline *tk;
|
|
char *encoded;
|
|
|
|
if ((cmptr = find_Command_simple("PART")))
|
|
{
|
|
if (ALLOW_PART_IF_SHUNNED)
|
|
cmptr->flags |= M_SHUN;
|
|
else
|
|
cmptr->flags &= ~M_SHUN;
|
|
}
|
|
|
|
encoded = unreal_encodespace(SPAMFILTER_BAN_REASON);
|
|
if (!encoded)
|
|
abort(); /* hack to trace 'impossible' bug... */
|
|
for (tk = tklines[tkl_hash('q')]; tk; tk = tk->next)
|
|
{
|
|
if (tk->type != TKL_NICK)
|
|
continue;
|
|
if (!tk->setby)
|
|
{
|
|
if (me.name[0] != '\0')
|
|
tk->setby = strdup(me.name);
|
|
else
|
|
tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
|
|
}
|
|
}
|
|
|
|
for (tk = tklines[tkl_hash('f')]; tk; tk = tk->next)
|
|
{
|
|
if (tk->type != TKL_SPAMF)
|
|
continue; /* global entry or something else.. */
|
|
if (!strcmp(tk->ptr.spamf->tkl_reason, "<internally added by ircd>"))
|
|
{
|
|
MyFree(tk->ptr.spamf->tkl_reason);
|
|
tk->ptr.spamf->tkl_reason = strdup(encoded);
|
|
tk->ptr.spamf->tkl_duration = SPAMFILTER_BAN_TIME;
|
|
}
|
|
/* This one is even more ugly, but our config crap is VERY confusing :[ */
|
|
if (!tk->setby)
|
|
{
|
|
if (me.name[0] != '\0')
|
|
tk->setby = strdup(me.name);
|
|
else
|
|
tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
|
|
}
|
|
}
|
|
if (loop.ircd_booted) /* only has to be done for rehashes, api-isupport takes care of boot */
|
|
{
|
|
if (WATCH_AWAY_NOTIFICATION)
|
|
{
|
|
IsupportAdd(NULL, "WATCHOPTS", "A");
|
|
} else {
|
|
Isupport *hunted = IsupportFind("WATCHOPTS");
|
|
if (hunted)
|
|
IsupportDel(hunted);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void make_default_logblock(void)
|
|
{
|
|
ConfigItem_log *ca = MyMallocEx(sizeof(ConfigItem_log));
|
|
|
|
config_status("No log { } block found -- using default: errors will be logged to 'ircd.log'");
|
|
|
|
ca->file = strdup("ircd.log");
|
|
ca->flags |= LOG_ERROR;
|
|
AddListItem(ca, conf_log);
|
|
}
|
|
|
|
int isanyserverlinked(void)
|
|
{
|
|
int i;
|
|
aClient *acptr;
|
|
|
|
for (i = LastSlot; i >= 0; i--)
|
|
if ((acptr = local[i]) && (acptr != &me) && IsServer(acptr))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void applymeblock(void)
|
|
{
|
|
if (!conf_me || !me.serv)
|
|
return; /* uh-huh? */
|
|
|
|
/* Numeric change? */
|
|
if (conf_me->numeric != me.serv->numeric)
|
|
{
|
|
/* Can we apply ? */
|
|
if (!isanyserverlinked())
|
|
{
|
|
me.serv->numeric = conf_me->numeric;
|
|
} else {
|
|
config_warn("me::numeric: Numeric change detected, but change cannot be applied "
|
|
"due to being linked to other servers. Unlink all servers and /REHASH to "
|
|
"try again.");
|
|
}
|
|
}
|
|
}
|
|
|
|
int init_conf(char *rootconf, int rehash)
|
|
{
|
|
char *old_pid_file = NULL;
|
|
|
|
config_status("Loading IRCd configuration ..");
|
|
if (conf)
|
|
{
|
|
config_error("%s:%i - Someone forgot to clean up", __FILE__, __LINE__);
|
|
return -1;
|
|
}
|
|
bzero(&tempiConf, sizeof(iConf));
|
|
bzero(&settings, sizeof(settings));
|
|
bzero(&requiredstuff, sizeof(requiredstuff));
|
|
config_setdefaultsettings(&tempiConf);
|
|
if (load_conf(rootconf) > 0)
|
|
{
|
|
charsys_reset_pretest();
|
|
if ((config_test() < 0) || (callbacks_check() < 0) || (efunctions_check() < 0) ||
|
|
(charsys_postconftest() < 0))
|
|
{
|
|
config_error("IRCd configuration failed to pass testing");
|
|
#ifdef _WIN32
|
|
if (!rehash)
|
|
win_error();
|
|
#endif
|
|
#ifndef STATIC_LINKING
|
|
Unload_all_testing_modules();
|
|
#endif
|
|
unload_notloaded_includes();
|
|
config_free(conf);
|
|
conf = NULL;
|
|
free_iConf(&tempiConf);
|
|
return -1;
|
|
}
|
|
callbacks_switchover();
|
|
efunctions_switchover();
|
|
if (rehash)
|
|
{
|
|
Hook *h;
|
|
old_pid_file = conf_files->pid_file;
|
|
unrealdns_delasyncconnects();
|
|
config_rehash();
|
|
#ifndef STATIC_LINKING
|
|
Unload_all_loaded_modules();
|
|
|
|
/* Notify permanent modules of the rehash */
|
|
for (h = Hooks[HOOKTYPE_REHASH]; h; h = h->next)
|
|
{
|
|
if (!h->owner)
|
|
continue;
|
|
if (!(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
(*(h->func.intfunc))();
|
|
}
|
|
#else
|
|
RunHook0(HOOKTYPE_REHASH);
|
|
#endif
|
|
unload_loaded_includes();
|
|
}
|
|
load_includes();
|
|
#ifndef STATIC_LINKING
|
|
Init_all_testing_modules();
|
|
#else
|
|
if (!rehash) {
|
|
ModuleInfo ModCoreInfo;
|
|
ModCoreInfo.size = sizeof(ModuleInfo);
|
|
ModCoreInfo.module_load = 0;
|
|
ModCoreInfo.handle = NULL;
|
|
l_commands_Init(&ModCoreInfo);
|
|
}
|
|
#endif
|
|
charsys_reset();
|
|
if (config_run() < 0)
|
|
{
|
|
config_error("Bad case of config errors. Server will now die. This really shouldn't happen");
|
|
#ifdef _WIN32
|
|
if (!rehash)
|
|
win_error();
|
|
#endif
|
|
abort();
|
|
}
|
|
charsys_finish();
|
|
applymeblock();
|
|
if(old_pid_file &&
|
|
strcmp(old_pid_file, conf_files->pid_file))
|
|
{
|
|
sendto_ops("pidfile is being rewritten to %s, please delete %s",
|
|
conf_files->pid_file,
|
|
old_pid_file);
|
|
ircfree(old_pid_file);
|
|
|
|
write_pidfile();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error("IRCd configuration failed to load");
|
|
#ifndef STATIC_LINKING
|
|
Unload_all_testing_modules();
|
|
#endif
|
|
unload_notloaded_includes();
|
|
config_free(conf);
|
|
conf = NULL;
|
|
free_iConf(&tempiConf);
|
|
#ifdef _WIN32
|
|
if (!rehash)
|
|
win_error();
|
|
#endif
|
|
return -1;
|
|
}
|
|
config_free(conf);
|
|
conf = NULL;
|
|
if (rehash)
|
|
{
|
|
#ifndef STATIC_LINKING
|
|
module_loadall(0);
|
|
#endif
|
|
RunHook0(HOOKTYPE_REHASH_COMPLETE);
|
|
}
|
|
do_weird_shun_stuff();
|
|
if (!conf_log)
|
|
make_default_logblock();
|
|
nextconnect = TStime() + 1; /* check for autoconnects */
|
|
config_status("Configuration loaded without any problems ..");
|
|
return 0;
|
|
}
|
|
|
|
int load_conf(char *filename)
|
|
{
|
|
ConfigFile *cfptr, *cfptr2, **cfptr3;
|
|
ConfigEntry *ce;
|
|
int ret;
|
|
|
|
if (config_verbose > 0)
|
|
config_status("Loading config file %s ..", filename);
|
|
if ((cfptr = config_load(filename)))
|
|
{
|
|
for (cfptr3 = &conf, cfptr2 = conf; cfptr2; cfptr2 = cfptr2->cf_next)
|
|
cfptr3 = &cfptr2->cf_next;
|
|
*cfptr3 = cfptr;
|
|
if (config_verbose > 1)
|
|
config_status("Loading modules in %s", filename);
|
|
for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
|
|
if (!strcmp(ce->ce_varname, "loadmodule"))
|
|
{
|
|
ret = _conf_loadmodule(cfptr, ce);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
if (config_verbose > 1)
|
|
config_status("Searching through %s for include files..", filename);
|
|
for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
|
|
if (!strcmp(ce->ce_varname, "include"))
|
|
{
|
|
ret = _conf_include(cfptr, ce);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
config_error("Could not load config file %s", filename);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void config_rehash()
|
|
{
|
|
ConfigItem_oper *oper_ptr;
|
|
ConfigItem_class *class_ptr;
|
|
ConfigItem_ulines *uline_ptr;
|
|
ConfigItem_allow *allow_ptr;
|
|
ConfigItem_except *except_ptr;
|
|
ConfigItem_ban *ban_ptr;
|
|
ConfigItem_link *link_ptr;
|
|
ConfigItem_cgiirc *cgiirc_ptr;
|
|
ConfigItem_listen *listen_ptr;
|
|
ConfigItem_tld *tld_ptr;
|
|
ConfigItem_vhost *vhost_ptr;
|
|
ConfigItem_badword *badword_ptr;
|
|
ConfigItem_deny_dcc *deny_dcc_ptr;
|
|
ConfigItem_allow_dcc *allow_dcc_ptr;
|
|
ConfigItem_deny_link *deny_link_ptr;
|
|
ConfigItem_deny_channel *deny_channel_ptr;
|
|
ConfigItem_allow_channel *allow_channel_ptr;
|
|
ConfigItem_admin *admin_ptr;
|
|
ConfigItem_deny_version *deny_version_ptr;
|
|
ConfigItem_log *log_ptr;
|
|
ConfigItem_alias *alias_ptr;
|
|
ConfigItem_help *help_ptr;
|
|
ConfigItem_offchans *of_ptr;
|
|
OperStat *os_ptr;
|
|
ListStruct *next, *next2;
|
|
aTKline *tk, *tk_next;
|
|
SpamExcept *spamex_ptr;
|
|
int i;
|
|
|
|
USE_BAN_VERSION = 0;
|
|
/* clean out stuff that we don't use */
|
|
for (admin_ptr = conf_admin; admin_ptr; admin_ptr = (ConfigItem_admin *)next)
|
|
{
|
|
next = (ListStruct *)admin_ptr->next;
|
|
ircfree(admin_ptr->line);
|
|
DelListItem(admin_ptr, conf_admin);
|
|
MyFree(admin_ptr);
|
|
}
|
|
/* wipe the fckers out ..*/
|
|
for (oper_ptr = conf_oper; oper_ptr; oper_ptr = (ConfigItem_oper *)next)
|
|
{
|
|
ConfigItem_oper_from *oper_from;
|
|
next = (ListStruct *)oper_ptr->next;
|
|
ircfree(oper_ptr->name);
|
|
ircfree(oper_ptr->swhois);
|
|
ircfree(oper_ptr->snomask);
|
|
Auth_DeleteAuthStruct(oper_ptr->auth);
|
|
for (oper_from = (ConfigItem_oper_from *) oper_ptr->from; oper_from; oper_from = (ConfigItem_oper_from *) next2)
|
|
{
|
|
next2 = (ListStruct *)oper_from->next;
|
|
ircfree(oper_from->name);
|
|
if (oper_from->netmask)
|
|
{
|
|
MyFree(oper_from->netmask);
|
|
}
|
|
DelListItem(oper_from, oper_ptr->from);
|
|
MyFree(oper_from);
|
|
}
|
|
DelListItem(oper_ptr, conf_oper);
|
|
MyFree(oper_ptr);
|
|
}
|
|
for (link_ptr = conf_link; link_ptr; link_ptr = (ConfigItem_link *) next)
|
|
{
|
|
next = (ListStruct *)link_ptr->next;
|
|
if (link_ptr->refcount == 0)
|
|
{
|
|
Debug((DEBUG_ERROR, "s_conf: deleting block %s (refcount 0)", link_ptr->servername));
|
|
delete_linkblock(link_ptr);
|
|
}
|
|
else
|
|
{
|
|
Debug((DEBUG_ERROR, "s_conf: marking block %s (refcount %d) as temporary",
|
|
link_ptr->servername, link_ptr->refcount));
|
|
link_ptr->flag.temporary = 1;
|
|
}
|
|
}
|
|
for (class_ptr = conf_class; class_ptr; class_ptr = (ConfigItem_class *) next)
|
|
{
|
|
next = (ListStruct *)class_ptr->next;
|
|
if (class_ptr->flag.permanent == 1)
|
|
continue;
|
|
class_ptr->flag.temporary = 1;
|
|
/* We'll wipe it out when it has no clients */
|
|
if (!class_ptr->clients && !class_ptr->xrefcount)
|
|
{
|
|
delete_classblock(class_ptr);
|
|
}
|
|
}
|
|
for (uline_ptr = conf_ulines; uline_ptr; uline_ptr = (ConfigItem_ulines *) next)
|
|
{
|
|
next = (ListStruct *)uline_ptr->next;
|
|
/* We'll wipe it out when it has no clients */
|
|
ircfree(uline_ptr->servername);
|
|
DelListItem(uline_ptr, conf_ulines);
|
|
MyFree(uline_ptr);
|
|
}
|
|
for (allow_ptr = conf_allow; allow_ptr; allow_ptr = (ConfigItem_allow *) next)
|
|
{
|
|
next = (ListStruct *)allow_ptr->next;
|
|
ircfree(allow_ptr->ip);
|
|
ircfree(allow_ptr->hostname);
|
|
if (allow_ptr->netmask)
|
|
MyFree(allow_ptr->netmask);
|
|
Auth_DeleteAuthStruct(allow_ptr->auth);
|
|
DelListItem(allow_ptr, conf_allow);
|
|
MyFree(allow_ptr);
|
|
}
|
|
for (except_ptr = conf_except; except_ptr; except_ptr = (ConfigItem_except *) next)
|
|
{
|
|
next = (ListStruct *)except_ptr->next;
|
|
ircfree(except_ptr->mask);
|
|
if (except_ptr->netmask)
|
|
MyFree(except_ptr->netmask);
|
|
DelListItem(except_ptr, conf_except);
|
|
MyFree(except_ptr);
|
|
}
|
|
for (ban_ptr = conf_ban; ban_ptr; ban_ptr = (ConfigItem_ban *) next)
|
|
{
|
|
next = (ListStruct *)ban_ptr->next;
|
|
if (ban_ptr->flag.type2 == CONF_BAN_TYPE_CONF || ban_ptr->flag.type2 == CONF_BAN_TYPE_TEMPORARY)
|
|
{
|
|
ircfree(ban_ptr->mask);
|
|
ircfree(ban_ptr->reason);
|
|
if (ban_ptr->netmask)
|
|
MyFree(ban_ptr->netmask);
|
|
DelListItem(ban_ptr, conf_ban);
|
|
MyFree(ban_ptr);
|
|
}
|
|
}
|
|
for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)listen_ptr->next)
|
|
{
|
|
listen_ptr->flag.temporary = 1;
|
|
}
|
|
for (tld_ptr = conf_tld; tld_ptr; tld_ptr = (ConfigItem_tld *) next)
|
|
{
|
|
aMotd *motd;
|
|
next = (ListStruct *)tld_ptr->next;
|
|
ircfree(tld_ptr->motd_file);
|
|
ircfree(tld_ptr->rules_file);
|
|
ircfree(tld_ptr->smotd_file);
|
|
ircfree(tld_ptr->opermotd_file);
|
|
ircfree(tld_ptr->botmotd_file);
|
|
if (!tld_ptr->flag.motdptr) {
|
|
while (tld_ptr->motd) {
|
|
motd = tld_ptr->motd->next;
|
|
ircfree(tld_ptr->motd->line);
|
|
ircfree(tld_ptr->motd);
|
|
tld_ptr->motd = motd;
|
|
}
|
|
}
|
|
if (!tld_ptr->flag.rulesptr) {
|
|
while (tld_ptr->rules) {
|
|
motd = tld_ptr->rules->next;
|
|
ircfree(tld_ptr->rules->line);
|
|
ircfree(tld_ptr->rules);
|
|
tld_ptr->rules = motd;
|
|
}
|
|
}
|
|
while (tld_ptr->smotd) {
|
|
motd = tld_ptr->smotd->next;
|
|
ircfree(tld_ptr->smotd->line);
|
|
ircfree(tld_ptr->smotd);
|
|
tld_ptr->smotd = motd;
|
|
}
|
|
while (tld_ptr->opermotd) {
|
|
motd = tld_ptr->opermotd->next;
|
|
ircfree(tld_ptr->opermotd->line);
|
|
ircfree(tld_ptr->opermotd);
|
|
tld_ptr->opermotd = motd;
|
|
}
|
|
while (tld_ptr->botmotd) {
|
|
motd = tld_ptr->botmotd->next;
|
|
ircfree(tld_ptr->botmotd->line);
|
|
ircfree(tld_ptr->botmotd);
|
|
tld_ptr->botmotd = motd;
|
|
}
|
|
DelListItem(tld_ptr, conf_tld);
|
|
MyFree(tld_ptr);
|
|
}
|
|
for (vhost_ptr = conf_vhost; vhost_ptr; vhost_ptr = (ConfigItem_vhost *) next)
|
|
{
|
|
ConfigItem_oper_from *vhost_from;
|
|
|
|
next = (ListStruct *)vhost_ptr->next;
|
|
|
|
ircfree(vhost_ptr->login);
|
|
Auth_DeleteAuthStruct(vhost_ptr->auth);
|
|
ircfree(vhost_ptr->virthost);
|
|
ircfree(vhost_ptr->virtuser);
|
|
for (vhost_from = (ConfigItem_oper_from *) vhost_ptr->from; vhost_from;
|
|
vhost_from = (ConfigItem_oper_from *) next2)
|
|
{
|
|
next2 = (ListStruct *)vhost_from->next;
|
|
ircfree(vhost_from->name);
|
|
DelListItem(vhost_from, vhost_ptr->from);
|
|
MyFree(vhost_from);
|
|
}
|
|
DelListItem(vhost_ptr, conf_vhost);
|
|
MyFree(vhost_ptr);
|
|
}
|
|
|
|
#ifdef STRIPBADWORDS
|
|
for (badword_ptr = conf_badword_channel; badword_ptr;
|
|
badword_ptr = (ConfigItem_badword *) next) {
|
|
next = (ListStruct *)badword_ptr->next;
|
|
ircfree(badword_ptr->word);
|
|
if (badword_ptr->replace)
|
|
ircfree(badword_ptr->replace);
|
|
regfree(&badword_ptr->expr);
|
|
DelListItem(badword_ptr, conf_badword_channel);
|
|
MyFree(badword_ptr);
|
|
}
|
|
for (badword_ptr = conf_badword_message; badword_ptr;
|
|
badword_ptr = (ConfigItem_badword *) next) {
|
|
next = (ListStruct *)badword_ptr->next;
|
|
ircfree(badword_ptr->word);
|
|
if (badword_ptr->replace)
|
|
ircfree(badword_ptr->replace);
|
|
regfree(&badword_ptr->expr);
|
|
DelListItem(badword_ptr, conf_badword_message);
|
|
MyFree(badword_ptr);
|
|
}
|
|
for (badword_ptr = conf_badword_quit; badword_ptr;
|
|
badword_ptr = (ConfigItem_badword *) next) {
|
|
next = (ListStruct *)badword_ptr->next;
|
|
ircfree(badword_ptr->word);
|
|
if (badword_ptr->replace)
|
|
ircfree(badword_ptr->replace);
|
|
regfree(&badword_ptr->expr);
|
|
DelListItem(badword_ptr, conf_badword_quit);
|
|
MyFree(badword_ptr);
|
|
}
|
|
#endif
|
|
/* Clean up local spamfilter entries... */
|
|
for (tk = tklines[tkl_hash('f')]; tk; tk = tk_next)
|
|
{
|
|
if (tk->type == TKL_SPAMF)
|
|
tk_next = tkl_del_line(tk);
|
|
else /* global spamfilter.. don't touch! */
|
|
tk_next = tk->next;
|
|
}
|
|
|
|
for (tk = tklines[tkl_hash('q')]; tk; tk = tk_next)
|
|
{
|
|
if (tk->type == TKL_NICK)
|
|
tk_next = tkl_del_line(tk);
|
|
else
|
|
tk_next = tk->next;
|
|
}
|
|
|
|
for (deny_dcc_ptr = conf_deny_dcc; deny_dcc_ptr; deny_dcc_ptr = (ConfigItem_deny_dcc *)next)
|
|
{
|
|
next = (ListStruct *)deny_dcc_ptr->next;
|
|
if (deny_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
|
|
{
|
|
ircfree(deny_dcc_ptr->filename);
|
|
ircfree(deny_dcc_ptr->reason);
|
|
DelListItem(deny_dcc_ptr, conf_deny_dcc);
|
|
MyFree(deny_dcc_ptr);
|
|
}
|
|
}
|
|
for (deny_link_ptr = conf_deny_link; deny_link_ptr; deny_link_ptr = (ConfigItem_deny_link *) next) {
|
|
next = (ListStruct *)deny_link_ptr->next;
|
|
ircfree(deny_link_ptr->prettyrule);
|
|
ircfree(deny_link_ptr->mask);
|
|
crule_free(&deny_link_ptr->rule);
|
|
DelListItem(deny_link_ptr, conf_deny_link);
|
|
MyFree(deny_link_ptr);
|
|
}
|
|
for (deny_version_ptr = conf_deny_version; deny_version_ptr; deny_version_ptr = (ConfigItem_deny_version *) next) {
|
|
next = (ListStruct *)deny_version_ptr->next;
|
|
ircfree(deny_version_ptr->mask);
|
|
ircfree(deny_version_ptr->version);
|
|
ircfree(deny_version_ptr->flags);
|
|
DelListItem(deny_version_ptr, conf_deny_version);
|
|
MyFree(deny_version_ptr);
|
|
}
|
|
for (deny_channel_ptr = conf_deny_channel; deny_channel_ptr; deny_channel_ptr = (ConfigItem_deny_channel *) next)
|
|
{
|
|
next = (ListStruct *)deny_channel_ptr->next;
|
|
ircfree(deny_channel_ptr->redirect);
|
|
ircfree(deny_channel_ptr->channel);
|
|
ircfree(deny_channel_ptr->reason);
|
|
DelListItem(deny_channel_ptr, conf_deny_channel);
|
|
MyFree(deny_channel_ptr);
|
|
}
|
|
|
|
for (allow_channel_ptr = conf_allow_channel; allow_channel_ptr; allow_channel_ptr = (ConfigItem_allow_channel *) next)
|
|
{
|
|
next = (ListStruct *)allow_channel_ptr->next;
|
|
ircfree(allow_channel_ptr->channel);
|
|
DelListItem(allow_channel_ptr, conf_allow_channel);
|
|
MyFree(allow_channel_ptr);
|
|
}
|
|
for (allow_dcc_ptr = conf_allow_dcc; allow_dcc_ptr; allow_dcc_ptr = (ConfigItem_allow_dcc *)next)
|
|
{
|
|
next = (ListStruct *)allow_dcc_ptr->next;
|
|
if (allow_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
|
|
{
|
|
ircfree(allow_dcc_ptr->filename);
|
|
DelListItem(allow_dcc_ptr, conf_allow_dcc);
|
|
MyFree(allow_dcc_ptr);
|
|
}
|
|
}
|
|
|
|
if (conf_drpass)
|
|
{
|
|
Auth_DeleteAuthStruct(conf_drpass->restartauth);
|
|
conf_drpass->restartauth = NULL;
|
|
Auth_DeleteAuthStruct(conf_drpass->dieauth);
|
|
conf_drpass->dieauth = NULL;
|
|
ircfree(conf_drpass);
|
|
}
|
|
for (log_ptr = conf_log; log_ptr; log_ptr = (ConfigItem_log *)next) {
|
|
next = (ListStruct *)log_ptr->next;
|
|
ircfree(log_ptr->file);
|
|
DelListItem(log_ptr, conf_log);
|
|
MyFree(log_ptr);
|
|
}
|
|
for (alias_ptr = conf_alias; alias_ptr; alias_ptr = (ConfigItem_alias *)next) {
|
|
aCommand *cmptr = find_Command(alias_ptr->alias, 0, 0);
|
|
ConfigItem_alias_format *fmt;
|
|
next = (ListStruct *)alias_ptr->next;
|
|
ircfree(alias_ptr->nick);
|
|
del_Command(alias_ptr->alias, NULL, cmptr->func);
|
|
ircfree(alias_ptr->alias);
|
|
if (alias_ptr->format && (alias_ptr->type == ALIAS_COMMAND)) {
|
|
for (fmt = (ConfigItem_alias_format *) alias_ptr->format; fmt; fmt = (ConfigItem_alias_format *) next2)
|
|
{
|
|
next2 = (ListStruct *)fmt->next;
|
|
ircfree(fmt->format);
|
|
ircfree(fmt->nick);
|
|
ircfree(fmt->parameters);
|
|
regfree(&fmt->expr);
|
|
DelListItem(fmt, alias_ptr->format);
|
|
MyFree(fmt);
|
|
}
|
|
}
|
|
DelListItem(alias_ptr, conf_alias);
|
|
MyFree(alias_ptr);
|
|
}
|
|
for (help_ptr = conf_help; help_ptr; help_ptr = (ConfigItem_help *)next) {
|
|
aMotd *text;
|
|
next = (ListStruct *)help_ptr->next;
|
|
ircfree(help_ptr->command);
|
|
while (help_ptr->text) {
|
|
text = help_ptr->text->next;
|
|
ircfree(help_ptr->text->line);
|
|
ircfree(help_ptr->text);
|
|
help_ptr->text = text;
|
|
}
|
|
DelListItem(help_ptr, conf_help);
|
|
MyFree(help_ptr);
|
|
}
|
|
for (os_ptr = iConf.oper_only_stats_ext; os_ptr; os_ptr = (OperStat *)next)
|
|
{
|
|
next = (ListStruct *)os_ptr->next;
|
|
ircfree(os_ptr->flag);
|
|
MyFree(os_ptr);
|
|
}
|
|
iConf.oper_only_stats_ext = NULL;
|
|
for (spamex_ptr = iConf.spamexcept; spamex_ptr; spamex_ptr = (SpamExcept *)next)
|
|
{
|
|
next = (ListStruct *)spamex_ptr->next;
|
|
MyFree(spamex_ptr);
|
|
}
|
|
iConf.spamexcept = NULL;
|
|
for (of_ptr = conf_offchans; of_ptr; of_ptr = (ConfigItem_offchans *)next)
|
|
{
|
|
next = (ListStruct *)of_ptr->next;
|
|
ircfree(of_ptr->topic);
|
|
MyFree(of_ptr);
|
|
}
|
|
conf_offchans = NULL;
|
|
|
|
#ifdef EXTCMODE
|
|
for (i = 0; i < EXTCMODETABLESZ; i++)
|
|
{
|
|
if (iConf.modes_on_join.extparams[i])
|
|
free(iConf.modes_on_join.extparams[i]);
|
|
}
|
|
#endif
|
|
|
|
for (cgiirc_ptr = conf_cgiirc; cgiirc_ptr; cgiirc_ptr = (ConfigItem_cgiirc *) next)
|
|
{
|
|
next = (ListStruct *)cgiirc_ptr->next;
|
|
delete_cgiircblock(cgiirc_ptr);
|
|
}
|
|
|
|
/*
|
|
reset conf_files -- should this be in its own function? no, because
|
|
it's only used here
|
|
*/
|
|
ircfree(conf_files->motd_file);
|
|
ircfree(conf_files->smotd_file);
|
|
ircfree(conf_files->opermotd_file);
|
|
ircfree(conf_files->svsmotd_file);
|
|
ircfree(conf_files->botmotd_file);
|
|
ircfree(conf_files->rules_file);
|
|
ircfree(conf_files->tune_file);
|
|
/*
|
|
Don't free conf_files->pid_file here; the old value is used to determine if
|
|
the pidfile location has changed and write_pidfile() needs to be called
|
|
again.
|
|
*/
|
|
ircfree(conf_files);
|
|
conf_files = NULL;
|
|
}
|
|
|
|
int config_post_test()
|
|
{
|
|
#define Error(x) { config_error((x)); errors++; }
|
|
int errors = 0;
|
|
Hook *h;
|
|
|
|
if (!requiredstuff.conf_me)
|
|
Error("me {} block is missing");
|
|
if (!requiredstuff.conf_admin)
|
|
Error("admin {} block is missing");
|
|
if (!requiredstuff.conf_listen)
|
|
Error("listen {} block is missing");
|
|
if (!settings.has_kline_address)
|
|
Error("set::kline-address is missing");
|
|
if (!settings.has_maxchannelsperuser)
|
|
Error("set::maxchannelsperuser is missing");
|
|
#if 0
|
|
if (!settings.has_dns_nameserver)
|
|
Error("set::dns::nameserver is missing");
|
|
if (!settings.has_dns_timeout)
|
|
Error("set::dns::timeout is missing");
|
|
if (!settings.has_dns_retries)
|
|
Error("set::dns::retries is missing");
|
|
#endif
|
|
if (!settings.has_services_server)
|
|
Error("set::services-server is missing");
|
|
if (!settings.has_default_server)
|
|
Error("set::default-server is missing");
|
|
if (!settings.has_network_name)
|
|
Error("set::network-name is missing");
|
|
if (!settings.has_hosts_global)
|
|
Error("set::hosts::global is missing");
|
|
if (!settings.has_hosts_admin)
|
|
Error("set::hosts::admin is missing");
|
|
if (!settings.has_hosts_servicesadmin)
|
|
Error("set::hosts::servicesadmin is missing");
|
|
if (!settings.has_hosts_netadmin)
|
|
Error("set::hosts::netadmin is missing");
|
|
if (!settings.has_hosts_coadmin)
|
|
Error("set::hosts::coadmin is missing");
|
|
if (!settings.has_help_channel)
|
|
Error("set::help-channel is missing");
|
|
if (!settings.has_hiddenhost_prefix)
|
|
Error("set::hiddenhost-prefix is missing");
|
|
|
|
for (h = Hooks[HOOKTYPE_CONFIGPOSTTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
|
|
!(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(&errs);
|
|
if (value == -1)
|
|
{
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
errors += errs;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int config_run()
|
|
{
|
|
ConfigEntry *ce;
|
|
ConfigFile *cfptr;
|
|
ConfigCommand *cc;
|
|
int errors = 0;
|
|
Hook *h;
|
|
for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
|
|
{
|
|
if (config_verbose > 1)
|
|
config_status("Running %s", cfptr->cf_filename);
|
|
for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
|
|
{
|
|
if ((cc = config_binary_search(ce->ce_varname))) {
|
|
if ((cc->conffunc) && (cc->conffunc(cfptr, ce) < 0))
|
|
errors++;
|
|
}
|
|
else
|
|
{
|
|
int value;
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
close_listeners();
|
|
listen_cleanup();
|
|
close_listeners();
|
|
loop.do_bancheck = 1;
|
|
free_iConf(&iConf);
|
|
bcopy(&tempiConf, &iConf, sizeof(aConfiguration));
|
|
bzero(&tempiConf, sizeof(aConfiguration));
|
|
#ifdef THROTTLING
|
|
{
|
|
EventInfo eInfo;
|
|
long v;
|
|
eInfo.flags = EMOD_EVERY;
|
|
if (!THROTTLING_PERIOD)
|
|
v = 120;
|
|
else
|
|
{
|
|
v = THROTTLING_PERIOD/2;
|
|
if (v > 5)
|
|
v = 5; /* accuracy, please */
|
|
}
|
|
eInfo.every = v;
|
|
EventMod(EventFind("bucketcleaning"), &eInfo);
|
|
}
|
|
#endif
|
|
|
|
/* initialize conf_files with defaults if the block isn't set: */
|
|
if(!conf_files)
|
|
_conf_files(NULL, NULL);
|
|
|
|
if (errors > 0)
|
|
{
|
|
config_error("%i fatal errors encountered", errors);
|
|
}
|
|
return (errors > 0 ? -1 : 1);
|
|
}
|
|
|
|
|
|
OperFlag *config_binary_flags_search(OperFlag *table, char *cmd, int size) {
|
|
int start = 0;
|
|
int stop = size-1;
|
|
int mid;
|
|
while (start <= stop) {
|
|
mid = (start+stop)/2;
|
|
|
|
if (smycmp(cmd,table[mid].name) < 0) {
|
|
stop = mid-1;
|
|
}
|
|
else if (strcmp(cmd,table[mid].name) == 0) {
|
|
return &(table[mid]);
|
|
}
|
|
else
|
|
start = mid+1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int config_test()
|
|
{
|
|
ConfigEntry *ce;
|
|
ConfigFile *cfptr;
|
|
ConfigCommand *cc;
|
|
int errors = 0;
|
|
Hook *h;
|
|
|
|
for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
|
|
{
|
|
if (config_verbose > 1)
|
|
config_status("Testing %s", cfptr->cf_filename);
|
|
for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
|
|
{
|
|
if (!ce->ce_varname)
|
|
{
|
|
config_error("%s:%i: %s:%i: null ce->ce_varname",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
__FILE__, __LINE__);
|
|
return -1;
|
|
}
|
|
if ((cc = config_binary_search(ce->ce_varname))) {
|
|
if (cc->testfunc)
|
|
errors += (cc->testfunc(cfptr, ce));
|
|
}
|
|
else
|
|
{
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
|
|
|
|
continue;
|
|
value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN,&errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
|
|
}
|
|
if (!used)
|
|
config_status("%s:%i: unknown directive %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_varname);
|
|
}
|
|
}
|
|
}
|
|
errors += config_post_test();
|
|
if (errors > 0)
|
|
{
|
|
config_error("%i errors encountered", errors);
|
|
}
|
|
return (errors > 0 ? -1 : 1);
|
|
}
|
|
|
|
/*
|
|
* Service functions
|
|
*/
|
|
|
|
ConfigItem_deny_dcc *Find_deny_dcc(char *name)
|
|
{
|
|
ConfigItem_deny_dcc *p;
|
|
|
|
if (!name)
|
|
return NULL;
|
|
|
|
for (p = conf_deny_dcc; p; p = (ConfigItem_deny_dcc *) p->next)
|
|
{
|
|
if (!match(name, p->filename))
|
|
return (p);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_alias *Find_alias(char *name) {
|
|
ConfigItem_alias *alias;
|
|
|
|
if (!name)
|
|
return NULL;
|
|
|
|
for (alias = conf_alias; alias; alias = (ConfigItem_alias *)alias->next) {
|
|
if (!stricmp(alias->alias, name))
|
|
return alias;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_class *Find_class(char *name)
|
|
{
|
|
ConfigItem_class *p;
|
|
|
|
if (!name)
|
|
return NULL;
|
|
|
|
for (p = conf_class; p; p = (ConfigItem_class *) p->next)
|
|
{
|
|
if (!strcmp(name, p->name))
|
|
return (p);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_oper *Find_oper(char *name)
|
|
{
|
|
ConfigItem_oper *p;
|
|
|
|
if (!name)
|
|
return NULL;
|
|
|
|
for (p = conf_oper; p; p = (ConfigItem_oper *) p->next)
|
|
{
|
|
if (!strcmp(name, p->name))
|
|
return (p);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int count_oper_sessions(char *name)
|
|
{
|
|
int i, count = 0;
|
|
aClient *cptr;
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
int j;
|
|
for (i = oper_fdlist.entry[j = 1]; j <= oper_fdlist.last_entry; i = oper_fdlist.entry[++j])
|
|
#endif
|
|
if ((cptr = local[i]) && IsPerson(cptr) && IsAnOper(cptr) &&
|
|
cptr->user && cptr->user->operlogin && !strcmp(cptr->user->operlogin,name))
|
|
count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
ConfigItem_listen *Find_listen(char *ipmask, int port)
|
|
{
|
|
ConfigItem_listen *p;
|
|
|
|
if (!ipmask)
|
|
return NULL;
|
|
|
|
for (p = conf_listen; p; p = (ConfigItem_listen *) p->next)
|
|
{
|
|
if (!match(p->ip, ipmask) && (port == p->port))
|
|
return (p);
|
|
if (!match(ipmask, p->ip) && (port == p->port))
|
|
return (p);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_ulines *Find_uline(char *host) {
|
|
ConfigItem_ulines *ulines;
|
|
|
|
if (!host)
|
|
return NULL;
|
|
|
|
for(ulines = conf_ulines; ulines; ulines =(ConfigItem_ulines *) ulines->next) {
|
|
if (!stricmp(host, ulines->servername))
|
|
return ulines;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ConfigItem_except *Find_except(aClient *sptr, char *host, short type) {
|
|
ConfigItem_except *excepts;
|
|
|
|
if (!host)
|
|
return NULL;
|
|
|
|
for(excepts = conf_except; excepts; excepts =(ConfigItem_except *) excepts->next) {
|
|
if (excepts->flag.type == type)
|
|
{
|
|
if (match_ip(sptr->ip, host, excepts->mask, excepts->netmask))
|
|
return excepts;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_tld *Find_tld(aClient *cptr, char *uhost) {
|
|
ConfigItem_tld *tld;
|
|
|
|
if (!uhost || !cptr)
|
|
return NULL;
|
|
|
|
for(tld = conf_tld; tld; tld = (ConfigItem_tld *) tld->next)
|
|
{
|
|
if (!match(tld->mask, uhost))
|
|
{
|
|
if ((tld->options & TLD_SSL) && !IsSecure(cptr))
|
|
continue;
|
|
if ((tld->options & TLD_REMOTE) && MyClient(cptr))
|
|
continue;
|
|
return tld;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
ConfigItem_link *Find_link(char *username,
|
|
char *hostname,
|
|
char *ip,
|
|
char *servername)
|
|
{
|
|
ConfigItem_link *link;
|
|
|
|
if (!username || !hostname || !servername || !ip)
|
|
return NULL;
|
|
|
|
for(link = conf_link; link; link = (ConfigItem_link *) link->next)
|
|
{
|
|
if (!match(link->servername, servername) &&
|
|
!match(link->username, username) &&
|
|
(!match(link->hostname, hostname) || !match(link->hostname, ip)))
|
|
return link;
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* ugly ugly ugly */
|
|
int match_ip46(char *a, char *b)
|
|
{
|
|
#ifdef INET6
|
|
if (!strncmp(a, "::ffff:", 7) && !strcmp(a+7, b))
|
|
return 0; // match
|
|
#endif
|
|
return 1; //nomatch
|
|
}
|
|
|
|
ConfigItem_cgiirc *Find_cgiirc(char *username, char *hostname, char *ip, CGIIRCType type)
|
|
{
|
|
ConfigItem_cgiirc *e;
|
|
|
|
if (!username || !hostname || !ip)
|
|
return NULL;
|
|
|
|
for (e = conf_cgiirc; e; e = (ConfigItem_cgiirc *)e->next)
|
|
{
|
|
if ((e->type == type) && (!e->username || !match(e->username, username)) &&
|
|
(!match(e->hostname, hostname) || !match(e->hostname, ip) || !match_ip46(e->hostname, ip)))
|
|
return e;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_ban *Find_ban(aClient *sptr, char *host, short type)
|
|
{
|
|
ConfigItem_ban *ban;
|
|
|
|
/* Check for an except ONLY if we find a ban, makes it
|
|
* faster since most users will not have a ban so excepts
|
|
* don't need to be searched -- codemastr
|
|
*/
|
|
|
|
for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
|
|
{
|
|
if (ban->flag.type == type)
|
|
{
|
|
if (sptr)
|
|
{
|
|
if (match_ip(sptr->ip, host, ban->mask, ban->netmask))
|
|
{
|
|
/* Person got a exception */
|
|
if ((type == CONF_BAN_USER || type == CONF_BAN_IP)
|
|
&& Find_except(sptr, host, CONF_EXCEPT_BAN))
|
|
return NULL;
|
|
return ban;
|
|
}
|
|
}
|
|
else if (!match(ban->mask, host)) /* We don't worry about exceptions */
|
|
return ban;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ConfigItem_ban *Find_banEx(aClient *sptr, char *host, short type, short type2)
|
|
{
|
|
ConfigItem_ban *ban;
|
|
|
|
/* Check for an except ONLY if we find a ban, makes it
|
|
* faster since most users will not have a ban so excepts
|
|
* don't need to be searched -- codemastr
|
|
*/
|
|
|
|
for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
|
|
{
|
|
if ((ban->flag.type == type) && (ban->flag.type2 == type2))
|
|
{
|
|
if (sptr)
|
|
{
|
|
if (match_ip(sptr->ip, host, ban->mask, ban->netmask)) {
|
|
/* Person got a exception */
|
|
if (Find_except(sptr, host, type))
|
|
return NULL;
|
|
return ban;
|
|
}
|
|
}
|
|
else if (!match(ban->mask, host)) /* We don't worry about exceptions */
|
|
return ban;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *username)
|
|
{
|
|
ConfigItem_allow *aconf;
|
|
char *hname;
|
|
int i, ii = 0;
|
|
static char uhost[HOSTLEN + USERLEN + 3];
|
|
static char fullname[HOSTLEN + 1];
|
|
|
|
for (aconf = conf_allow; aconf; aconf = (ConfigItem_allow *) aconf->next)
|
|
{
|
|
if (!aconf->hostname || !aconf->ip)
|
|
goto attach;
|
|
if (aconf->auth && !cptr->passwd && aconf->flags.nopasscont)
|
|
continue;
|
|
if (aconf->flags.ssl && !IsSecure(cptr))
|
|
continue;
|
|
if (hp && hp->h_name)
|
|
{
|
|
hname = hp->h_name;
|
|
strncpyzt(fullname, hname, sizeof(fullname));
|
|
add_local_domain(fullname, HOSTLEN - strlen(fullname));
|
|
Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
|
|
if (index(aconf->hostname, '@'))
|
|
{
|
|
if (aconf->flags.noident)
|
|
strlcpy(uhost, username, sizeof(uhost));
|
|
else
|
|
strlcpy(uhost, cptr->username, sizeof(uhost));
|
|
strlcat(uhost, "@", sizeof(uhost));
|
|
}
|
|
else
|
|
*uhost = '\0';
|
|
strlcat(uhost, fullname, sizeof(uhost));
|
|
if (!match(aconf->hostname, uhost))
|
|
goto attach;
|
|
}
|
|
|
|
if (index(aconf->ip, '@'))
|
|
{
|
|
if (aconf->flags.noident)
|
|
strncpyzt(uhost, username, sizeof(uhost));
|
|
else
|
|
strncpyzt(uhost, cptr->username, sizeof(uhost));
|
|
(void)strlcat(uhost, "@", sizeof(uhost));
|
|
}
|
|
else
|
|
*uhost = '\0';
|
|
strlcat(uhost, sockhost, sizeof(uhost));
|
|
/* Check the IP */
|
|
if (match_ip(cptr->ip, uhost, aconf->ip, aconf->netmask))
|
|
goto attach;
|
|
|
|
/* Hmm, localhost is a special case, hp == NULL and sockhost contains
|
|
* 'localhost' instead of an ip... -- Syzop. */
|
|
if (!strcmp(sockhost, "localhost"))
|
|
{
|
|
if (index(aconf->hostname, '@'))
|
|
{
|
|
if (aconf->flags.noident)
|
|
strcpy(uhost, username);
|
|
else
|
|
strcpy(uhost, cptr->username);
|
|
strcat(uhost, "@localhost");
|
|
}
|
|
else
|
|
strcpy(uhost, "localhost");
|
|
|
|
if (!match(aconf->hostname, uhost))
|
|
goto attach;
|
|
}
|
|
|
|
continue;
|
|
attach:
|
|
/* if (index(uhost, '@')) now flag based -- codemastr */
|
|
if (!aconf->flags.noident)
|
|
cptr->flags |= FLAGS_DOID;
|
|
if (!aconf->flags.useip && hp)
|
|
strncpyzt(uhost, fullname, sizeof(uhost));
|
|
else
|
|
strncpyzt(uhost, sockhost, sizeof(uhost));
|
|
get_sockhost(cptr, uhost);
|
|
/* FIXME */
|
|
if (aconf->maxperip)
|
|
{
|
|
ii = 1;
|
|
for (i = LastSlot; i >= 0; i--)
|
|
if (local[i] && MyClient(local[i]) &&
|
|
#ifndef INET6
|
|
local[i]->ip.S_ADDR == cptr->ip.S_ADDR)
|
|
#else
|
|
!bcmp(local[i]->ip.S_ADDR, cptr->ip.S_ADDR, sizeof(cptr->ip.S_ADDR)))
|
|
#endif
|
|
{
|
|
ii++;
|
|
if (ii > aconf->maxperip)
|
|
{
|
|
exit_client(cptr, cptr, &me,
|
|
"Too many connections from your IP");
|
|
return -5; /* Already got one with that ip# */
|
|
}
|
|
}
|
|
}
|
|
if ((i = Auth_Check(cptr, aconf->auth, cptr->passwd)) == -1)
|
|
{
|
|
exit_client(cptr, cptr, &me,
|
|
"Password mismatch");
|
|
return -5;
|
|
}
|
|
if ((i == 2) && (cptr->passwd))
|
|
{
|
|
MyFree(cptr->passwd);
|
|
cptr->passwd = NULL;
|
|
}
|
|
if (!((aconf->class->clients + 1) > aconf->class->maxclients))
|
|
{
|
|
cptr->class = aconf->class;
|
|
cptr->class->clients++;
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, rpl_str(RPL_REDIR), me.name, cptr->name, aconf->server ? aconf->server : defserv, aconf->port ? aconf->port : 6667);
|
|
return -3;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
ConfigItem_vhost *Find_vhost(char *name) {
|
|
ConfigItem_vhost *vhost;
|
|
|
|
for (vhost = conf_vhost; vhost; vhost = (ConfigItem_vhost *)vhost->next) {
|
|
if (!strcmp(name, vhost->login))
|
|
return vhost;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/** returns NULL if allowed and struct if denied */
|
|
ConfigItem_deny_channel *Find_channel_allowed(char *name)
|
|
{
|
|
ConfigItem_deny_channel *dchannel;
|
|
ConfigItem_allow_channel *achannel;
|
|
|
|
for (dchannel = conf_deny_channel; dchannel; dchannel = (ConfigItem_deny_channel *)dchannel->next)
|
|
{
|
|
if (!match(dchannel->channel, name))
|
|
break;
|
|
}
|
|
if (dchannel)
|
|
{
|
|
for (achannel = conf_allow_channel; achannel; achannel = (ConfigItem_allow_channel *)achannel->next)
|
|
{
|
|
if (!match(achannel->channel, name))
|
|
break;
|
|
}
|
|
if (achannel)
|
|
return NULL;
|
|
else
|
|
return (dchannel);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void init_dynconf(void)
|
|
{
|
|
bzero(&iConf, sizeof(iConf));
|
|
bzero(&tempiConf, sizeof(iConf));
|
|
}
|
|
|
|
char *pretty_time_val(long timeval)
|
|
{
|
|
static char buf[512];
|
|
|
|
if (timeval == 0)
|
|
return "0";
|
|
|
|
buf[0] = 0;
|
|
|
|
if (timeval/86400)
|
|
sprintf(buf, "%ld day%s ", timeval/86400, timeval/86400 != 1 ? "s" : "");
|
|
if ((timeval/3600) % 24)
|
|
sprintf(buf, "%s%ld hour%s ", buf, (timeval/3600)%24, (timeval/3600)%24 != 1 ? "s" : "");
|
|
if ((timeval/60)%60)
|
|
sprintf(buf, "%s%ld minute%s ", buf, (timeval/60)%60, (timeval/60)%60 != 1 ? "s" : "");
|
|
if ((timeval%60))
|
|
sprintf(buf, "%s%ld second%s", buf, timeval%60, timeval%60 != 1 ? "s" : "");
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* Actual config parser funcs
|
|
*/
|
|
|
|
int _conf_include(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
int ret = 0;
|
|
#ifdef GLOBH
|
|
glob_t files;
|
|
int i;
|
|
#elif defined(_WIN32)
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATA FindData;
|
|
char cPath[MAX_PATH], *cSlash = NULL, *path;
|
|
#endif
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_status("%s:%i: include: no filename given",
|
|
ce->ce_fileptr->cf_filename,
|
|
ce->ce_varlinenum);
|
|
return -1;
|
|
}
|
|
#ifdef USE_LIBCURL
|
|
if (url_is_valid(ce->ce_vardata))
|
|
return remote_include(ce);
|
|
#endif
|
|
#if !defined(_WIN32) && !defined(_AMIGA) && !defined(OSXTIGER) && DEFAULT_PERMISSIONS != 0
|
|
chmod(ce->ce_vardata, DEFAULT_PERMISSIONS);
|
|
#endif
|
|
#ifdef GLOBH
|
|
#if defined(__OpenBSD__) && defined(GLOB_LIMIT)
|
|
glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK|GLOB_LIMIT, NULL, &files);
|
|
#else
|
|
glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK, NULL, &files);
|
|
#endif
|
|
if (!files.gl_pathc) {
|
|
globfree(&files);
|
|
config_status("%s:%i: include %s: invalid file given",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return -1;
|
|
}
|
|
for (i = 0; i < files.gl_pathc; i++) {
|
|
ret = load_conf(files.gl_pathv[i]);
|
|
if (ret < 0)
|
|
{
|
|
globfree(&files);
|
|
return ret;
|
|
}
|
|
add_include(files.gl_pathv[i]);
|
|
}
|
|
globfree(&files);
|
|
#elif defined(_WIN32)
|
|
bzero(cPath,MAX_PATH);
|
|
if (strchr(ce->ce_vardata, '/') || strchr(ce->ce_vardata, '\\')) {
|
|
strncpyzt(cPath,ce->ce_vardata,MAX_PATH);
|
|
cSlash=cPath+strlen(cPath);
|
|
while(*cSlash != '\\' && *cSlash != '/' && cSlash > cPath)
|
|
cSlash--;
|
|
*(cSlash+1)=0;
|
|
}
|
|
if ( (hFind = FindFirstFile(ce->ce_vardata, &FindData)) == INVALID_HANDLE_VALUE )
|
|
{
|
|
config_status("%s:%i: include %s: invalid file given",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return -1;
|
|
}
|
|
if (cPath) {
|
|
path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
|
|
strcpy(path,cPath);
|
|
strcat(path,FindData.cFileName);
|
|
ret = load_conf(path);
|
|
if (ret >= 0)
|
|
add_include(path);
|
|
free(path);
|
|
|
|
}
|
|
else
|
|
{
|
|
ret = load_conf(FindData.cFileName);
|
|
if (ret >= 0)
|
|
add_include(FindData.cFileName);
|
|
}
|
|
if (ret < 0)
|
|
{
|
|
FindClose(hFind);
|
|
return ret;
|
|
}
|
|
|
|
ret = 0;
|
|
while (FindNextFile(hFind, &FindData) != 0) {
|
|
if (cPath) {
|
|
path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
|
|
strcpy(path,cPath);
|
|
strcat(path,FindData.cFileName);
|
|
ret = load_conf(path);
|
|
if (ret >= 0)
|
|
{
|
|
add_include(path);
|
|
free(path);
|
|
}
|
|
else
|
|
{
|
|
free(path);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = load_conf(FindData.cFileName);
|
|
if (ret >= 0)
|
|
add_include(FindData.cFileName);
|
|
}
|
|
}
|
|
FindClose(hFind);
|
|
if (ret < 0)
|
|
return ret;
|
|
#else
|
|
ret = load_conf(ce->ce_vardata);
|
|
if (ret >= 0)
|
|
add_include(ce->ce_vardata);
|
|
return ret;
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int _test_include(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int _conf_admin(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigItem_admin *ca;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
ca = MyMallocEx(sizeof(ConfigItem_admin));
|
|
if (!conf_admin)
|
|
conf_admin_tail = ca;
|
|
ircstrdup(ca->line, cep->ce_varname);
|
|
AddListItem(ca, conf_admin);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_admin(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
|
|
if (requiredstuff.conf_admin)
|
|
{
|
|
config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "admin");
|
|
return 0;
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error("%s:%i: blank admin item",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
requiredstuff.conf_admin = 1;
|
|
return errors;
|
|
}
|
|
|
|
int _conf_me(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
|
|
if (!conf_me)
|
|
conf_me = MyMallocEx(sizeof(ConfigItem_me));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "name"))
|
|
{
|
|
ircstrdup(conf_me->name, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "info"))
|
|
{
|
|
ircstrdup(conf_me->info, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "numeric"))
|
|
{
|
|
conf_me->numeric = atol(cep->ce_vardata);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_me(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
char has_name = 0, has_info = 0, has_numeric = 0;
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
|
|
if (requiredstuff.conf_me)
|
|
{
|
|
config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me");
|
|
return 0;
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "me"))
|
|
continue;
|
|
|
|
/* me::name */
|
|
if (!strcmp(cep->ce_varname, "name"))
|
|
{
|
|
if (has_name)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "me::name");
|
|
continue;
|
|
}
|
|
has_name = 1;
|
|
if (!strchr(cep->ce_vardata, '.'))
|
|
{
|
|
config_error("%s:%i: illegal me::name, must be fully qualified hostname",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
if (!valid_host(cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: illegal me::name contains invalid character(s) [only a-z, 0-9, _, -, . are allowed]",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
if (strlen(cep->ce_vardata) > HOSTLEN)
|
|
{
|
|
config_error("%s:%i: illegal me::name, must be less or equal to %i characters",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, HOSTLEN);
|
|
errors++;
|
|
}
|
|
}
|
|
/* me::info */
|
|
else if (!strcmp(cep->ce_varname, "info"))
|
|
{
|
|
char *p;
|
|
char valid = 0;
|
|
if (has_info)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "me::info");
|
|
continue;
|
|
}
|
|
has_info = 1;
|
|
if (strlen(cep->ce_vardata) > (REALLEN-1))
|
|
{
|
|
config_error("%s:%i: too long me::info, must be max. %i characters",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
REALLEN-1);
|
|
errors++;
|
|
}
|
|
|
|
/* Valid me::info? Any data except spaces is ok */
|
|
for (p=cep->ce_vardata; *p; p++)
|
|
{
|
|
if (*p != ' ')
|
|
{
|
|
valid = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!valid)
|
|
{
|
|
config_error("%s:%i: empty me::info, should be a server description.",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* me::numeric */
|
|
else if (!strcmp(cep->ce_varname, "numeric"))
|
|
{
|
|
long l;
|
|
|
|
has_numeric = 1;
|
|
l = atol(cep->ce_vardata);
|
|
if ((l < 0) || (l > 254))
|
|
{
|
|
config_error("%s:%i: illegal me::numeric error (must be between 0 and 254)",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* Unknown entry */
|
|
else
|
|
{
|
|
config_error_unknown(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"me", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_name)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::name");
|
|
errors++;
|
|
}
|
|
if (!has_info)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::info");
|
|
errors++;
|
|
}
|
|
if (!has_numeric)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"me::numeric");
|
|
errors++;
|
|
}
|
|
requiredstuff.conf_me = 1;
|
|
return errors;
|
|
}
|
|
|
|
/*
|
|
* The files {} block
|
|
*/
|
|
int _conf_files(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
|
|
if (!conf_files)
|
|
{
|
|
conf_files = MyMallocEx(sizeof(ConfigItem_files));
|
|
|
|
/* set defaults */
|
|
conf_files->motd_file = strdup(MPATH);
|
|
conf_files->rules_file = strdup(RPATH);
|
|
conf_files->smotd_file = strdup(SMPATH);
|
|
conf_files->botmotd_file = strdup(BPATH);
|
|
conf_files->opermotd_file = strdup(OPATH);
|
|
conf_files->svsmotd_file = strdup(VPATH);
|
|
|
|
conf_files->pid_file = strdup(IRCD_PIDFILE);
|
|
conf_files->tune_file = strdup(IRCDTUNE);
|
|
|
|
/* we let actual files get read in later by the motd caching mechanism */
|
|
fprintf(stderr, "files {} got initilized!\n");
|
|
}
|
|
/*
|
|
* hack to allow initialization of conf_files (above) when there is no files block in
|
|
* CPATH. The caller calls _conf_files(NULL, NULL); to do this. We return here because
|
|
* the for loop's initialization of cep would segfault otherwise. We return 1 because
|
|
* if config_run() calls us with a NULL ce, it's got a bug...but we can't detect that.
|
|
*/
|
|
if(!ce)
|
|
return 1;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "motd"))
|
|
ircstrdup(conf_files->motd_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "shortmotd"))
|
|
ircstrdup(conf_files->smotd_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "opermotd"))
|
|
ircstrdup(conf_files->opermotd_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "svsmotd"))
|
|
ircstrdup(conf_files->svsmotd_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "botmotd"))
|
|
ircstrdup(conf_files->botmotd_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "rules"))
|
|
ircstrdup(conf_files->rules_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "tunefile"))
|
|
ircstrdup(conf_files->tune_file, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "pidfile"))
|
|
ircstrdup(conf_files->pid_file, cep->ce_vardata);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_files(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
char has_motd = 0, has_smotd = 0, has_rules = 0;
|
|
char has_botmotd = 0, has_opermotd = 0, has_svsmotd = 0;
|
|
char has_pidfile = 0, has_tunefile = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
/* files::motd */
|
|
if (!strcmp(cep->ce_varname, "motd"))
|
|
{
|
|
if (has_motd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::motd");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::motd", 0);
|
|
has_motd = 1;
|
|
}
|
|
/* files::smotd */
|
|
else if (!strcmp(cep->ce_varname, "smotd"))
|
|
{
|
|
if (has_smotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::smotd");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::smotd", 0);
|
|
has_smotd = 1;
|
|
}
|
|
/* files::rules */
|
|
else if (!strcmp(cep->ce_varname, "rules"))
|
|
{
|
|
if (has_rules)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::rules");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::rules", 0);
|
|
has_rules = 1;
|
|
}
|
|
/* files::botmotd */
|
|
else if (!strcmp(cep->ce_varname, "botmotd"))
|
|
{
|
|
if (has_botmotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::botmotd");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::botmotd", 0);
|
|
has_botmotd = 1;
|
|
}
|
|
/* files::opermotd */
|
|
else if (!strcmp(cep->ce_varname, "opermotd"))
|
|
{
|
|
if (has_opermotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::opermotd");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::opermotd", 0);
|
|
has_opermotd = 1;
|
|
}
|
|
/* files::svsmotd
|
|
* This config stuff should somehow be inside of modules/m_svsmotd.c!!!... right?
|
|
*/
|
|
else if (!strcmp(cep->ce_varname, "svsmotd"))
|
|
{
|
|
if (has_svsmotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::svsmotd");
|
|
continue;
|
|
}
|
|
config_test_openfile(cep, O_RDONLY, 0, "files::svsmotd", 0);
|
|
has_svsmotd = 1;
|
|
}
|
|
/* files::pidfile */
|
|
else if (!strcmp(cep->ce_varname, "pidfile"))
|
|
{
|
|
if (has_pidfile)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::pidfile");
|
|
continue;
|
|
}
|
|
|
|
errors += config_test_openfile(cep, O_WRONLY | O_CREAT, 0600, "files::pidfile", 1);
|
|
has_pidfile = 1;
|
|
}
|
|
/* files::tunefile */
|
|
else if (!strcmp(cep->ce_varname, "tunefile"))
|
|
{
|
|
if (has_tunefile)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "files::tunefile");
|
|
continue;
|
|
}
|
|
errors += config_test_openfile(cep, O_RDWR | O_CREAT, 0600, "files::tunefile", 1);
|
|
has_tunefile = 1;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/*
|
|
* The oper {} block parser
|
|
*/
|
|
|
|
int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
ConfigItem_oper *oper = NULL;
|
|
ConfigItem_oper_from *from;
|
|
OperFlag *ofp = NULL;
|
|
struct irc_netmask tmp;
|
|
|
|
oper = MyMallocEx(sizeof(ConfigItem_oper));
|
|
oper->name = strdup(ce->ce_vardata);
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "password"))
|
|
oper->auth = Auth_ConvertConf2AuthStruct(cep);
|
|
else if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
oper->class = Find_class(cep->ce_vardata);
|
|
if (!oper->class || (oper->class->flag.temporary == 1))
|
|
{
|
|
config_status("%s:%i: illegal oper::class, unknown class '%s' using default of class 'default'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
oper->class = default_class;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
if (!cep->ce_entries)
|
|
{
|
|
char *m = "*";
|
|
int *i, flag;
|
|
|
|
for (m = (*cep->ce_vardata) ? cep->ce_vardata : m; *m; m++)
|
|
{
|
|
for (i = _OldOperFlags; (flag = *i); i += 2)
|
|
if (*m == (char)(*(i + 1)))
|
|
{
|
|
oper->oflags |= flag;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if ((ofp = config_binary_flags_search(_OperFlags, cepp->ce_varname, ARRAY_SIZEOF(_OperFlags))))
|
|
oper->oflags |= ofp->flag;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "swhois"))
|
|
{
|
|
ircstrdup(oper->swhois, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "snomask"))
|
|
{
|
|
ircstrdup(oper->snomask, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes"))
|
|
{
|
|
oper->modes = set_usermode(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxlogins"))
|
|
{
|
|
oper->maxlogins = atoi(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "from"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "userhost"))
|
|
{
|
|
from = MyMallocEx(sizeof(ConfigItem_oper_from));
|
|
ircstrdup(from->name, cepp->ce_vardata);
|
|
tmp.type = parse_netmask(from->name, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
from->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, from->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
AddListItem(from, oper->from);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AddListItem(oper, conf_oper);
|
|
return 1;
|
|
}
|
|
|
|
int _test_oper(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
char has_class = 0, has_password = 0, has_flags = 0, has_swhois = 0, has_snomask = 0;
|
|
char has_modes = 0, has_from = 0, has_maxlogins = 0;
|
|
int oper_flags = 0;
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
OperFlag *ofp;
|
|
int errors = 0;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "oper");
|
|
errors++;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"oper");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "password"))
|
|
{
|
|
if (has_password)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::password");
|
|
continue;
|
|
}
|
|
has_password = 1;
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* Regular variables */
|
|
if (!cep->ce_entries)
|
|
{
|
|
if (config_is_blankorempty(cep, "oper"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* oper::class */
|
|
if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
if (has_class)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::class");
|
|
continue;
|
|
}
|
|
has_class = 1;
|
|
}
|
|
/* oper::swhois */
|
|
else if (!strcmp(cep->ce_varname, "swhois"))
|
|
{
|
|
if (has_swhois)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::swhois");
|
|
continue;
|
|
}
|
|
has_swhois = 1;
|
|
}
|
|
/* oper::snomask */
|
|
else if (!strcmp(cep->ce_varname, "snomask"))
|
|
{
|
|
if (has_snomask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::snomask");
|
|
continue;
|
|
}
|
|
has_snomask = 1;
|
|
}
|
|
/* oper::modes */
|
|
else if (!strcmp(cep->ce_varname, "modes"))
|
|
{
|
|
char *p;
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if (strchr("oOaANCrzS", *p))
|
|
{
|
|
config_error("%s:%i: oper::modes may not include mode '%c'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
|
|
errors++;
|
|
}
|
|
if (has_modes)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::modes");
|
|
continue;
|
|
}
|
|
has_modes = 1;
|
|
}
|
|
/* oper::maxlogins */
|
|
else if (!strcmp(cep->ce_varname, "maxlogins"))
|
|
{
|
|
int l;
|
|
|
|
if (has_maxlogins)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::maxlogins");
|
|
continue;
|
|
}
|
|
has_maxlogins = 1;
|
|
|
|
l = atoi(cep->ce_vardata);
|
|
if ((l < 0) || (l > 5000))
|
|
{
|
|
config_error("%s:%i: oper::maxlogins: value out of range (%d) should be 0-5000",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, l);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
/* oper::flags */
|
|
else if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
if (has_flags)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::flags");
|
|
continue;
|
|
}
|
|
has_flags = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
/* Sections */
|
|
else
|
|
{
|
|
/* oper::flags {} */
|
|
if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
if (has_flags)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::flags");
|
|
continue;
|
|
}
|
|
has_flags = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
{
|
|
config_error_empty(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "oper::flags",
|
|
cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!(ofp = config_binary_flags_search(_OperFlags, cepp->ce_varname, ARRAY_SIZEOF(_OperFlags)))) {
|
|
config_error_unknownflag(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "oper",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
} else
|
|
oper_flags |= ofp->flag;
|
|
}
|
|
continue;
|
|
}
|
|
/* oper::from {} */
|
|
else if (!strcmp(cep->ce_varname, "from"))
|
|
{
|
|
if (has_from)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper::from");
|
|
continue;
|
|
}
|
|
has_from = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cepp, "oper::from"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* Unknown Entry */
|
|
if (strcmp(cepp->ce_varname, "userhost"))
|
|
{
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "oper::from",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "oper", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!has_password)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"oper::password");
|
|
errors++;
|
|
}
|
|
if (!has_from)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"oper::from");
|
|
errors++;
|
|
}
|
|
if (!has_flags)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"oper::flags");
|
|
errors++;
|
|
} else {
|
|
/* Check oper flags -- warning needed only (autoconvert) */
|
|
if (!(oper_flags & (OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)) &&
|
|
(oper_flags & (OFLAG_GZL|OFLAG_TKL|OFLAG_OVERRIDE)))
|
|
{
|
|
config_warn("%s:%i: oper::oflags: can_gzline/can_gkline/can_override (global privileges) "
|
|
"are incompatible with local oper -- user will be globop",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
}
|
|
}
|
|
if (!has_class)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"oper::class");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
|
|
}
|
|
|
|
/*
|
|
* The class {} block parser
|
|
*/
|
|
int _conf_class(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cep2;
|
|
ConfigItem_class *class;
|
|
unsigned char isnew = 0;
|
|
|
|
if (!(class = Find_class(ce->ce_vardata)))
|
|
{
|
|
class = MyMallocEx(sizeof(ConfigItem_class));
|
|
ircstrdup(class->name, ce->ce_vardata);
|
|
isnew = 1;
|
|
}
|
|
else
|
|
{
|
|
isnew = 0;
|
|
class->flag.temporary = 0;
|
|
class->options = 0; /* RESET OPTIONS */
|
|
}
|
|
ircstrdup(class->name, ce->ce_vardata);
|
|
|
|
class->connfreq = 60; /* default */
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "pingfreq"))
|
|
class->pingfreq = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "connfreq"))
|
|
class->connfreq = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "maxclients"))
|
|
class->maxclients = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "sendq"))
|
|
class->sendq = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "recvq"))
|
|
class->recvq = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
|
|
if (!strcmp(cep2->ce_varname, "nofakelag"))
|
|
class->options |= CLASS_OPT_NOFAKELAG;
|
|
}
|
|
}
|
|
if (isnew)
|
|
AddListItem(class, conf_class);
|
|
return 1;
|
|
}
|
|
|
|
int _test_class(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cep2;
|
|
int errors = 0;
|
|
char has_pingfreq = 0, has_connfreq = 0, has_maxclients = 0, has_sendq = 0;
|
|
char has_recvq = 0;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "class");
|
|
errors++;
|
|
}
|
|
if (!strcasecmp(ce->ce_vardata, "default"))
|
|
{
|
|
config_error("%s:%d: Class cannot be named 'default', this class name is reserved for internal use.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
|
|
{
|
|
#ifdef FAKELAG_CONFIGURABLE
|
|
if (!strcmp(cep2->ce_varname, "nofakelag"))
|
|
;
|
|
else
|
|
#endif
|
|
{
|
|
config_error("%s:%d: Unknown option '%s' in class::options",
|
|
cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep2->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else if (config_is_blankorempty(cep, "class"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* class::pingfreq */
|
|
else if (!strcmp(cep->ce_varname, "pingfreq"))
|
|
{
|
|
int v = atol(cep->ce_vardata);
|
|
if (has_pingfreq)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "class::pingfreq");
|
|
continue;
|
|
}
|
|
has_pingfreq = 1;
|
|
if ((v < 30) || (v > 600))
|
|
{
|
|
config_error("%s:%i: class::pingfreq should be a reasonable value (30-600)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
/* class::maxclients */
|
|
else if (!strcmp(cep->ce_varname, "maxclients"))
|
|
{
|
|
long l;
|
|
if (has_maxclients)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "class::maxclients");
|
|
continue;
|
|
}
|
|
has_maxclients = 1;
|
|
l = atol(cep->ce_vardata);
|
|
if ((l < 1) || (l > 1000000))
|
|
{
|
|
config_error("%s:%i: class::maxclients with illegal value",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* class::connfreq */
|
|
else if (!strcmp(cep->ce_varname, "connfreq"))
|
|
{
|
|
long l;
|
|
if (has_connfreq)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "class::connfreq");
|
|
continue;
|
|
}
|
|
has_connfreq = 1;
|
|
l = atol(cep->ce_vardata);
|
|
if ((l < 10) || (l > 604800))
|
|
{
|
|
config_error("%s:%i: class::connfreq with illegal value (must be >10 and <7d)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* class::sendq */
|
|
else if (!strcmp(cep->ce_varname, "sendq"))
|
|
{
|
|
long l;
|
|
if (has_sendq)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "class::sendq");
|
|
continue;
|
|
}
|
|
has_sendq = 1;
|
|
l = atol(cep->ce_vardata);
|
|
if ((l < 0) || (l > 2000000000))
|
|
{
|
|
config_error("%s:%i: class::sendq with illegal value",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* class::recvq */
|
|
else if (!strcmp(cep->ce_varname, "recvq"))
|
|
{
|
|
long l;
|
|
if (has_recvq)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "class::recvq");
|
|
continue;
|
|
}
|
|
has_recvq = 1;
|
|
l = atol(cep->ce_vardata);
|
|
if ((l < 512) || (l > 32768))
|
|
{
|
|
config_error("%s:%i: class::recvq with illegal value (must be >512 and <32k)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
/* Unknown */
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"class", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_pingfreq)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"class::pingfreq");
|
|
errors++;
|
|
}
|
|
if (!has_maxclients)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"class::maxclients");
|
|
errors++;
|
|
}
|
|
if (!has_sendq)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"class::sendq");
|
|
errors++;
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
int _conf_drpass(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
|
|
if (!conf_drpass)
|
|
{
|
|
conf_drpass = MyMallocEx(sizeof(ConfigItem_drpass));
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "restart"))
|
|
{
|
|
if (conf_drpass->restartauth)
|
|
Auth_DeleteAuthStruct(conf_drpass->restartauth);
|
|
|
|
conf_drpass->restartauth = Auth_ConvertConf2AuthStruct(cep);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "die"))
|
|
{
|
|
if (conf_drpass->dieauth)
|
|
Auth_DeleteAuthStruct(conf_drpass->dieauth);
|
|
|
|
conf_drpass->dieauth = Auth_ConvertConf2AuthStruct(cep);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_drpass(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
char has_restart = 0, has_die = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "drpass"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* drpass::restart */
|
|
if (!strcmp(cep->ce_varname, "restart"))
|
|
{
|
|
if (has_restart)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "drpass::restart");
|
|
continue;
|
|
}
|
|
has_restart = 1;
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* drpass::die */
|
|
else if (!strcmp(cep->ce_varname, "die"))
|
|
{
|
|
if (has_die)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "drpass::die");
|
|
continue;
|
|
}
|
|
has_die = 1;
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* Unknown */
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"drpass", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/*
|
|
* The ulines {} block parser
|
|
*/
|
|
int _conf_ulines(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigItem_ulines *ca;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
ca = MyMallocEx(sizeof(ConfigItem_ulines));
|
|
ircstrdup(ca->servername, cep->ce_varname);
|
|
AddListItem(ca, conf_ulines);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_ulines(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "ulines");
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_tld(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigItem_tld *ca;
|
|
|
|
ca = MyMallocEx(sizeof(ConfigItem_tld));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
ca->mask = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "motd"))
|
|
{
|
|
ca->motd_file = strdup(cep->ce_vardata);
|
|
ca->motd = read_file_ex(cep->ce_vardata, NULL, &ca->motd_tm);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "shortmotd"))
|
|
{
|
|
ca->smotd_file = strdup(cep->ce_vardata);
|
|
ca->smotd = read_file_ex(cep->ce_vardata, NULL, &ca->smotd_tm);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "opermotd"))
|
|
{
|
|
ca->opermotd_file = strdup(cep->ce_vardata);
|
|
ca->opermotd = read_file(cep->ce_vardata, NULL);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "botmotd"))
|
|
{
|
|
ca->botmotd_file = strdup(cep->ce_vardata);
|
|
ca->botmotd = read_file(cep->ce_vardata, NULL);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "rules"))
|
|
{
|
|
ca->rules_file = strdup(cep->ce_vardata);
|
|
ca->rules = read_file(cep->ce_vardata, NULL);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
ConfigEntry *cepp;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "ssl"))
|
|
ca->options |= TLD_SSL;
|
|
else if (!strcmp(cepp->ce_varname, "remote"))
|
|
ca->options |= TLD_REMOTE;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "channel"))
|
|
ca->channel = strdup(cep->ce_vardata);
|
|
}
|
|
AddListItem(ca, conf_tld);
|
|
return 1;
|
|
}
|
|
|
|
int _test_tld(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
int fd = -1;
|
|
char has_mask = 0, has_motd = 0, has_rules = 0, has_shortmotd = 0, has_channel = 0;
|
|
char has_opermotd = 0, has_botmotd = 0, has_options = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"tld");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!cep->ce_vardata && strcmp(cep->ce_varname, "options"))
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"tld", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
/* tld::mask */
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
/* tld::motd */
|
|
else if (!strcmp(cep->ce_varname, "motd"))
|
|
{
|
|
if (has_motd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::motd");
|
|
continue;
|
|
}
|
|
has_motd = 1;
|
|
if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
|
|
{
|
|
config_error("%s:%i: tld::motd: %s: %s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata, strerror(errno));
|
|
errors++;
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
/* tld::rules */
|
|
else if (!strcmp(cep->ce_varname, "rules"))
|
|
{
|
|
if (has_rules)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::rules");
|
|
continue;
|
|
}
|
|
has_rules = 1;
|
|
if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
|
|
{
|
|
config_error("%s:%i: tld::rules: %s: %s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata, strerror(errno));
|
|
errors++;
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
/* tld::channel */
|
|
else if (!strcmp(cep->ce_varname, "channel"))
|
|
{
|
|
if (has_channel)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::channel");
|
|
continue;
|
|
}
|
|
has_channel = 1;
|
|
}
|
|
/* tld::shortmotd */
|
|
else if (!strcmp(cep->ce_varname, "shortmotd"))
|
|
{
|
|
if (has_shortmotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::shortmotd");
|
|
continue;
|
|
}
|
|
has_shortmotd = 1;
|
|
if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
|
|
{
|
|
config_error("%s:%i: tld::shortmotd: %s: %s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata, strerror(errno));
|
|
errors++;
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
/* tld::opermotd */
|
|
else if (!strcmp(cep->ce_varname, "opermotd"))
|
|
{
|
|
if (has_opermotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::opermotd");
|
|
continue;
|
|
}
|
|
has_opermotd = 1;
|
|
if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
|
|
{
|
|
config_error("%s:%i: tld::opermotd: %s: %s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata, strerror(errno));
|
|
errors++;
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
/* tld::botmotd */
|
|
else if (!strcmp(cep->ce_varname, "botmotd"))
|
|
{
|
|
if (has_botmotd)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::botmotd");
|
|
continue;
|
|
}
|
|
has_botmotd = 1;
|
|
if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
|
|
{
|
|
config_error("%s:%i: tld::botmotd: %s: %s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata, strerror(errno));
|
|
errors++;
|
|
}
|
|
else
|
|
close(fd);
|
|
}
|
|
/* tld::options */
|
|
else if (!strcmp(cep->ce_varname, "options")) {
|
|
ConfigEntry *cep2;
|
|
|
|
if (has_options)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "tld::options");
|
|
continue;
|
|
}
|
|
has_options = 1;
|
|
|
|
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
|
|
{
|
|
if (!cep2->ce_varname)
|
|
{
|
|
config_error_blank(cep2->ce_fileptr->cf_filename,
|
|
cep2->ce_varlinenum, "tld::options");
|
|
continue;
|
|
}
|
|
if (strcmp(cep2->ce_varname, "ssl") &&
|
|
strcmp(cep2->ce_varname, "remote"))
|
|
{
|
|
config_error_unknownopt(cep2->ce_fileptr->cf_filename,
|
|
cep2->ce_varlinenum, "tld", cep2->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"tld", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"tld::mask");
|
|
errors++;
|
|
}
|
|
if (!has_motd)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"tld::motd");
|
|
errors++;
|
|
}
|
|
if (!has_rules)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"tld::rules");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
ConfigItem_listen *listen = NULL;
|
|
OperFlag *ofp;
|
|
char copy[256];
|
|
char *ip;
|
|
char *port;
|
|
int start, end, iport, isnew;
|
|
int tmpflags =0;
|
|
|
|
strcpy(copy, ce->ce_vardata);
|
|
/* Seriously cheap hack to make listen <port> work -Stskeeps */
|
|
ipport_seperate(copy, &ip, &port);
|
|
if (!ip || !*ip)
|
|
{
|
|
return -1;
|
|
}
|
|
if (strchr(ip, '*') && strcmp(ip, "*"))
|
|
{
|
|
return -1;
|
|
}
|
|
if (!port || !*port)
|
|
{
|
|
return -1;
|
|
}
|
|
port_range(port, &start, &end);
|
|
if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
|
|
{
|
|
return -1;
|
|
}
|
|
end++;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if ((ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
|
|
tmpflags |= ofp->flag;
|
|
}
|
|
}
|
|
}
|
|
#ifndef USE_SSL
|
|
tmpflags &= ~LISTENER_SSL;
|
|
#endif
|
|
for (iport = start; iport < end; iport++)
|
|
{
|
|
if (!(listen = Find_listen(ip, iport)))
|
|
{
|
|
listen = MyMallocEx(sizeof(ConfigItem_listen));
|
|
listen->ip = strdup(ip);
|
|
listen->port = iport;
|
|
isnew = 1;
|
|
} else
|
|
isnew = 0;
|
|
|
|
if (listen->options & LISTENER_BOUND)
|
|
tmpflags |= LISTENER_BOUND;
|
|
|
|
listen->options = tmpflags;
|
|
if (isnew)
|
|
AddListItem(listen, conf_listen);
|
|
listen->flag.temporary = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_listen(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
char copy[256];
|
|
char *ip;
|
|
char *port;
|
|
int start, end;
|
|
int errors = 0;
|
|
char has_options = 0;
|
|
OperFlag *ofp;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: listen without ip:port",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
|
|
strcpy(copy, ce->ce_vardata);
|
|
/* Seriously cheap hack to make listen <port> work -Stskeeps */
|
|
ipport_seperate(copy, &ip, &port);
|
|
if (!ip || !*ip)
|
|
{
|
|
config_error("%s:%i: listen: illegal ip:port mask",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (strchr(ip, '*') && strcmp(ip, "*"))
|
|
{
|
|
config_error("%s:%i: listen: illegal ip, (mask, and not '*')",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!port || !*port)
|
|
{
|
|
config_error("%s:%i: listen: missing port in mask",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
#ifdef INET6
|
|
if ((strlen(ip) > 6) && !strchr(ip, ':') && isdigit(ip[strlen(ip)-1]))
|
|
{
|
|
char crap[32];
|
|
if (inet_pton(AF_INET, ip, crap) != 0)
|
|
{
|
|
char ipv6buf[128];
|
|
snprintf(ipv6buf, sizeof(ipv6buf), "[::ffff:%s]:%s", ip, port);
|
|
ce->ce_vardata = strdup(ipv6buf);
|
|
} else {
|
|
/* Insert IPv6 validation here */
|
|
config_error("%s:%i: listen: '%s' looks like it might be IPv4, but is not a valid address.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ip);
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
port_range(port, &start, &end);
|
|
if (start == end)
|
|
{
|
|
if ((start < 0) || (start > 65535))
|
|
{
|
|
config_error("%s:%i: listen: illegal port (must be 0..65535)",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (end < start)
|
|
{
|
|
config_error("%s:%i: listen: illegal port range end value is less than starting value",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (end - start >= 100)
|
|
{
|
|
config_error("%s:%i: listen: you requested port %d-%d, that's %d ports "
|
|
"(and thus consumes %d sockets) this is probably not what you want.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum, start, end,
|
|
end - start + 1, end - start + 1);
|
|
return 1;
|
|
}
|
|
if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
|
|
{
|
|
config_error("%s:%i: listen: illegal port range values must be between 0 and 65535",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"listen");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
if (has_options)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "listen::options");
|
|
continue;
|
|
}
|
|
has_options = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
{
|
|
config_error_blank(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "listen::options");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!(ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "class", cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
#ifndef USE_SSL
|
|
else if (ofp->flag & LISTENER_SSL)
|
|
{
|
|
config_warn("%s:%i: listen with SSL flag enabled on a non SSL compile",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"listen", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
|
|
}
|
|
requiredstuff.conf_listen = 1;
|
|
return errors;
|
|
}
|
|
|
|
|
|
int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
ConfigItem_allow *allow;
|
|
Hook *h;
|
|
struct irc_netmask tmp;
|
|
if (ce->ce_vardata)
|
|
{
|
|
if (!strcmp(ce->ce_vardata, "channel"))
|
|
return (_conf_allow_channel(conf, ce));
|
|
else if (!strcmp(ce->ce_vardata, "dcc"))
|
|
return (_conf_allow_dcc(conf, ce));
|
|
else
|
|
{
|
|
int value;
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
allow = MyMallocEx(sizeof(ConfigItem_allow));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "ip"))
|
|
{
|
|
allow->ip = strdup(cep->ce_vardata);
|
|
/* CIDR */
|
|
tmp.type = parse_netmask(allow->ip, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
allow->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, allow->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
allow->hostname = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
allow->auth = Auth_ConvertConf2AuthStruct(cep);
|
|
else if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
allow->class = Find_class(cep->ce_vardata);
|
|
if (!allow->class || (allow->class->flag.temporary == 1))
|
|
{
|
|
config_status("%s:%i: illegal allow::class, unknown class '%s' using default of class 'default'",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
allow->class = default_class;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxperip"))
|
|
allow->maxperip = atoi(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "redirect-server"))
|
|
allow->server = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "redirect-port"))
|
|
allow->port = atoi(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "noident"))
|
|
allow->flags.noident = 1;
|
|
else if (!strcmp(cepp->ce_varname, "useip"))
|
|
allow->flags.useip = 1;
|
|
else if (!strcmp(cepp->ce_varname, "ssl"))
|
|
allow->flags.ssl = 1;
|
|
else if (!strcmp(cepp->ce_varname, "nopasscont"))
|
|
allow->flags.nopasscont = 1;
|
|
}
|
|
}
|
|
}
|
|
AddListItem(allow, conf_allow);
|
|
return 1;
|
|
}
|
|
|
|
int _test_allow(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
int errors = 0;
|
|
Hook *h;
|
|
char has_ip = 0, has_hostname = 0, has_maxperip = 0, has_password = 0, has_class = 0;
|
|
char has_redirectserver = 0, has_redirectport = 0, has_options = 0;
|
|
|
|
if (ce->ce_vardata)
|
|
{
|
|
if (!strcmp(ce->ce_vardata, "channel"))
|
|
return (_test_allow_channel(conf, ce));
|
|
else if (!strcmp(ce->ce_vardata, "dcc"))
|
|
return (_test_allow_dcc(conf, ce));
|
|
else
|
|
{
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW,&errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
}
|
|
if (!used) {
|
|
config_error("%s:%i: allow item with unknown type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
return errors;
|
|
}
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (strcmp(cep->ce_varname, "options") && config_is_blankorempty(cep, "allow"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "ip"))
|
|
{
|
|
if (has_ip)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::ip");
|
|
continue;
|
|
}
|
|
has_ip = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxperip"))
|
|
{
|
|
int v = atoi(cep->ce_vardata);
|
|
if (has_maxperip)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::maxperip");
|
|
continue;
|
|
}
|
|
has_maxperip = 1;
|
|
if ((v <= 0) || (v > 65535))
|
|
{
|
|
config_error("%s:%i: allow::maxperip with illegal value (must be 1-65535)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
{
|
|
if (has_hostname)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::hostname");
|
|
continue;
|
|
}
|
|
has_hostname = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
{
|
|
if (has_password)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::password");
|
|
continue;
|
|
}
|
|
has_password = 1;
|
|
/* some auth check stuff? */
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
if (has_class)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::class");
|
|
continue;
|
|
}
|
|
has_class = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "redirect-server"))
|
|
{
|
|
if (has_redirectserver)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::redirect-server");
|
|
continue;
|
|
}
|
|
has_redirectserver = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "redirect-port"))
|
|
{
|
|
if (has_redirectport)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::redirect-port");
|
|
continue;
|
|
}
|
|
has_redirectport = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
if (has_options)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow::options");
|
|
continue;
|
|
}
|
|
has_options = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "noident"))
|
|
{}
|
|
else if (!strcmp(cepp->ce_varname, "useip"))
|
|
{}
|
|
else if (!strcmp(cepp->ce_varname, "ssl"))
|
|
{}
|
|
else if (!strcmp(cepp->ce_varname, "nopasscont"))
|
|
{}
|
|
else
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "allow", cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"allow", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_ip)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"allow::ip");
|
|
errors++;
|
|
}
|
|
if (!has_hostname)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"allow::hostname");
|
|
errors++;
|
|
}
|
|
if (!has_class)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"allow::class");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_allow_channel *allow = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "channel"))
|
|
{
|
|
allow = MyMallocEx(sizeof(ConfigItem_allow_channel));
|
|
ircstrdup(allow->channel, cep->ce_vardata);
|
|
AddListItem(allow, conf_allow_channel);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
char has_channel = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "allow channel"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "channel"))
|
|
has_channel = 1;
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"allow channel", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_channel)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"allow channel::channel");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_allow_dcc *allow = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
allow = MyMallocEx(sizeof(ConfigItem_allow_dcc));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "filename"))
|
|
ircstrdup(allow->filename, cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "soft"))
|
|
{
|
|
int x = config_checkval(cep->ce_vardata,CFG_YESNO);
|
|
if (x)
|
|
allow->flag.type = DCCDENY_SOFT;
|
|
}
|
|
}
|
|
AddListItem(allow, conf_allow_dcc);
|
|
return 1;
|
|
}
|
|
|
|
int _test_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0, has_filename = 0, has_soft = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "allow dcc"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "filename"))
|
|
{
|
|
if (has_filename)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow dcc::filename");
|
|
continue;
|
|
}
|
|
has_filename = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "soft"))
|
|
{
|
|
if (has_soft)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "allow dcc::soft");
|
|
continue;
|
|
}
|
|
has_soft = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"allow dcc", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_filename)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"allow dcc::filename");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
void create_tkl_except(char *mask, char *type)
|
|
{
|
|
ConfigItem_except *ca;
|
|
struct irc_netmask tmp;
|
|
OperFlag *opf;
|
|
ca = MyMallocEx(sizeof(ConfigItem_except));
|
|
ca->mask = strdup(mask);
|
|
|
|
opf = config_binary_flags_search(ExceptTklFlags, type, ARRAY_SIZEOF(ExceptTklFlags));
|
|
ca->type = opf->flag;
|
|
|
|
if (ca->type & TKL_KILL || ca->type & TKL_ZAP || ca->type & TKL_SHUN)
|
|
{
|
|
tmp.type = parse_netmask(ca->mask, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
}
|
|
ca->flag.type = CONF_EXCEPT_TKL;
|
|
AddListItem(ca, conf_except);
|
|
}
|
|
|
|
int _conf_except(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
|
|
ConfigEntry *cep;
|
|
ConfigItem_except *ca;
|
|
Hook *h;
|
|
struct irc_netmask tmp;
|
|
|
|
if (!strcmp(ce->ce_vardata, "ban")) {
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask")) {
|
|
ca = MyMallocEx(sizeof(ConfigItem_except));
|
|
ca->mask = strdup(cep->ce_vardata);
|
|
tmp.type = parse_netmask(ca->mask, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
ca->flag.type = CONF_EXCEPT_BAN;
|
|
AddListItem(ca, conf_except);
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
}
|
|
#ifdef THROTTLING
|
|
else if (!strcmp(ce->ce_vardata, "throttle")) {
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask")) {
|
|
ca = MyMallocEx(sizeof(ConfigItem_except));
|
|
ca->mask = strdup(cep->ce_vardata);
|
|
tmp.type = parse_netmask(ca->mask, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
ca->flag.type = CONF_EXCEPT_THROTTLE;
|
|
AddListItem(ca, conf_except);
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
else if (!strcmp(ce->ce_vardata, "tkl")) {
|
|
ConfigEntry *mask = NULL, *type = NULL;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
mask = cep;
|
|
else if (!strcmp(cep->ce_varname, "type"))
|
|
type = cep;
|
|
}
|
|
if (type->ce_vardata)
|
|
create_tkl_except(mask->ce_vardata, type->ce_vardata);
|
|
else
|
|
{
|
|
ConfigEntry *cepp;
|
|
for (cepp = type->ce_entries; cepp; cepp = cepp->ce_next)
|
|
create_tkl_except(mask->ce_vardata, cepp->ce_varname);
|
|
}
|
|
}
|
|
else {
|
|
int value;
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_except(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
Hook *h;
|
|
char has_mask = 0;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: except without type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
|
|
if (!strcmp(ce->ce_vardata, "ban"))
|
|
{
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "except ban"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except ban::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except ban", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"except ban::mask");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
#ifdef THROTTLING
|
|
else if (!strcmp(ce->ce_vardata, "throttle")) {
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "except throttle"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except throttle::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except throttle", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"except throttle::mask");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
#endif
|
|
else if (!strcmp(ce->ce_vardata, "tkl")) {
|
|
char has_type = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl", "mask");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type"))
|
|
{
|
|
if (has_type)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl::type");
|
|
continue;
|
|
}
|
|
if (cep->ce_vardata)
|
|
{
|
|
if (!strcmp(cep->ce_vardata, "tkline") ||
|
|
!strcmp(cep->ce_vardata, "tzline"))
|
|
{
|
|
config_error("%s:%i: except tkl of type %s is"
|
|
" deprecated. Use except ban {}"
|
|
" instead",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
if (!config_binary_flags_search(ExceptTklFlags,
|
|
cep->ce_vardata, ARRAY_SIZEOF(ExceptTklFlags)))
|
|
{
|
|
config_error("%s:%i: unknown except tkl type %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
return 1;
|
|
}
|
|
}
|
|
else if (cep->ce_entries)
|
|
{
|
|
ConfigEntry *cepp;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "tkline") ||
|
|
!strcmp(cepp->ce_varname, "tzline"))
|
|
{
|
|
config_error("%s:%i: except tkl of type %s is"
|
|
" deprecated. Use except ban {}"
|
|
" instead",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
if (!config_binary_flags_search(ExceptTklFlags,
|
|
cepp->ce_varname, ARRAY_SIZEOF(ExceptTklFlags)))
|
|
{
|
|
config_error("%s:%i: unknown except tkl type %s",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl", "type");
|
|
errors++;
|
|
continue;
|
|
}
|
|
has_type = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "except tkl", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error("%s:%i: except tkl without mask item",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!has_type)
|
|
{
|
|
config_error("%s:%i: except tkl without type item",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
return errors;
|
|
}
|
|
else {
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT,&errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
}
|
|
if (!used) {
|
|
config_error("%s:%i: unknown except type %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return 1;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/*
|
|
* vhost {} block parser
|
|
*/
|
|
int _conf_vhost(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_vhost *vhost;
|
|
ConfigItem_oper_from *from;
|
|
ConfigEntry *cep, *cepp;
|
|
vhost = MyMallocEx(sizeof(ConfigItem_vhost));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "vhost"))
|
|
{
|
|
char *user, *host;
|
|
user = strtok(cep->ce_vardata, "@");
|
|
host = strtok(NULL, "");
|
|
if (!host)
|
|
vhost->virthost = strdup(user);
|
|
else
|
|
{
|
|
vhost->virtuser = strdup(user);
|
|
vhost->virthost = strdup(host);
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "login"))
|
|
vhost->login = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
vhost->auth = Auth_ConvertConf2AuthStruct(cep);
|
|
else if (!strcmp(cep->ce_varname, "from"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "userhost"))
|
|
{
|
|
from = MyMallocEx(sizeof(ConfigItem_oper_from));
|
|
ircstrdup(from->name, cepp->ce_vardata);
|
|
AddListItem(from, vhost->from);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "swhois"))
|
|
vhost->swhois = strdup(cep->ce_vardata);
|
|
}
|
|
AddListItem(vhost, conf_vhost);
|
|
return 1;
|
|
}
|
|
|
|
int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
int errors = 0;
|
|
ConfigEntry *cep;
|
|
char has_vhost = 0, has_login = 0, has_password = 0, has_swhois = 0, has_from = 0;
|
|
char has_userhost = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "vhost"))
|
|
{
|
|
char *at, *tmp, *host;
|
|
if (has_vhost)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost::vhost");
|
|
continue;
|
|
}
|
|
has_vhost = 1;
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost", "vhost");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if ((at = strchr(cep->ce_vardata, '@')))
|
|
{
|
|
for (tmp = cep->ce_vardata; tmp != at; tmp++)
|
|
{
|
|
if (*tmp == '~' && tmp == cep->ce_vardata)
|
|
continue;
|
|
if (!isallowed(*tmp))
|
|
break;
|
|
}
|
|
if (tmp != at)
|
|
{
|
|
config_error("%s:%i: vhost::vhost contains an invalid ident",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
host = at+1;
|
|
}
|
|
else
|
|
host = cep->ce_vardata;
|
|
if (!*host)
|
|
{
|
|
config_error("%s:%i: vhost::vhost does not have a host set",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
else
|
|
{
|
|
if (!valid_host(host))
|
|
{
|
|
config_error("%s:%i: vhost::vhost contains an invalid host",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "login"))
|
|
{
|
|
if (has_login)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost::login");
|
|
}
|
|
has_login = 1;
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost", "login");
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
{
|
|
if (has_password)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost::password");
|
|
}
|
|
has_password = 1;
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost", "password");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "from"))
|
|
{
|
|
ConfigEntry *cepp;
|
|
|
|
if (has_from)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost::from");
|
|
continue;
|
|
}
|
|
has_from = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cepp, "vhost::from"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cepp->ce_varname, "userhost"))
|
|
has_userhost = 1;
|
|
else
|
|
{
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "vhost::from",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "swhois"))
|
|
{
|
|
if (has_swhois)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "vhost::swhois");
|
|
continue;
|
|
}
|
|
has_swhois = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"vhost", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_vhost)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"vhost::vhost");
|
|
errors++;
|
|
}
|
|
if (!has_login)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"vhost::login");
|
|
errors++;
|
|
|
|
}
|
|
if (!has_password)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"vhost::password");
|
|
errors++;
|
|
}
|
|
if (!has_from)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"vhost::from");
|
|
errors++;
|
|
}
|
|
if (!has_userhost)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"vhost::userhost");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
#ifdef STRIPBADWORDS
|
|
|
|
static ConfigItem_badword *copy_badword_struct(ConfigItem_badword *ca, int regex, int regflags)
|
|
{
|
|
ConfigItem_badword *x = MyMalloc(sizeof(ConfigItem_badword));
|
|
memcpy(x, ca, sizeof(ConfigItem_badword));
|
|
x->word = strdup(ca->word);
|
|
if (ca->replace)
|
|
x->replace = strdup(ca->replace);
|
|
if (regex)
|
|
{
|
|
memset(&x->expr, 0, sizeof(regex_t));
|
|
regcomp(&x->expr, x->word, regflags);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
int _conf_badword(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *word = NULL;
|
|
ConfigItem_badword *ca;
|
|
char *tmp;
|
|
short regex = 0;
|
|
int regflags = 0;
|
|
#ifdef FAST_BADWORD_REPLACE
|
|
int ast_l = 0, ast_r = 0;
|
|
#endif
|
|
|
|
ca = MyMallocEx(sizeof(ConfigItem_badword));
|
|
ca->action = BADWORD_REPLACE;
|
|
regflags = REG_ICASE|REG_EXTENDED;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "action"))
|
|
{
|
|
if (!strcmp(cep->ce_vardata, "block"))
|
|
{
|
|
ca->action = BADWORD_BLOCK;
|
|
/* If it is set to just block, then we don't need to worry about
|
|
* replacements
|
|
*/
|
|
regflags |= REG_NOSUB;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "replace"))
|
|
{
|
|
ircstrdup(ca->replace, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "word"))
|
|
word = cep;
|
|
}
|
|
#ifdef FAST_BADWORD_REPLACE
|
|
/* The fast badwords routine can do: "blah" "*blah" "blah*" and "*blah*",
|
|
* in all other cases use regex.
|
|
*/
|
|
for (tmp = word->ce_vardata; *tmp; tmp++) {
|
|
if (!isalnum(*tmp) && !(*tmp >= 128)) {
|
|
if ((word->ce_vardata == tmp) && (*tmp == '*')) {
|
|
ast_l = 1; /* Asterisk at the left */
|
|
continue;
|
|
}
|
|
if ((*(tmp + 1) == '\0') && (*tmp == '*')) {
|
|
ast_r = 1; /* Asterisk at the right */
|
|
continue;
|
|
}
|
|
regex = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (regex)
|
|
{
|
|
ca->type = BADW_TYPE_REGEX;
|
|
ircstrdup(ca->word, word->ce_vardata);
|
|
regcomp(&ca->expr, ca->word, regflags);
|
|
}
|
|
else
|
|
{
|
|
char *tmpw;
|
|
ca->type = BADW_TYPE_FAST;
|
|
ca->word = tmpw = MyMalloc(strlen(word->ce_vardata) - ast_l - ast_r + 1);
|
|
/* Copy except for asterisks */
|
|
for (tmp = word->ce_vardata; *tmp; tmp++)
|
|
if (*tmp != '*')
|
|
*tmpw++ = *tmp;
|
|
*tmpw = '\0';
|
|
if (ast_l)
|
|
ca->type |= BADW_TYPE_FAST_L;
|
|
if (ast_r)
|
|
ca->type |= BADW_TYPE_FAST_R;
|
|
}
|
|
#else
|
|
for (tmp = word->ce_vardata; *tmp; tmp++)
|
|
{
|
|
if (!isalnum(*tmp) && !(*tmp >= 128))
|
|
{
|
|
regex = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (regex)
|
|
{
|
|
ircstrdup(ca->word, word->ce_vardata);
|
|
}
|
|
else
|
|
{
|
|
ca->word = MyMalloc(strlen(word->ce_vardata) + strlen(PATTERN) -1);
|
|
ircsprintf(ca->word, PATTERN, word->ce_vardata);
|
|
}
|
|
/* Yes this is called twice, once in test, and once here, but it is still MUCH
|
|
faster than calling it each time a message is received like before. -- codemastr
|
|
*/
|
|
regcomp(&ca->expr, ca->word, regflags);
|
|
#endif
|
|
if (!strcmp(ce->ce_vardata, "channel"))
|
|
AddListItem(ca, conf_badword_channel);
|
|
else if (!strcmp(ce->ce_vardata, "message"))
|
|
AddListItem(ca, conf_badword_message);
|
|
else if (!strcmp(ce->ce_vardata, "quit"))
|
|
AddListItem(ca, conf_badword_quit);
|
|
else if (!strcmp(ce->ce_vardata, "all"))
|
|
{
|
|
AddListItem(ca, conf_badword_channel);
|
|
AddListItem(copy_badword_struct(ca,regex,regflags), conf_badword_message);
|
|
AddListItem(copy_badword_struct(ca,regex,regflags), conf_badword_quit);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _test_badword(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
int errors = 0;
|
|
ConfigEntry *cep;
|
|
char has_word = 0, has_replace = 0, has_action = 0, action = 'r';
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: badword without type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
else if (strcmp(ce->ce_vardata, "channel") && strcmp(ce->ce_vardata, "message") &&
|
|
strcmp(ce->ce_vardata, "quit") && strcmp(ce->ce_vardata, "all")) {
|
|
config_error("%s:%i: badword with unknown type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "badword"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "word"))
|
|
{
|
|
char *errbuf;
|
|
if (has_word)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "badword::word");
|
|
continue;
|
|
}
|
|
has_word = 1;
|
|
if ((errbuf = unreal_checkregex(cep->ce_vardata,1,1)))
|
|
{
|
|
config_error("%s:%i: badword::%s contains an invalid regex: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
cep->ce_varname, errbuf);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "replace"))
|
|
{
|
|
if (has_replace)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "badword::replace");
|
|
continue;
|
|
}
|
|
has_replace = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "action"))
|
|
{
|
|
if (has_action)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "badword::action");
|
|
continue;
|
|
}
|
|
has_action = 1;
|
|
if (!strcmp(cep->ce_vardata, "replace"))
|
|
action = 'r';
|
|
else if (!strcmp(cep->ce_vardata, "block"))
|
|
action = 'b';
|
|
else
|
|
{
|
|
config_error("%s:%d: Unknown badword::action '%s'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"badword", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
|
|
if (!has_word)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"badword::word");
|
|
errors++;
|
|
}
|
|
if (has_action)
|
|
{
|
|
if (has_replace && action == 'b')
|
|
{
|
|
config_error("%s:%i: badword::action is block but badword::replace exists",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
#endif
|
|
|
|
int _conf_spamfilter(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
aTKline *nl = MyMallocEx(sizeof(aTKline));
|
|
char *word = NULL, *reason = NULL, *bantime = NULL;
|
|
int action = 0, target = 0;
|
|
char has_reason = 0, has_bantime = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "regex"))
|
|
{
|
|
nl->reason = strdup(cep->ce_vardata);
|
|
|
|
word = cep->ce_vardata;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "target"))
|
|
{
|
|
if (cep->ce_vardata)
|
|
target = spamfilter_getconftargets(cep->ce_vardata);
|
|
else
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
target |= spamfilter_getconftargets(cepp->ce_varname);
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "action"))
|
|
{
|
|
action = banact_stringtoval(cep->ce_vardata);
|
|
nl->hostmask = strdup(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
has_reason = 1;
|
|
reason = cep->ce_vardata;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ban-time"))
|
|
{
|
|
has_bantime = 1;
|
|
bantime = cep->ce_vardata;
|
|
}
|
|
}
|
|
nl->type = TKL_SPAMF;
|
|
nl->expire_at = 0;
|
|
nl->set_at = TStime();
|
|
|
|
strncpyzt(nl->usermask, spamfilter_target_inttostring(target), sizeof(nl->usermask));
|
|
nl->subtype = target;
|
|
|
|
nl->setby = BadPtr(me.name) ? NULL : strdup(me.name); /* Hmm! */
|
|
nl->ptr.spamf = unreal_buildspamfilter(word);
|
|
nl->ptr.spamf->action = action;
|
|
|
|
if (has_reason && reason)
|
|
nl->ptr.spamf->tkl_reason = strdup(unreal_encodespace(reason));
|
|
else
|
|
nl->ptr.spamf->tkl_reason = strdup("<internally added by ircd>");
|
|
|
|
if (has_bantime)
|
|
nl->ptr.spamf->tkl_duration = config_checkval(bantime, CFG_TIME);
|
|
else
|
|
nl->ptr.spamf->tkl_duration = (SPAMFILTER_BAN_TIME ? SPAMFILTER_BAN_TIME : 86400);
|
|
|
|
AddListItem(nl, tklines[tkl_hash('f')]);
|
|
return 1;
|
|
}
|
|
|
|
int _test_spamfilter(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
int errors = 0;
|
|
char *regex = NULL, *reason = NULL;
|
|
char has_target = 0, has_regex = 0, has_action = 0, has_reason = 0, has_bantime = 0;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"spamfilter");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "target"))
|
|
{
|
|
if (has_target)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter::target");
|
|
continue;
|
|
}
|
|
has_target = 1;
|
|
if (cep->ce_vardata)
|
|
{
|
|
if (!spamfilter_getconftargets(cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: unknown spamfiler target type '%s'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (cep->ce_entries)
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
{
|
|
config_error_blank(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
"spamfilter::target");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!spamfilter_getconftargets(cepp->ce_varname))
|
|
{
|
|
config_error("%s:%i: unknown spamfiler target type '%s'",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
continue;
|
|
}
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"spamfilter", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
if (has_reason)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter::reason");
|
|
continue;
|
|
}
|
|
has_reason = 1;
|
|
reason = cep->ce_vardata;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "regex"))
|
|
{
|
|
char *errbuf;
|
|
if (has_regex)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter::regex");
|
|
continue;
|
|
}
|
|
has_regex = 1;
|
|
if ((errbuf = unreal_checkregex(cep->ce_vardata,0,0)))
|
|
{
|
|
config_error("%s:%i: spamfilter::regex contains an invalid regex: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
errbuf);
|
|
errors++;
|
|
continue;
|
|
}
|
|
regex = cep->ce_vardata;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "action"))
|
|
{
|
|
if (has_action)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter::action");
|
|
continue;
|
|
}
|
|
has_action = 1;
|
|
if (!banact_stringtoval(cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: spamfilter::action has unknown action type '%s'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ban-time"))
|
|
{
|
|
if (has_bantime)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "spamfilter::ban-time");
|
|
continue;
|
|
}
|
|
has_bantime = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"spamfilter", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!has_regex)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"spamfilter::regex");
|
|
errors++;
|
|
}
|
|
if (!has_target)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"spamfilter::target");
|
|
errors++;
|
|
}
|
|
if (!has_action)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"spamfilter::action");
|
|
errors++;
|
|
}
|
|
if (regex && reason && (strlen(regex) + strlen(reason) > 505))
|
|
{
|
|
config_error("%s:%i: spamfilter block problem: regex + reason field are together over 505 bytes, "
|
|
"please choose a shorter regex or reason",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
int _conf_help(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigItem_help *ca;
|
|
aMotd *last = NULL, *temp;
|
|
ca = MyMallocEx(sizeof(ConfigItem_help));
|
|
|
|
if (!ce->ce_vardata)
|
|
ca->command = NULL;
|
|
else
|
|
ca->command = strdup(ce->ce_vardata);
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
temp = MyMalloc(sizeof(aMotd));
|
|
temp->line = strdup(cep->ce_varname);
|
|
temp->next = NULL;
|
|
if (!ca->text)
|
|
ca->text = temp;
|
|
else
|
|
last->next = temp;
|
|
last = temp;
|
|
}
|
|
AddListItem(ca, conf_help);
|
|
return 1;
|
|
|
|
}
|
|
|
|
int _test_help(ConfigFile *conf, ConfigEntry *ce) {
|
|
int errors = 0;
|
|
ConfigEntry *cep;
|
|
if (!ce->ce_entries)
|
|
{
|
|
config_error("%s:%i: empty help block",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"help");
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_log(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
ConfigItem_log *ca;
|
|
OperFlag *ofp = NULL;
|
|
|
|
ca = MyMallocEx(sizeof(ConfigItem_log));
|
|
ircstrdup(ca->file, ce->ce_vardata);
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "maxsize"))
|
|
{
|
|
ca->maxsize = config_checkval(cep->ce_vardata,CFG_SIZE);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if ((ofp = config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags))))
|
|
ca->flags |= ofp->flag;
|
|
}
|
|
}
|
|
}
|
|
AddListItem(ca, conf_log);
|
|
return 1;
|
|
|
|
}
|
|
|
|
int _test_log(ConfigFile *conf, ConfigEntry *ce) {
|
|
int errors = 0;
|
|
ConfigEntry *cep, *cepp;
|
|
char has_flags = 0, has_maxsize = 0;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: log block without filename",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!ce->ce_entries)
|
|
{
|
|
config_error("%s:%i: empty log block",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"log");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
if (has_flags)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "log::flags");
|
|
continue;
|
|
}
|
|
has_flags = 1;
|
|
if (!cep->ce_entries)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "log", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
{
|
|
config_error_blank(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "log::flags");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags)))
|
|
{
|
|
config_error_unknownflag(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "log", cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxsize"))
|
|
{
|
|
if (has_maxsize)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "log::maxsize");
|
|
continue;
|
|
}
|
|
has_maxsize = 1;
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "log", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"log", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
if (!has_flags)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"log::flags");
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
|
|
int _conf_link(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
ConfigItem_link *link = NULL;
|
|
OperFlag *ofp;
|
|
|
|
link = (ConfigItem_link *) MyMallocEx(sizeof(ConfigItem_link));
|
|
link->servername = strdup(ce->ce_vardata);
|
|
/* ugly, but it works. if it fails, we know _test_link failed miserably */
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "username"))
|
|
link->username = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
link->hostname = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "bind-ip"))
|
|
link->bindip = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "port"))
|
|
link->port = atol(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "password-receive"))
|
|
link->recvauth = Auth_ConvertConf2AuthStruct(cep);
|
|
else if (!strcmp(cep->ce_varname, "password-connect"))
|
|
link->connpwd = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
link->class = Find_class(cep->ce_vardata);
|
|
if (!link->class || (link->class->flag.temporary == 1))
|
|
{
|
|
config_status("%s:%i: illegal link::class, unknown class '%s' using default of class 'default'",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
link->class = default_class;
|
|
}
|
|
link->class->xrefcount++;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
link->options = 0;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if ((ofp = config_binary_flags_search(_LinkFlags, cepp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
|
|
link->options |= ofp->flag;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hub"))
|
|
link->hubmask = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "leaf"))
|
|
link->leafmask = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "leafdepth"))
|
|
link->leafdepth = atol(cep->ce_vardata);
|
|
#ifdef USE_SSL
|
|
else if (!strcmp(cep->ce_varname, "ciphers"))
|
|
link->ciphers = strdup(cep->ce_vardata);
|
|
#endif
|
|
#ifdef ZIP_LINKS
|
|
else if (!strcmp(cep->ce_varname, "compression-level"))
|
|
link->compression_level = atoi(cep->ce_vardata);
|
|
#endif
|
|
}
|
|
AddListItem(link, conf_link);
|
|
return 0;
|
|
}
|
|
|
|
int _test_link(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
OperFlag *ofp;
|
|
int errors = 0;
|
|
char has_username = 0, has_hostname = 0, has_bindip = 0, has_port = 0;
|
|
char has_passwordreceive = 0, has_passwordconnect = 0, has_class = 0;
|
|
char has_hub = 0, has_leaf = 0, has_leafdepth = 0, has_ciphers = 0;
|
|
char has_options = 0;
|
|
char has_autoconnect = 0;
|
|
char has_hostname_wildcards = 0;
|
|
#ifdef ZIP_LINKS
|
|
char has_compressionlevel = 0;
|
|
#endif
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: link without servername",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
|
|
}
|
|
if (!strchr(ce->ce_vardata, '.'))
|
|
{
|
|
config_error("%s:%i: link: bogus server name",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"link");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
if (has_options)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::options");
|
|
continue;
|
|
}
|
|
has_options = 1;
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
{
|
|
config_error_blank(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "link::options");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!(ofp = config_binary_flags_search(_LinkFlags, cepp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "link", cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
#ifndef USE_SSL
|
|
if (ofp->flag == CONNECT_SSL)
|
|
{
|
|
config_error("%s:%i: link %s with SSL option enabled on a non-SSL compile",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, ce->ce_vardata);
|
|
errors++;
|
|
}
|
|
#endif
|
|
#ifndef ZIP_LINKS
|
|
if (ofp->flag == CONNECT_ZIP)
|
|
{
|
|
config_error("%s:%i: link %s with ZIP option enabled on a non-ZIP compile",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, ce->ce_vardata);
|
|
errors++;
|
|
}
|
|
#endif
|
|
if (ofp->flag == CONNECT_AUTO)
|
|
{
|
|
has_autoconnect = 1;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"link", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "username"))
|
|
{
|
|
if (has_username)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::username");
|
|
continue;
|
|
}
|
|
has_username = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
{
|
|
if (has_hostname)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::hostname");
|
|
continue;
|
|
}
|
|
has_hostname = 1;
|
|
#ifdef INET6
|
|
/* I'm nice... I'll help those poor ipv6 users. -- Syzop */
|
|
/* [ not null && len>6 && has not a : in it && last character is a digit ] */
|
|
if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
|
|
isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
|
|
{
|
|
char crap[32];
|
|
if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
|
|
{
|
|
char ipv6buf[48];
|
|
snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
|
|
MyFree(cep->ce_vardata);
|
|
cep->ce_vardata = strdup(ipv6buf);
|
|
} else {
|
|
/* Insert IPv6 validation here */
|
|
config_error( "%s:%i: listen: '%s' looks like "
|
|
"it might be IPv4, but is not a valid address.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
if (strchr(cep->ce_vardata, '*') != NULL || strchr(cep->ce_vardata, '?'))
|
|
{
|
|
has_hostname_wildcards = 1;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "bind-ip"))
|
|
{
|
|
if (has_bindip)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::bind-ip");
|
|
continue;
|
|
}
|
|
has_bindip = 1;
|
|
#ifdef INET6
|
|
/* I'm nice... I'll help those poor ipv6 users. -- Syzop */
|
|
/* [ not null && len>6 && has not a : in it && last character is a digit ] */
|
|
if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
|
|
isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
|
|
{
|
|
char crap[32];
|
|
if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
|
|
{
|
|
char ipv6buf[48];
|
|
snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
|
|
MyFree(cep->ce_vardata);
|
|
cep->ce_vardata = strdup(ipv6buf);
|
|
} else {
|
|
/* Insert IPv6 validation here */
|
|
config_error( "%s:%i: bind-ip: '%s' looks like "
|
|
"it might be IPv4, but is not a valid address.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "port"))
|
|
{
|
|
if (has_port)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::port");
|
|
continue;
|
|
}
|
|
has_port = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "password-receive"))
|
|
{
|
|
if (has_passwordreceive)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::password-receive");
|
|
continue;
|
|
}
|
|
has_passwordreceive = 1;
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "password-connect"))
|
|
{
|
|
if (has_passwordconnect)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::password-connect");
|
|
continue;
|
|
}
|
|
has_passwordconnect = 1;
|
|
if (cep->ce_entries)
|
|
{
|
|
config_error("%s:%i: link::password-connect cannot be encrypted",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "class"))
|
|
{
|
|
if (has_class)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::class");
|
|
continue;
|
|
}
|
|
has_class = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hub"))
|
|
{
|
|
if (has_hub)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::hub");
|
|
continue;
|
|
}
|
|
has_hub = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "leaf"))
|
|
{
|
|
if (has_leaf)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::leaf");
|
|
continue;
|
|
}
|
|
has_leaf = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "leafdepth"))
|
|
{
|
|
if (has_leafdepth)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::leafdepth");
|
|
continue;
|
|
}
|
|
has_leafdepth = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ciphers"))
|
|
{
|
|
if (has_ciphers)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::ciphers");
|
|
continue;
|
|
}
|
|
has_ciphers = 1;
|
|
}
|
|
#ifdef ZIP_LINKS
|
|
else if (!strcmp(cep->ce_varname, "compression-level"))
|
|
{
|
|
if (has_compressionlevel)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "link::compression-level");
|
|
continue;
|
|
}
|
|
has_compressionlevel = 1;
|
|
if ((atoi(cep->ce_vardata) < 1) || (atoi(cep->ce_vardata) > 9))
|
|
{
|
|
config_error("%s:%i: compression-level should be in range 1..9",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"link", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_username)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::username");
|
|
errors++;
|
|
}
|
|
if (!has_hostname)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::hostname");
|
|
errors++;
|
|
}
|
|
if (!has_port)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::port");
|
|
errors++;
|
|
}
|
|
if (!has_passwordreceive)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::password-receive");
|
|
errors++;
|
|
}
|
|
if (!has_passwordconnect)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::password-connect");
|
|
errors++;
|
|
}
|
|
if (!has_class)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"link::class");
|
|
errors++;
|
|
}
|
|
if (has_autoconnect && has_hostname_wildcards)
|
|
{
|
|
config_error("%s:%i: link block with autoconnect and wildcards (* and/or ? in hostname)",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
if (errors > 0)
|
|
return errors;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "options"))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
return errors;
|
|
|
|
}
|
|
|
|
int _conf_cgiirc(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
ConfigEntry *cepp;
|
|
ConfigItem_cgiirc *cgiirc = NULL;
|
|
|
|
cgiirc = (ConfigItem_cgiirc *) MyMallocEx(sizeof(ConfigItem_cgiirc));
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "username"))
|
|
cgiirc->username = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
cgiirc->hostname = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
cgiirc->auth = Auth_ConvertConf2AuthStruct(cep);
|
|
else if (!strcmp(cep->ce_varname, "type"))
|
|
{
|
|
if (!strcmp(cep->ce_vardata, "webirc"))
|
|
cgiirc->type = CGIIRC_WEBIRC;
|
|
else if (!strcmp(cep->ce_vardata, "old"))
|
|
cgiirc->type = CGIIRC_PASS;
|
|
else
|
|
abort();
|
|
}
|
|
}
|
|
AddListItem(cgiirc, conf_cgiirc);
|
|
return 0;
|
|
}
|
|
|
|
int _test_cgiirc(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
OperFlag *ofp;
|
|
int errors = 0;
|
|
char has_username = 0; /* dup checking only, not mandatory */
|
|
char has_type = 0; /* mandatory */
|
|
char has_hostname = 0; /* mandatory */
|
|
char has_password = 0; /* mandatory */
|
|
CGIIRCType type;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, "cgiirc");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!cep->ce_vardata)
|
|
{
|
|
config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"cgiirc", cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "username"))
|
|
{
|
|
if (has_username)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "cgiirc::username");
|
|
continue;
|
|
}
|
|
has_username = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hostname"))
|
|
{
|
|
if (has_hostname)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "cgiirc::hostname");
|
|
continue;
|
|
}
|
|
has_hostname = 1;
|
|
#ifdef INET6
|
|
/* I'm nice... I'll help those poor ipv6 users. -- Syzop */
|
|
/* [ not null && len>6 && has not a : in it && last character is a digit ] */
|
|
if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
|
|
isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
|
|
{
|
|
char crap[32];
|
|
if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
|
|
{
|
|
char ipv6buf[48];
|
|
snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
|
|
MyFree(cep->ce_vardata);
|
|
cep->ce_vardata = strdup(ipv6buf);
|
|
} else {
|
|
/* Insert IPv6 validation here */
|
|
config_error( "%s:%i: cgiirc::hostname: '%s' looks like "
|
|
"it might be IPv4, but is not a valid address.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "password"))
|
|
{
|
|
if (has_password)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "cgiirc::password");
|
|
continue;
|
|
}
|
|
has_password = 1;
|
|
if (Auth_CheckError(cep) < 0)
|
|
errors++;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type"))
|
|
{
|
|
if (has_type)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "cgiirc::type");
|
|
}
|
|
has_type = 1;
|
|
if (!strcmp(cep->ce_vardata, "webirc"))
|
|
type = CGIIRC_WEBIRC;
|
|
else if (!strcmp(cep->ce_vardata, "old"))
|
|
type = CGIIRC_PASS;
|
|
else
|
|
{
|
|
config_error("%s:%i: unknown cgiirc::type '%s', should be either 'webirc' or 'old'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"cgiirc", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_hostname)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"cgiirc::hostname");
|
|
errors++;
|
|
}
|
|
if (!has_type)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"cgiirc::type");
|
|
errors++;
|
|
} else
|
|
{
|
|
if (!has_password && (type == CGIIRC_WEBIRC))
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"cgiirc::password");
|
|
errors++;
|
|
} else
|
|
if (has_password && (type == CGIIRC_PASS))
|
|
{
|
|
config_error("%s:%i: cgiirc block has type set to 'old' but has a password set. "
|
|
"Passwords are not used with type 'old'. Either remove the password or "
|
|
"use the 'webirc' method instead.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
int _conf_ban(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
|
|
ConfigEntry *cep;
|
|
ConfigItem_ban *ca;
|
|
Hook *h;
|
|
|
|
ca = MyMallocEx(sizeof(ConfigItem_ban));
|
|
if (!strcmp(ce->ce_vardata, "nick"))
|
|
{
|
|
aTKline *nl = MyMallocEx(sizeof(aTKline));
|
|
nl->type = TKL_NICK;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
nl->hostmask = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
nl->reason = strdup(cep->ce_vardata);
|
|
}
|
|
strcpy(nl->usermask, "*");
|
|
AddListItem(nl, tklines[tkl_hash('q')]);
|
|
free(ca);
|
|
return 0;
|
|
}
|
|
else if (!strcmp(ce->ce_vardata, "ip"))
|
|
ca->flag.type = CONF_BAN_IP;
|
|
else if (!strcmp(ce->ce_vardata, "server"))
|
|
ca->flag.type = CONF_BAN_SERVER;
|
|
else if (!strcmp(ce->ce_vardata, "user"))
|
|
ca->flag.type = CONF_BAN_USER;
|
|
else if (!strcmp(ce->ce_vardata, "realname"))
|
|
ca->flag.type = CONF_BAN_REALNAME;
|
|
else if (!strcmp(ce->ce_vardata, "version"))
|
|
{
|
|
ca->flag.type = CONF_BAN_VERSION;
|
|
tempiConf.use_ban_version = 1;
|
|
}
|
|
else {
|
|
int value;
|
|
free(ca); /* ca isn't used, modules have their own list. */
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
ca->mask = strdup(cep->ce_vardata);
|
|
if (ca->flag.type == CONF_BAN_IP || ca->flag.type == CONF_BAN_USER)
|
|
{
|
|
struct irc_netmask tmp;
|
|
tmp.type = parse_netmask(ca->mask, &tmp);
|
|
if (tmp.type != HM_HOST)
|
|
{
|
|
ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
|
|
bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
ca->reason = strdup(cep->ce_vardata);
|
|
else if (!strcmp(cep->ce_varname, "action"))
|
|
ca ->action = banact_stringtoval(cep->ce_vardata);
|
|
}
|
|
AddListItem(ca, conf_ban);
|
|
return 0;
|
|
}
|
|
|
|
int _test_ban(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
Hook *h;
|
|
char type = 0;
|
|
char has_mask = 0, has_action = 0, has_reason = 0;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: ban without type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!strcmp(ce->ce_vardata, "nick"))
|
|
{}
|
|
else if (!strcmp(ce->ce_vardata, "ip"))
|
|
{}
|
|
else if (!strcmp(ce->ce_vardata, "server"))
|
|
{}
|
|
else if (!strcmp(ce->ce_vardata, "user"))
|
|
{}
|
|
else if (!strcmp(ce->ce_vardata, "realname"))
|
|
{}
|
|
else if (!strcmp(ce->ce_vardata, "version"))
|
|
type = 'v';
|
|
else
|
|
{
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN, &errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
}
|
|
if (!used) {
|
|
config_error("%s:%i: unknown ban type %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return 1;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "ban"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "ban::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
if (has_reason)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "ban::reason");
|
|
continue;
|
|
}
|
|
has_reason = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "action"))
|
|
{
|
|
if (has_action)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "ban::action");
|
|
}
|
|
has_action = 1;
|
|
if (!banact_stringtoval(cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: ban::action has unknown action type '%s'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"ban::mask");
|
|
errors++;
|
|
}
|
|
if (!has_reason)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"ban::reason");
|
|
errors++;
|
|
}
|
|
if (has_action && type != 'v')
|
|
{
|
|
config_error("%s:%d: ban::action specified even though type is not 'version'",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_set(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp, *ceppp;
|
|
OperFlag *ofl = NULL;
|
|
Hook *h;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "kline-address")) {
|
|
ircstrdup(tempiConf.kline_address, cep->ce_vardata);
|
|
}
|
|
if (!strcmp(cep->ce_varname, "gline-address")) {
|
|
ircstrdup(tempiConf.gline_address, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
|
|
tempiConf.conn_modes = (long) set_usermode(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
|
|
tempiConf.oper_modes = (long) set_usermode(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-join")) {
|
|
set_channelmodes(cep->ce_vardata, &tempiConf.modes_on_join, 0);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
|
|
ircstrdup(tempiConf.oper_snomask, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
|
|
ircstrdup(tempiConf.user_snomask, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "level-on-join")) {
|
|
tempiConf.level_on_join = channellevel_to_int(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "static-quit")) {
|
|
ircstrdup(tempiConf.static_quit, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "static-part")) {
|
|
ircstrdup(tempiConf.static_part, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "who-limit")) {
|
|
tempiConf.who_limit = atol(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxbans")) {
|
|
tempiConf.maxbans = atol(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxbanlength")) {
|
|
tempiConf.maxbanlength = atol(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "silence-limit")) {
|
|
tempiConf.silence_limit = atol(cep->ce_vardata);
|
|
if (loop.ircd_booted)
|
|
IsupportSetValue(IsupportFind("SILENCE"), cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "auto-join")) {
|
|
ircstrdup(tempiConf.auto_join_chans, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
|
|
ircstrdup(tempiConf.oper_auto_join_chans, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
|
|
tempiConf.check_target_nick_bans = config_checkval(cep->ce_vardata, CFG_YESNO);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "pingpong-warning")) {
|
|
tempiConf.pingpong_warning = config_checkval(cep->ce_vardata, CFG_YESNO);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
|
|
tempiConf.watch_away_notification = config_checkval(cep->ce_vardata, CFG_YESNO);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
|
|
if (!stricmp(cep->ce_vardata, "always"))
|
|
tempiConf.userhost_allowed = UHALLOW_ALWAYS;
|
|
else if (!stricmp(cep->ce_vardata, "never"))
|
|
tempiConf.userhost_allowed = UHALLOW_NEVER;
|
|
else if (!stricmp(cep->ce_vardata, "not-on-channels"))
|
|
tempiConf.userhost_allowed = UHALLOW_NOCHANS;
|
|
else
|
|
tempiConf.userhost_allowed = UHALLOW_REJOIN;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
|
|
charsys_add_language(cepp->ce_varname);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
|
|
ircstrdup(tempiConf.channel_command_prefix, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-usermodes")) {
|
|
int i;
|
|
char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
|
|
/* The data should be something like 'Gw' or something,
|
|
* but just in case users use '+Gw' then ignore the + (and -).
|
|
*/
|
|
for (i=0; i < strlen(cep->ce_vardata); i++)
|
|
if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
|
|
*x++ = cep->ce_vardata[i];
|
|
*x = '\0';
|
|
tempiConf.restrict_usermodes = p;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-channelmodes")) {
|
|
int i;
|
|
char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
|
|
/* The data should be something like 'GL' or something,
|
|
* but just in case users use '+GL' then ignore the + (and -).
|
|
*/
|
|
for (i=0; i < strlen(cep->ce_vardata); i++)
|
|
if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
|
|
*x++ = cep->ce_vardata[i];
|
|
*x = '\0';
|
|
tempiConf.restrict_channelmodes = p;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-extendedbans")) {
|
|
ircstrdup(tempiConf.restrict_extendedbans, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "new-linking-protocol")) {
|
|
tempiConf.new_linking_protocol = atoi(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
|
|
tempiConf.anti_spam_quit_message_time = config_checkval(cep->ce_vardata,CFG_TIME);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
|
|
if (!cep->ce_entries)
|
|
{
|
|
ircstrdup(tempiConf.oper_only_stats, cep->ce_vardata);
|
|
}
|
|
else
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
OperStat *os = MyMallocEx(sizeof(OperStat));
|
|
ircstrdup(os->flag, cepp->ce_varname);
|
|
AddListItem(os, tempiConf.oper_only_stats_ext);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
|
|
tempiConf.maxchannelsperuser = atoi(cep->ce_vardata);
|
|
if (loop.ircd_booted)
|
|
{
|
|
char tmpbuf[512];
|
|
IsupportSetValue(IsupportFind("MAXCHANNELS"), cep->ce_vardata);
|
|
ircsprintf(tmpbuf, "#:%s", cep->ce_vardata);
|
|
IsupportSetValue(IsupportFind("CHANLIMIT"), tmpbuf);
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxdccallow")) {
|
|
tempiConf.maxdccallow = atoi(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "network-name")) {
|
|
char *tmp;
|
|
ircstrdup(tempiConf.network.x_ircnetwork, cep->ce_vardata);
|
|
for (tmp = cep->ce_vardata; *cep->ce_vardata; cep->ce_vardata++) {
|
|
if (*cep->ce_vardata == ' ')
|
|
*cep->ce_vardata='-';
|
|
}
|
|
ircstrdup(tempiConf.network.x_ircnet005, tmp);
|
|
if (loop.ircd_booted)
|
|
IsupportSetValue(IsupportFind("NETWORK"), tmp);
|
|
cep->ce_vardata = tmp;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "default-server")) {
|
|
ircstrdup(tempiConf.network.x_defserv, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "services-server")) {
|
|
ircstrdup(tempiConf.network.x_services_name, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "stats-server")) {
|
|
ircstrdup(tempiConf.network.x_stats_server, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "help-channel")) {
|
|
ircstrdup(tempiConf.network.x_helpchan, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
|
|
ircstrdup(tempiConf.network.x_hidden_host, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "prefix-quit")) {
|
|
if (*cep->ce_vardata == '0')
|
|
{
|
|
ircstrdup(tempiConf.network.x_prefix_quit, "");
|
|
}
|
|
else
|
|
ircstrdup(tempiConf.network.x_prefix_quit, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "dns")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "timeout")) {
|
|
tempiConf.host_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "retries")) {
|
|
tempiConf.host_retries = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "nameserver")) {
|
|
ircstrdup(tempiConf.name_server, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "bind-ip")) {
|
|
ircstrdup(tempiConf.dns_bindip, cepp->ce_vardata);
|
|
}
|
|
}
|
|
}
|
|
#ifdef THROTTLING
|
|
else if (!strcmp(cep->ce_varname, "throttle")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "period"))
|
|
tempiConf.throttle_period = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
else if (!strcmp(cepp->ce_varname, "connections"))
|
|
tempiConf.throttle_count = atoi(cepp->ce_vardata);
|
|
}
|
|
}
|
|
#endif
|
|
else if (!strcmp(cep->ce_varname, "anti-flood")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
|
|
tempiConf.unknown_flood_bantime = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
|
|
tempiConf.unknown_flood_amount = atol(cepp->ce_vardata);
|
|
#ifdef NO_FLOOD_AWAY
|
|
else if (!strcmp(cepp->ce_varname, "away-count"))
|
|
tempiConf.away_count = atol(cepp->ce_vardata);
|
|
else if (!strcmp(cepp->ce_varname, "away-period"))
|
|
tempiConf.away_period = config_checkval(cepp->ce_vardata, CFG_TIME);
|
|
else if (!strcmp(cepp->ce_varname, "away-flood"))
|
|
{
|
|
int cnt, period;
|
|
config_parse_flood(cepp->ce_vardata, &cnt, &period);
|
|
tempiConf.away_count = cnt;
|
|
tempiConf.away_period = period;
|
|
}
|
|
#endif
|
|
else if (!strcmp(cepp->ce_varname, "nick-flood"))
|
|
{
|
|
int cnt, period;
|
|
config_parse_flood(cepp->ce_vardata, &cnt, &period);
|
|
tempiConf.nick_count = cnt;
|
|
tempiConf.nick_period = period;
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "options")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "webtv-support")) {
|
|
tempiConf.webtv_support = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "hide-ulines")) {
|
|
tempiConf.hide_ulines = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "flat-map")) {
|
|
tempiConf.flat_map = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "no-stealth")) {
|
|
tempiConf.no_oper_hiding = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
|
|
tempiConf.som = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "identd-check")) {
|
|
tempiConf.ident_check = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
|
|
tempiConf.fail_oper_warn = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
|
|
tempiConf.show_connect_info = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
|
|
tempiConf.dont_resolve = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
|
|
tempiConf.mkpasswd_for_everyone = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
|
|
tempiConf.allow_part_if_shunned = 1;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hosts")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "local")) {
|
|
ircstrdup(tempiConf.network.x_locop_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "global")) {
|
|
ircstrdup(tempiConf.network.x_oper_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "coadmin")) {
|
|
ircstrdup(tempiConf.network.x_coadmin_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "admin")) {
|
|
ircstrdup(tempiConf.network.x_admin_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "servicesadmin")) {
|
|
ircstrdup(tempiConf.network.x_sadmin_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "netadmin")) {
|
|
ircstrdup(tempiConf.network.x_netadmin_host, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "host-on-oper-up")) {
|
|
tempiConf.network.x_inah = config_checkval(cepp->ce_vardata,CFG_YESNO);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "cloak-keys"))
|
|
{
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
int value;
|
|
value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ident"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "connect-timeout"))
|
|
tempiConf.ident_connect_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
if (!strcmp(cepp->ce_varname, "read-timeout"))
|
|
tempiConf.ident_read_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "enabled"))
|
|
tempiConf.timesynch_enabled = config_checkval(cepp->ce_vardata,CFG_YESNO);
|
|
else if (!strcmp(cepp->ce_varname, "timeout"))
|
|
tempiConf.timesynch_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
else if (!strcmp(cepp->ce_varname, "server"))
|
|
ircstrdup(tempiConf.timesynch_server, cepp->ce_vardata);
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "spamfilter"))
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "ban-time"))
|
|
tempiConf.spamfilter_ban_time = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
else if (!strcmp(cepp->ce_varname, "ban-reason"))
|
|
ircstrdup(tempiConf.spamfilter_ban_reason, cepp->ce_vardata);
|
|
else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
|
|
ircstrdup(tempiConf.spamfilter_virus_help_channel, cepp->ce_vardata);
|
|
else if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
|
|
tempiConf.spamfilter_vchan_deny = config_checkval(cepp->ce_vardata,CFG_YESNO);
|
|
else if (!strcmp(cepp->ce_varname, "except"))
|
|
{
|
|
char *name, *p;
|
|
SpamExcept *e;
|
|
ircstrdup(tempiConf.spamexcept_line, cepp->ce_vardata);
|
|
for (name = strtoken(&p, cepp->ce_vardata, ","); name; name = strtoken(&p, NULL, ","))
|
|
{
|
|
if (*name == ' ')
|
|
name++;
|
|
if (*name)
|
|
{
|
|
e = MyMallocEx(sizeof(SpamExcept) + strlen(name));
|
|
strcpy(e->name, name);
|
|
AddListItem(e, tempiConf.spamexcept);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
|
|
{
|
|
tempiConf.spamfilter_detectslow_warn = atol(cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
|
|
{
|
|
tempiConf.spamfilter_detectslow_fatal = atol(cepp->ce_vardata);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "default-bantime"))
|
|
{
|
|
tempiConf.default_bantime = config_checkval(cep->ce_vardata,CFG_TIME);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ban-version-tkl-time"))
|
|
{
|
|
tempiConf.ban_version_tkl_time = config_checkval(cep->ce_vardata,CFG_TIME);
|
|
}
|
|
#ifdef NEWCHFLOODPROT
|
|
else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
|
|
int v = atoi(cep->ce_vardata);
|
|
tempiConf.modef_default_unsettime = (unsigned char)v;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
|
|
int v = atoi(cep->ce_vardata);
|
|
tempiConf.modef_max_unsettime = (unsigned char)v;
|
|
}
|
|
#endif
|
|
else if (!strcmp(cep->ce_varname, "ssl")) {
|
|
#ifdef USE_SSL
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "egd")) {
|
|
tempiConf.use_egd = 1;
|
|
if (cepp->ce_vardata)
|
|
tempiConf.egd_path = strdup(cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
|
|
{
|
|
ircstrdup(tempiConf.x_server_cipher_list, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "certificate"))
|
|
{
|
|
ircstrdup(tempiConf.x_server_cert_pem, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "key"))
|
|
{
|
|
ircstrdup(tempiConf.x_server_key_pem, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
|
|
{
|
|
ircstrdup(tempiConf.trusted_ca_file, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
|
|
{
|
|
tempiConf.ssl_renegotiate_bytes = config_checkval(cepp->ce_vardata, CFG_SIZE);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
|
|
{
|
|
tempiConf.ssl_renegotiate_timeout = config_checkval(cepp->ce_vardata, CFG_TIME);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "options"))
|
|
{
|
|
tempiConf.ssl_options = 0;
|
|
for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
|
|
{
|
|
for (ofl = _SSLFlags; ofl->name; ofl++)
|
|
{
|
|
if (!strcmp(ceppp->ce_varname, ofl->name))
|
|
{
|
|
tempiConf.ssl_options |= ofl->flag;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (tempiConf.ssl_options & SSLFLAG_DONOTACCEPTSELFSIGNED)
|
|
if (!tempiConf.ssl_options & SSLFLAG_VERIFYCERT)
|
|
tempiConf.ssl_options |= SSLFLAG_VERIFYCERT;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
int value;
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(conf,cep,CONFIG_SET);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _test_set(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp, *ceppp;
|
|
OperFlag *ofl = NULL;
|
|
long templong;
|
|
int tempi;
|
|
int errors = 0;
|
|
Hook *h;
|
|
#define CheckNull(x) if ((!(x)->ce_vardata) || (!(*((x)->ce_vardata)))) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
|
|
#define CheckDuplicate(cep, name, display) if (settings.has_##name) { config_warn_duplicate((cep)->ce_fileptr->cf_filename, cep->ce_varlinenum, "set::" display); continue; } else settings.has_##name = 1
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!cep->ce_varname)
|
|
{
|
|
config_error_blank(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "set");
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "kline-address")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, kline_address, "kline-address");
|
|
if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
|
|
{
|
|
config_error("%s:%i: set::kline-address must be an e-mail or an URL",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: set::kline-address may not be an UnrealIRCd Team address",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++; continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "gline-address")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, gline_address, "gline-address");
|
|
if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
|
|
{
|
|
config_error("%s:%i: set::gline-address must be an e-mail or an URL",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: set::gline-address may not be an UnrealIRCd Team address",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++; continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
|
|
char *p;
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, modes_on_connect, "modes-on-connect");
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if (strchr("oOaANCrzSgHhqtW", *p))
|
|
{
|
|
config_error("%s:%i: set::modes-on-connect may not include mode '%c'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
|
|
errors++;
|
|
}
|
|
templong = (long) set_usermode(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-join")) {
|
|
char *c;
|
|
struct ChMode temp;
|
|
bzero(&temp, sizeof(temp));
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, modes_on_join, "modes-on-join");
|
|
for (c = cep->ce_vardata; *c; c++)
|
|
{
|
|
if (*c == ' ')
|
|
break; /* don't check the parameter ;p */
|
|
switch (*c)
|
|
{
|
|
case 'q':
|
|
case 'a':
|
|
case 'o':
|
|
case 'h':
|
|
case 'v':
|
|
case 'b':
|
|
case 'e':
|
|
case 'I':
|
|
case 'O':
|
|
case 'A':
|
|
case 'z':
|
|
case 'l':
|
|
case 'k':
|
|
case 'L':
|
|
config_error("%s:%i: set::modes-on-join contains +%c",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *c);
|
|
errors++;
|
|
break;
|
|
}
|
|
}
|
|
set_channelmodes(cep->ce_vardata, &temp, 1);
|
|
if (temp.mode & MODE_NOKNOCK && !(temp.mode & MODE_INVITEONLY))
|
|
{
|
|
config_error("%s:%i: set::modes-on-join has +K but not +i",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
if (temp.mode & MODE_NOCOLOR && temp.mode & MODE_STRIP)
|
|
{
|
|
config_error("%s:%i: set::modes-on-join has +c and +S",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
if (temp.mode & MODE_SECRET && temp.mode & MODE_PRIVATE)
|
|
{
|
|
config_error("%s:%i: set::modes-on-join has +s and +p",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
|
|
char *p;
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, modes_on_oper, "modes-on-oper");
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if (strchr("oOaANCrzS", *p))
|
|
{
|
|
config_error("%s:%i: set::modes-on-oper may not include mode '%c'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
|
|
errors++;
|
|
}
|
|
templong = (long) set_usermode(cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, snomask_on_oper, "snomask-on-oper");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, snomask_on_connect, "snomask-on-connect");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "level-on-join")) {
|
|
char *p;
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, level_on_join, "level-on-join");
|
|
if (!channellevel_to_int(cep->ce_vardata))
|
|
{
|
|
config_error("%s:%i: set::level-on-join: unknown value '%s', should be one of: none, voice, halfop, op, protect, owner",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "static-quit")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, static_quit, "static-quit");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "static-part")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, static_part, "static-part");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "who-limit")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, who_limit, "who-limit");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxbans")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, maxbans, "maxbans");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxbanlength")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, maxbanlength, "maxbanlength");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "silence-limit")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, silence_limit, "silence-limit");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "auto-join")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, auto_join, "auto-join");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, oper_auto_join, "oper-auto-join");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, check_target_nick_bans, "check-target-nick-bans");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "pingpong-warning")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, pingpong_warning, "pingpong-warning");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, watch_away_notification, "watch-away-notification");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, channel_command_prefix, "channel-command-prefix");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, allow_userhost_change, "allow-userhost-change");
|
|
if (stricmp(cep->ce_vardata, "always") &&
|
|
stricmp(cep->ce_vardata, "never") &&
|
|
stricmp(cep->ce_vardata, "not-on-channels") &&
|
|
stricmp(cep->ce_vardata, "force-rejoin"))
|
|
{
|
|
config_error("%s:%i: set::allow-userhost-change is invalid",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
|
|
if (cep->ce_vardata)
|
|
{
|
|
config_error("%s:%i: set::allowed-nickchars: please use 'allowed-nickchars { name; };' "
|
|
"and not 'allowed-nickchars name;'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
|
|
{
|
|
if (!charsys_test_language(cepp->ce_varname))
|
|
{
|
|
config_error("%s:%i: set::allowed-nickchars: Unknown (sub)language '%s'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, anti_spam_quit_message_time, "anti-spam-quit-message-time");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
|
|
CheckDuplicate(cep, oper_only_stats, "oper-only-stats");
|
|
if (!cep->ce_entries)
|
|
{
|
|
CheckNull(cep);
|
|
}
|
|
else
|
|
{
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!cepp->ce_varname)
|
|
config_error("%s:%i: blank set::oper-only-stats item",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, maxchannelsperuser, "maxchannelsperuser");
|
|
tempi = atoi(cep->ce_vardata);
|
|
if (tempi < 1)
|
|
{
|
|
config_error("%s:%i: set::maxchannelsperuser must be > 0",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "maxdccallow")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, maxdccallow, "maxdccallow");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "network-name")) {
|
|
char *p;
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, network_name, "network-name");
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if ((*p < ' ') || (*p > '~'))
|
|
{
|
|
config_error("%s:%i: set::network-name can only contain ASCII characters 33-126. Invalid character = '%c'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
|
|
errors++;
|
|
break;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "default-server")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, default_server, "default-server");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "services-server")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, services_server, "services-server");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "stats-server")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, stats_server, "stats-server");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "help-channel")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, help_channel, "help-channel");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, hiddenhost_prefix, "hiddenhost-prefix");
|
|
if (strchr(cep->ce_vardata, ' ') || (*cep->ce_vardata == ':'))
|
|
{
|
|
config_error("%s:%i: set::hiddenhost-prefix must not contain spaces or be prefixed with ':'",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "prefix-quit")) {
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, prefix_quit, "prefix-quit");
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-usermodes"))
|
|
{
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, restrict_usermodes, "restrict-usermodes");
|
|
if (cep->ce_varname) {
|
|
int warn = 0;
|
|
char *p;
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if ((*p == '+') || (*p == '-'))
|
|
warn = 1;
|
|
if (warn) {
|
|
config_status("%s:%i: warning: set::restrict-usermodes: should only contain modechars, no + or -.\n",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-channelmodes"))
|
|
{
|
|
CheckNull(cep);
|
|
CheckDuplicate(cep, restrict_channelmodes, "restrict-channelmodes");
|
|
if (cep->ce_varname) {
|
|
int warn = 0;
|
|
char *p;
|
|
for (p = cep->ce_vardata; *p; p++)
|
|
if ((*p == '+') || (*p == '-'))
|
|
warn = 1;
|
|
if (warn) {
|
|
config_status("%s:%i: warning: set::restrict-channelmodes: should only contain modechars, no + or -.\n",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "restrict-extendedbans"))
|
|
{
|
|
CheckDuplicate(cep, restrict_extendedbans, "restrict-extendedbans");
|
|
CheckNull(cep);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "new-linking-protocol"))
|
|
{
|
|
CheckDuplicate(cep, new_linking_protocol, "new-linking-protocol");
|
|
CheckNull(cep);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "dns")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "timeout")) {
|
|
CheckDuplicate(cepp, dns_timeout, "dns::timeout");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "retries")) {
|
|
CheckDuplicate(cepp, dns_retries, "dns::retries");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "nameserver")) {
|
|
struct in_addr in;
|
|
CheckDuplicate(cepp, dns_nameserver, "dns::nameserver");
|
|
|
|
in.s_addr = inet_addr(cepp->ce_vardata);
|
|
if (strcmp((char *)inet_ntoa(in), cepp->ce_vardata))
|
|
{
|
|
config_error("%s:%i: set::dns::nameserver (%s) is not a valid IP",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
|
|
cepp->ce_vardata);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "bind-ip")) {
|
|
struct in_addr in;
|
|
CheckDuplicate(cepp, dns_bind_ip, "dns::bind-ip");
|
|
if (strcmp(cepp->ce_vardata, "*"))
|
|
{
|
|
in.s_addr = inet_addr(cepp->ce_vardata);
|
|
if (strcmp((char *)inet_ntoa(in), cepp->ce_vardata))
|
|
{
|
|
config_error("%s:%i: set::dns::bind-ip (%s) is not a valid IP",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
|
|
cepp->ce_vardata);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::dns",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
#ifdef THROTTLING
|
|
else if (!strcmp(cep->ce_varname, "throttle")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "period")) {
|
|
int x = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
CheckDuplicate(cepp, throttle_period, "throttle::period");
|
|
if (x > 86400*7)
|
|
{
|
|
config_error("%s:%i: insane set::throttle::period value",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "connections")) {
|
|
int x = atoi(cepp->ce_vardata);
|
|
CheckDuplicate(cepp, throttle_connections, "throttle::connections");
|
|
if ((x < 1) || (x > 127))
|
|
{
|
|
config_error("%s:%i: set::throttle::connections out of range, should be 1-127",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::throttle",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else if (!strcmp(cep->ce_varname, "anti-flood")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
|
|
{
|
|
CheckDuplicate(cepp, anti_flood_unknown_flood_bantime, "anti-flood::unknown-flood-bantime");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "unknown-flood-amount")) {
|
|
CheckDuplicate(cepp, anti_flood_unknown_flood_amount, "anti-flood::unknown-flood-amount");
|
|
}
|
|
#ifdef NO_FLOOD_AWAY
|
|
else if (!strcmp(cepp->ce_varname, "away-count")) {
|
|
int temp = atol(cepp->ce_vardata);
|
|
CheckDuplicate(cepp, anti_flood_away_count, "anti-flood::away-count");
|
|
if (temp < 1 || temp > 255)
|
|
{
|
|
config_error("%s:%i: set::anti-flood::away-count must be between 1 and 255",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "away-period")) {
|
|
int temp = config_checkval(cepp->ce_vardata, CFG_TIME);
|
|
CheckDuplicate(cepp, anti_flood_away_period, "anti-flood::away-period");
|
|
if (temp < 10)
|
|
{
|
|
config_error("%s:%i: set::anti-flood::away-period must be greater than 9",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "away-flood"))
|
|
{
|
|
int cnt, period;
|
|
if (settings.has_anti_flood_away_period)
|
|
{
|
|
config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-period",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
continue;
|
|
}
|
|
if (settings.has_anti_flood_away_count)
|
|
{
|
|
config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-count",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
continue;
|
|
}
|
|
settings.has_anti_flood_away_period = 1;
|
|
settings.has_anti_flood_away_count = 1;
|
|
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
|
|
(cnt < 1) || (cnt > 255) || (period < 10))
|
|
{
|
|
config_error("%s:%i: set::anti-flood::away-flood error. Syntax is '<count>:<period>' (eg 5:60), "
|
|
"count should be 1-255, period should be greater than 9",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
else if (!strcmp(cepp->ce_varname, "nick-flood"))
|
|
{
|
|
int cnt, period;
|
|
CheckDuplicate(cepp, anti_flood_nick_flood, "anti-flood::nick-flood");
|
|
if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
|
|
(cnt < 1) || (cnt > 255) || (period < 5))
|
|
{
|
|
config_error("%s:%i: set::anti-flood::away-flood error. Syntax is '<count>:<period>' (eg 5:60), "
|
|
"count should be 1-255, period should be greater than 4",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::anti-flood",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "options")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "webtv-support"))
|
|
{
|
|
CheckDuplicate(cepp, options_webtv_support, "options::webtv-support");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "hide-ulines"))
|
|
{
|
|
CheckDuplicate(cepp, options_hide_ulines, "options::hide-ulines");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "flat-map")) {
|
|
CheckDuplicate(cepp, options_flat_map, "options::flat-map");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
|
|
CheckDuplicate(cepp, options_show_opermotd, "options::show-opermotd");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "identd-check")) {
|
|
CheckDuplicate(cepp, options_identd_check, "options::identd-check");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
|
|
CheckDuplicate(cepp, options_fail_oper_warn, "options::fail-oper-warn");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
|
|
CheckDuplicate(cepp, options_show_connect_info, "options::show-connect-info");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
|
|
CheckDuplicate(cepp, options_dont_resolve, "options::dont-resolve");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
|
|
CheckDuplicate(cepp, options_mkpasswd_for_everyone, "options::mkpasswd-for-everyone");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
|
|
CheckDuplicate(cepp, options_allow_part_if_shunned, "options::allow-part-if-shunned");
|
|
}
|
|
else
|
|
{
|
|
config_error_unknownopt(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::options",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "hosts")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
char *c, *host;
|
|
if (!cepp->ce_vardata)
|
|
{
|
|
config_error_empty(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::hosts",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cepp->ce_varname, "local")) {
|
|
CheckDuplicate(cepp, hosts_local, "hosts::local");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "global")) {
|
|
CheckDuplicate(cepp, hosts_global, "hosts::global");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "coadmin")) {
|
|
CheckDuplicate(cepp, hosts_coadmin, "hosts::coadmin");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "admin")) {
|
|
CheckDuplicate(cepp, hosts_admin, "hosts::admin");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "servicesadmin")) {
|
|
CheckDuplicate(cepp, hosts_servicesadmin, "hosts::servicesadmin");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "netadmin")) {
|
|
CheckDuplicate(cepp, hosts_netadmin, "hosts::netadmin");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "host-on-oper-up")) {
|
|
CheckDuplicate(cepp, hosts_host_on_oper_up, "hosts::host-on-oper-up");
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::hosts", cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
|
|
}
|
|
if ((c = strchr(cepp->ce_vardata, '@')))
|
|
{
|
|
char *tmp;
|
|
if (!(*(c+1)) || (c-cepp->ce_vardata) > USERLEN ||
|
|
c == cepp->ce_vardata)
|
|
{
|
|
config_error("%s:%i: illegal value for set::hosts::%s",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
for (tmp = cepp->ce_vardata; tmp != c; tmp++)
|
|
{
|
|
if (*tmp == '~' && tmp == cepp->ce_vardata)
|
|
continue;
|
|
if (!isallowed(*tmp))
|
|
break;
|
|
}
|
|
if (tmp != c)
|
|
{
|
|
config_error("%s:%i: illegal value for set::hosts::%s",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
host = c+1;
|
|
}
|
|
else
|
|
host = cepp->ce_vardata;
|
|
if (strlen(host) > HOSTLEN)
|
|
{
|
|
config_error("%s:%i: illegal value for set::hosts::%s",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
for (; *host; host++)
|
|
{
|
|
if (!isallowed(*host) && *host != ':')
|
|
{
|
|
config_error("%s:%i: illegal value for set::hosts::%s",
|
|
cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "cloak-keys"))
|
|
{
|
|
CheckDuplicate(cep, cloak_keys, "cloak-keys");
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS, &errs);
|
|
|
|
if (value == 1)
|
|
break;
|
|
if (value == -1)
|
|
{
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
errors += errs;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "scan")) {
|
|
config_status("%s:%i: set::scan: WARNING: scanner support has been removed, "
|
|
"use BOPM instead: http://www.blitzed.org/bopm/ (*NIX) / http://vulnscan.org/winbopm/ (Windows)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ident")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
int is_ok = 0;
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "connect-timeout"))
|
|
{
|
|
is_ok = 1;
|
|
CheckDuplicate(cepp, ident_connect_timeout, "ident::connect-timeout");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "read-timeout"))
|
|
{
|
|
is_ok = 1;
|
|
CheckDuplicate(cepp, ident_read_timeout, "ident::read-timeout");
|
|
}
|
|
if (is_ok)
|
|
{
|
|
int v = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
if ((v > 60) || (v < 1))
|
|
{
|
|
config_error("%s:%i: set::ident::%s value out of range (%d), should be between 1 and 60.",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
|
|
errors++;
|
|
continue;
|
|
}
|
|
} else {
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::ident",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "enabled"))
|
|
{
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "timeout"))
|
|
{
|
|
int v = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
if ((v > 5) || (v < 1))
|
|
{
|
|
config_error("%s:%i: set::timesync::%s value out of range (%d), should be between 1 and 5 (higher=unreliable).",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
|
|
errors++;
|
|
continue;
|
|
}
|
|
} else if (!strcmp(cepp->ce_varname, "server"))
|
|
{
|
|
} else {
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::timesync",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "spamfilter")) {
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
CheckNull(cepp);
|
|
if (!strcmp(cepp->ce_varname, "ban-time"))
|
|
{
|
|
long x;
|
|
CheckDuplicate(cepp, spamfilter_ban_time, "spamfilter::ban-time");
|
|
x = config_checkval(cepp->ce_vardata,CFG_TIME);
|
|
if ((x < 0) > (x > 2000000000))
|
|
{
|
|
config_error("%s:%i: set::spamfilter:ban-time: value '%ld' out of range",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
|
|
errors++;
|
|
continue;
|
|
}
|
|
} else
|
|
if (!strcmp(cepp->ce_varname, "ban-reason"))
|
|
{
|
|
CheckDuplicate(cepp, spamfilter_ban_reason, "spamfilter::ban-reason");
|
|
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
|
|
{
|
|
CheckDuplicate(cepp, spamfilter_virus_help_channel, "spamfilter::virus-help-channel");
|
|
if ((cepp->ce_vardata[0] != '#') || (strlen(cepp->ce_vardata) > CHANNELLEN))
|
|
{
|
|
config_error("%s:%i: set::spamfilter:virus-help-channel: "
|
|
"specified channelname is too long or contains invalid characters (%s)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cepp->ce_vardata);
|
|
errors++;
|
|
continue;
|
|
}
|
|
} else
|
|
if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
|
|
{
|
|
CheckDuplicate(cepp, spamfilter_virus_help_channel_deny, "spamfilter::virus-help-channel-deny");
|
|
} else
|
|
if (!strcmp(cepp->ce_varname, "except"))
|
|
{
|
|
CheckDuplicate(cepp, spamfilter_except, "spamfilter::except");
|
|
} else
|
|
#ifdef SPAMFILTER_DETECTSLOW
|
|
if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
|
|
{
|
|
} else
|
|
if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
|
|
{
|
|
} else
|
|
#endif
|
|
{
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "set::spamfilter",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
/* TODO: FIX THIS */
|
|
else if (!strcmp(cep->ce_varname, "default-bantime"))
|
|
{
|
|
long x;
|
|
CheckDuplicate(cep, default_bantime, "default-bantime");
|
|
CheckNull(cep);
|
|
x = config_checkval(cep->ce_vardata,CFG_TIME);
|
|
if ((x < 0) > (x > 2000000000))
|
|
{
|
|
config_error("%s:%i: set::default-bantime: value '%ld' out of range",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "ban-version-tkl-time")) {
|
|
long x;
|
|
CheckDuplicate(cep, ban_version_tkl_time, "ban-version-tkl-time");
|
|
CheckNull(cep);
|
|
x = config_checkval(cep->ce_vardata,CFG_TIME);
|
|
if ((x < 0) > (x > 2000000000))
|
|
{
|
|
config_error("%s:%i: set::ban-version-tkl-time: value '%ld' out of range",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
|
|
errors++;
|
|
}
|
|
}
|
|
#ifdef NEWCHFLOODPROT
|
|
else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
|
|
int v;
|
|
CheckDuplicate(cep, modef_default_unsettime, "modef-default-unsettime");
|
|
CheckNull(cep);
|
|
v = atoi(cep->ce_vardata);
|
|
if ((v <= 0) || (v > 255))
|
|
{
|
|
config_error("%s:%i: set::modef-default-unsettime: value '%d' out of range (should be 1-255)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
|
|
int v;
|
|
CheckDuplicate(cep, modef_max_unsettime, "modef-max-unsettime");
|
|
CheckNull(cep);
|
|
v = atoi(cep->ce_vardata);
|
|
if ((v <= 0) || (v > 255))
|
|
{
|
|
config_error("%s:%i: set::modef-max-unsettime: value '%d' out of range (should be 1-255)",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
|
|
errors++;
|
|
}
|
|
}
|
|
#endif
|
|
else if (!strcmp(cep->ce_varname, "ssl")) {
|
|
#ifdef USE_SSL
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "egd")) {
|
|
CheckDuplicate(cep, ssl_egd, "ssl::egd");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
|
|
{
|
|
CheckDuplicate(cep, renegotiate_timeout, "ssl::renegotiate-timeout");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
|
|
{
|
|
CheckDuplicate(cep, renegotiate_bytes, "ssl::renegotiate-bytes");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
|
|
{
|
|
CheckNull(cepp);
|
|
CheckDuplicate(cep, ssl_server_cipher_list, "ssl::server-cipher-list");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "certificate"))
|
|
{
|
|
CheckNull(cepp);
|
|
CheckDuplicate(cep, ssl_certificate, "ssl::certificate");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "key"))
|
|
{
|
|
CheckNull(cepp);
|
|
CheckDuplicate(cep, ssl_key, "ssl::key");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
|
|
{
|
|
CheckNull(cepp);
|
|
CheckDuplicate(cep, ssl_trusted_ca_file, "ssl::trusted-ca-file");
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "options"))
|
|
{
|
|
CheckDuplicate(cep, ssl_options, "ssl::options");
|
|
for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
|
|
{
|
|
for (ofl = _SSLFlags; ofl->name; ofl++)
|
|
{
|
|
if (!strcmp(ceppp->ce_varname, ofl->name))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ofl && !ofl->name)
|
|
{
|
|
config_error("%s:%i: unknown SSL flag '%s'",
|
|
ceppp->ce_fileptr->cf_filename,
|
|
ceppp->ce_varlinenum, ceppp->ce_varname);
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
|
|
!(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf,cep,CONFIG_SET, &errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
}
|
|
if (!used) {
|
|
config_error("%s:%i: unknown directive set::%s",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
#ifdef GLOBH
|
|
glob_t files;
|
|
int i;
|
|
#elif defined(_WIN32)
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATA FindData;
|
|
char cPath[MAX_PATH], *cSlash = NULL, *path;
|
|
#endif
|
|
char *ret;
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_status("%s:%i: loadmodule without filename",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return -1;
|
|
}
|
|
#ifdef GLOBH
|
|
#if defined(__OpenBSD__) && defined(GLOB_LIMIT)
|
|
glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK|GLOB_LIMIT, NULL, &files);
|
|
#else
|
|
glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK, NULL, &files);
|
|
#endif
|
|
if (!files.gl_pathc) {
|
|
globfree(&files);
|
|
config_status("%s:%i: loadmodule %s: failed to load",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return -1;
|
|
}
|
|
for (i = 0; i < files.gl_pathc; i++) {
|
|
if ((ret = Module_Create(files.gl_pathv[i]))) {
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
files.gl_pathv[i], ret);
|
|
return -1;
|
|
}
|
|
}
|
|
globfree(&files);
|
|
#elif defined(_WIN32)
|
|
bzero(cPath,MAX_PATH);
|
|
if (strchr(ce->ce_vardata, '/') || strchr(ce->ce_vardata, '\\')) {
|
|
strncpyzt(cPath,ce->ce_vardata,MAX_PATH);
|
|
cSlash=cPath+strlen(cPath);
|
|
while(*cSlash != '\\' && *cSlash != '/' && cSlash > cPath)
|
|
cSlash--;
|
|
*(cSlash+1)=0;
|
|
}
|
|
hFind = FindFirstFile(ce->ce_vardata, &FindData);
|
|
if (!FindData.cFileName || hFind == INVALID_HANDLE_VALUE) {
|
|
config_status("%s:%i: loadmodule %s: failed to load",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
FindClose(hFind);
|
|
return -1;
|
|
}
|
|
|
|
if (cPath) {
|
|
path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
|
|
strcpy(path,cPath);
|
|
strcat(path,FindData.cFileName);
|
|
if ((ret = Module_Create(path))) {
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
path, ret);
|
|
free(path);
|
|
return -1;
|
|
}
|
|
free(path);
|
|
}
|
|
else
|
|
{
|
|
if ((ret = Module_Create(FindData.cFileName))) {
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
FindData.cFileName, ret);
|
|
return -1;
|
|
}
|
|
}
|
|
while (FindNextFile(hFind, &FindData) != 0) {
|
|
if (cPath) {
|
|
path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
|
|
strcpy(path,cPath);
|
|
strcat(path,FindData.cFileName);
|
|
if ((ret = Module_Create(path)))
|
|
{
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
FindData.cFileName, ret);
|
|
free(path);
|
|
return -1;
|
|
}
|
|
free(path);
|
|
}
|
|
else
|
|
{
|
|
if ((ret = Module_Create(FindData.cFileName)))
|
|
{
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
FindData.cFileName, ret);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
FindClose(hFind);
|
|
#else
|
|
if ((ret = Module_Create(ce->ce_vardata))) {
|
|
config_status("%s:%i: loadmodule %s: failed to load: %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, ret);
|
|
return -1;
|
|
}
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int _test_loadmodule(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Actually use configuration
|
|
*/
|
|
|
|
void run_configuration(void)
|
|
{
|
|
ConfigItem_listen *listenptr;
|
|
|
|
for (listenptr = conf_listen; listenptr; listenptr = (ConfigItem_listen *) listenptr->next)
|
|
{
|
|
if (!(listenptr->options & LISTENER_BOUND))
|
|
{
|
|
if (add_listener2(listenptr) == -1)
|
|
{
|
|
ircd_log(LOG_ERROR, "Failed to bind to %s:%i", listenptr->ip, listenptr->port);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (listenptr->listener)
|
|
{
|
|
listenptr->listener->umodes =
|
|
(listenptr->options & ~LISTENER_BOUND) ? listenptr->options : LISTENER_NORMAL;
|
|
listenptr->listener->umodes |= LISTENER_BOUND;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int _conf_offchans(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep, *cepp;
|
|
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
ConfigItem_offchans *of = MyMallocEx(sizeof(ConfigItem_offchans));
|
|
strlcpy(of->chname, cep->ce_varname, CHANNELLEN+1);
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
|
|
{
|
|
if (!strcmp(cepp->ce_varname, "topic"))
|
|
of->topic = strdup(cepp->ce_vardata);
|
|
}
|
|
AddListItem(of, conf_offchans);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
int errors = 0;
|
|
ConfigEntry *cep, *cep2;
|
|
char checkchan[CHANNELLEN + 1];
|
|
|
|
if (!ce->ce_entries)
|
|
{
|
|
config_error("%s:%i: empty official-channels block",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (strlen(cep->ce_varname) > CHANNELLEN)
|
|
{
|
|
config_error("%s:%i: official-channels: '%s' name too long (max %d characters).",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname, CHANNELLEN);
|
|
errors++;
|
|
continue;
|
|
}
|
|
strcpy(checkchan, cep->ce_varname); /* safe */
|
|
clean_channelname(checkchan);
|
|
if (strcmp(checkchan, cep->ce_varname) || (*cep->ce_varname != '#'))
|
|
{
|
|
config_error("%s:%i: official-channels: '%s' is not a valid channel name.",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
|
|
{
|
|
if (!cep2->ce_vardata)
|
|
{
|
|
config_error_empty(cep2->ce_fileptr->cf_filename,
|
|
cep2->ce_varlinenum, "official-channels",
|
|
cep2->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep2->ce_varname, "topic"))
|
|
{
|
|
if (strlen(cep2->ce_vardata) > TOPICLEN)
|
|
{
|
|
config_error("%s:%i: official-channels::%s: topic too long (max %d characters).",
|
|
cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname, TOPICLEN);
|
|
errors++;
|
|
continue;
|
|
}
|
|
} else {
|
|
config_error_unknown(cep2->ce_fileptr->cf_filename,
|
|
cep2->ce_varlinenum, "official-channels",
|
|
cep2->ce_varname);
|
|
errors++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_alias(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_alias *alias = NULL;
|
|
ConfigItem_alias_format *format;
|
|
ConfigEntry *cep, *cepp;
|
|
aCommand *cmptr;
|
|
|
|
if ((cmptr = find_Command(ce->ce_vardata, 0, M_ALIAS)))
|
|
del_Command(ce->ce_vardata, NULL, cmptr->func);
|
|
if (find_Command_simple(ce->ce_vardata))
|
|
{
|
|
config_warn("%s:%i: Alias '%s' would conflict with command (or server token) '%s', alias not added.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, ce->ce_vardata);
|
|
return 0;
|
|
}
|
|
if ((alias = Find_alias(ce->ce_vardata)))
|
|
DelListItem(alias, conf_alias);
|
|
alias = MyMallocEx(sizeof(ConfigItem_alias));
|
|
ircstrdup(alias->alias, ce->ce_vardata);
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "format")) {
|
|
format = MyMallocEx(sizeof(ConfigItem_alias_format));
|
|
ircstrdup(format->format, cep->ce_vardata);
|
|
regcomp(&format->expr, cep->ce_vardata, REG_ICASE|REG_EXTENDED);
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (!strcmp(cepp->ce_varname, "nick") ||
|
|
!strcmp(cepp->ce_varname, "target") ||
|
|
!strcmp(cepp->ce_varname, "command")) {
|
|
ircstrdup(format->nick, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "parameters")) {
|
|
ircstrdup(format->parameters, cepp->ce_vardata);
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "type")) {
|
|
if (!strcmp(cepp->ce_vardata, "services"))
|
|
format->type = ALIAS_SERVICES;
|
|
else if (!strcmp(cepp->ce_vardata, "stats"))
|
|
format->type = ALIAS_STATS;
|
|
else if (!strcmp(cepp->ce_vardata, "normal"))
|
|
format->type = ALIAS_NORMAL;
|
|
else if (!strcmp(cepp->ce_vardata, "channel"))
|
|
format->type = ALIAS_CHANNEL;
|
|
else if (!strcmp(cepp->ce_vardata, "real"))
|
|
format->type = ALIAS_REAL;
|
|
}
|
|
}
|
|
AddListItem(format, alias->format);
|
|
}
|
|
|
|
else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
|
|
{
|
|
ircstrdup(alias->nick, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type")) {
|
|
if (!strcmp(cep->ce_vardata, "services"))
|
|
alias->type = ALIAS_SERVICES;
|
|
else if (!strcmp(cep->ce_vardata, "stats"))
|
|
alias->type = ALIAS_STATS;
|
|
else if (!strcmp(cep->ce_vardata, "normal"))
|
|
alias->type = ALIAS_NORMAL;
|
|
else if (!strcmp(cep->ce_vardata, "channel"))
|
|
alias->type = ALIAS_CHANNEL;
|
|
else if (!strcmp(cep->ce_vardata, "command"))
|
|
alias->type = ALIAS_COMMAND;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "spamfilter"))
|
|
alias->spamfilter = config_checkval(cep->ce_vardata, CFG_YESNO);
|
|
}
|
|
if (BadPtr(alias->nick) && alias->type != ALIAS_COMMAND) {
|
|
ircstrdup(alias->nick, alias->alias);
|
|
}
|
|
add_CommandX(alias->alias, NULL, m_alias, 1, M_USER|M_ALIAS);
|
|
AddListItem(alias, conf_alias);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int _test_alias(ConfigFile *conf, ConfigEntry *ce) {
|
|
int errors = 0;
|
|
ConfigEntry *cep, *cepp;
|
|
char has_type = 0, has_target = 0, has_format = 0;
|
|
char type = 0;
|
|
|
|
if (!ce->ce_entries)
|
|
{
|
|
config_error("%s:%i: empty alias block",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: alias without name",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
else if (!find_Command(ce->ce_vardata, 0, M_ALIAS) && find_Command(ce->ce_vardata, 0, 0)) {
|
|
config_status("%s:%i: %s is an existing command, can not add alias",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ce->ce_vardata);
|
|
errors++;
|
|
}
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "alias"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "format")) {
|
|
int errorcode, errorbufsize;
|
|
char *errorbuf;
|
|
regex_t expr;
|
|
char has_type = 0, has_target = 0, has_parameters = 0;
|
|
|
|
has_format = 1;
|
|
errorcode = regcomp(&expr, cep->ce_vardata, REG_ICASE|REG_EXTENDED);
|
|
if (errorcode > 0)
|
|
{
|
|
errorbufsize = regerror(errorcode, &expr, NULL, 0)+1;
|
|
errorbuf = MyMalloc(errorbufsize);
|
|
regerror(errorcode, &expr, errorbuf, errorbufsize);
|
|
config_error("%s:%i: alias::format contains an invalid regex: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
errorbuf);
|
|
errors++;
|
|
free(errorbuf);
|
|
}
|
|
regfree(&expr);
|
|
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
|
|
if (config_is_blankorempty(cepp, "alias::format"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cepp->ce_varname, "nick") ||
|
|
!strcmp(cepp->ce_varname, "command") ||
|
|
!strcmp(cepp->ce_varname, "target"))
|
|
{
|
|
if (has_target)
|
|
{
|
|
config_warn_duplicate(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
"alias::format::target");
|
|
continue;
|
|
}
|
|
has_target = 1;
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "type"))
|
|
{
|
|
if (has_type)
|
|
{
|
|
config_warn_duplicate(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
"alias::format::type");
|
|
continue;
|
|
}
|
|
has_type = 1;
|
|
if (!strcmp(cepp->ce_vardata, "services"))
|
|
;
|
|
else if (!strcmp(cepp->ce_vardata, "stats"))
|
|
;
|
|
else if (!strcmp(cepp->ce_vardata, "normal"))
|
|
;
|
|
else if (!strcmp(cepp->ce_vardata, "channel"))
|
|
;
|
|
else if (!strcmp(cepp->ce_vardata, "real"))
|
|
;
|
|
else
|
|
{
|
|
config_error("%s:%i: unknown alias type",
|
|
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cepp->ce_varname, "parameters"))
|
|
{
|
|
if (has_parameters)
|
|
{
|
|
config_warn_duplicate(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum,
|
|
"alias::format::parameters");
|
|
continue;
|
|
}
|
|
has_parameters = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cepp->ce_fileptr->cf_filename,
|
|
cepp->ce_varlinenum, "alias::format",
|
|
cepp->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_target)
|
|
{
|
|
config_error_missing(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "alias::format::target");
|
|
errors++;
|
|
}
|
|
if (!has_type)
|
|
{
|
|
config_error_missing(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "alias::format::type");
|
|
errors++;
|
|
}
|
|
if (!has_parameters)
|
|
{
|
|
config_error_missing(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "alias::format::parameters");
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
|
|
{
|
|
if (has_target)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "alias::target");
|
|
continue;
|
|
}
|
|
has_target = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type")) {
|
|
if (has_type)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "alias::type");
|
|
continue;
|
|
}
|
|
has_type = 1;
|
|
if (!strcmp(cep->ce_vardata, "services"))
|
|
;
|
|
else if (!strcmp(cep->ce_vardata, "stats"))
|
|
;
|
|
else if (!strcmp(cep->ce_vardata, "normal"))
|
|
;
|
|
else if (!strcmp(cep->ce_vardata, "channel"))
|
|
;
|
|
else if (!strcmp(cep->ce_vardata, "command"))
|
|
type = 'c';
|
|
else {
|
|
config_error("%s:%i: unknown alias type",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "spamfilter"))
|
|
;
|
|
else {
|
|
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
|
"alias", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_type)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"alias::type");
|
|
errors++;
|
|
}
|
|
if (!has_format && type == 'c')
|
|
{
|
|
config_error("%s:%d: alias::type is 'command' but no alias::format was specified",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
else if (has_format && type != 'c')
|
|
{
|
|
config_error("%s:%d: alias::format specified when type is not 'command'",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
int _conf_deny(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
Hook *h;
|
|
|
|
if (!strcmp(ce->ce_vardata, "dcc"))
|
|
_conf_deny_dcc(conf, ce);
|
|
else if (!strcmp(ce->ce_vardata, "channel"))
|
|
_conf_deny_channel(conf, ce);
|
|
else if (!strcmp(ce->ce_vardata, "link"))
|
|
_conf_deny_link(conf, ce);
|
|
else if (!strcmp(ce->ce_vardata, "version"))
|
|
_conf_deny_version(conf, ce);
|
|
else
|
|
{
|
|
int value;
|
|
for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
|
|
{
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY);
|
|
if (value == 1)
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _conf_deny_dcc(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_deny_dcc *deny = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
deny = MyMallocEx(sizeof(ConfigItem_deny_dcc));
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "filename"))
|
|
{
|
|
ircstrdup(deny->filename, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
ircstrdup(deny->reason, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "soft"))
|
|
{
|
|
int x = config_checkval(cep->ce_vardata,CFG_YESNO);
|
|
if (x == 1)
|
|
deny->flag.type = DCCDENY_SOFT;
|
|
}
|
|
}
|
|
if (!deny->reason)
|
|
{
|
|
if (deny->flag.type == DCCDENY_HARD)
|
|
ircstrdup(deny->reason, "Possible infected virus file");
|
|
else
|
|
ircstrdup(deny->reason, "Possible executable content");
|
|
}
|
|
AddListItem(deny, conf_deny_dcc);
|
|
return 0;
|
|
}
|
|
|
|
int _conf_deny_channel(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_deny_channel *deny = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
deny = MyMallocEx(sizeof(ConfigItem_deny_channel));
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "channel"))
|
|
{
|
|
ircstrdup(deny->channel, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "redirect"))
|
|
{
|
|
ircstrdup(deny->redirect, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
ircstrdup(deny->reason, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "warn"))
|
|
{
|
|
deny->warn = config_checkval(cep->ce_vardata,CFG_YESNO);
|
|
}
|
|
}
|
|
AddListItem(deny, conf_deny_channel);
|
|
return 0;
|
|
}
|
|
int _conf_deny_link(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_deny_link *deny = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
deny = MyMallocEx(sizeof(ConfigItem_deny_link));
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
ircstrdup(deny->mask, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "rule"))
|
|
{
|
|
deny->rule = (char *)crule_parse(cep->ce_vardata);
|
|
ircstrdup(deny->prettyrule, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type")) {
|
|
if (!strcmp(cep->ce_vardata, "all"))
|
|
deny->flag.type = CRULE_ALL;
|
|
else if (!strcmp(cep->ce_vardata, "auto"))
|
|
deny->flag.type = CRULE_AUTO;
|
|
}
|
|
}
|
|
AddListItem(deny, conf_deny_link);
|
|
return 0;
|
|
}
|
|
|
|
int _conf_deny_version(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigItem_deny_version *deny = NULL;
|
|
ConfigEntry *cep;
|
|
|
|
deny = MyMallocEx(sizeof(ConfigItem_deny_version));
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
ircstrdup(deny->mask, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "version"))
|
|
{
|
|
ircstrdup(deny->version, cep->ce_vardata);
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
ircstrdup(deny->flags, cep->ce_vardata);
|
|
}
|
|
}
|
|
AddListItem(deny, conf_deny_version);
|
|
return 0;
|
|
}
|
|
|
|
int _test_deny(ConfigFile *conf, ConfigEntry *ce)
|
|
{
|
|
ConfigEntry *cep;
|
|
int errors = 0;
|
|
Hook *h;
|
|
|
|
if (!ce->ce_vardata)
|
|
{
|
|
config_error("%s:%i: deny without type",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
|
return 1;
|
|
}
|
|
if (!strcmp(ce->ce_vardata, "dcc"))
|
|
{
|
|
char has_filename = 0, has_reason = 0, has_soft = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "deny dcc"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "filename"))
|
|
{
|
|
if (has_filename)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny dcc::filename");
|
|
continue;
|
|
}
|
|
has_filename = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
if (has_reason)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny dcc::reason");
|
|
continue;
|
|
}
|
|
has_reason = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "soft"))
|
|
{
|
|
if (has_soft)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny dcc::soft");
|
|
continue;
|
|
}
|
|
has_soft = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny dcc", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_filename)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny dcc::filename");
|
|
errors++;
|
|
}
|
|
if (!has_reason)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny dcc::reason");
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(ce->ce_vardata, "channel"))
|
|
{
|
|
char has_channel = 0, has_warn = 0, has_reason = 0, has_redirect = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "deny channel"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "channel"))
|
|
{
|
|
if (has_channel)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny channel::channel");
|
|
continue;
|
|
}
|
|
has_channel = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "redirect"))
|
|
{
|
|
if (has_redirect)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny channel::redirect");
|
|
continue;
|
|
}
|
|
has_redirect = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "reason"))
|
|
{
|
|
if (has_reason)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny channel::reason");
|
|
continue;
|
|
}
|
|
has_reason = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "warn"))
|
|
{
|
|
if (has_warn)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny channel::warn");
|
|
continue;
|
|
}
|
|
has_warn = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny channel", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_channel)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny channel::channel");
|
|
errors++;
|
|
}
|
|
if (!has_reason)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny channel::reason");
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(ce->ce_vardata, "link"))
|
|
{
|
|
char has_mask = 0, has_rule = 0, has_type = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "deny link"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny link::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "rule"))
|
|
{
|
|
int val = 0;
|
|
if (has_rule)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny link::rule");
|
|
continue;
|
|
}
|
|
has_rule = 1;
|
|
if ((val = crule_test(cep->ce_vardata)))
|
|
{
|
|
config_error("%s:%i: deny link::rule contains an invalid expression: %s",
|
|
cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum,
|
|
crule_errstring(val));
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "type"))
|
|
{
|
|
if (has_type)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny link::type");
|
|
continue;
|
|
}
|
|
has_type = 1;
|
|
if (!strcmp(cep->ce_vardata, "auto"))
|
|
;
|
|
else if (!strcmp(cep->ce_vardata, "all"))
|
|
;
|
|
else {
|
|
config_status("%s:%i: unknown deny link type",
|
|
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
|
|
errors++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny link", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny link::mask");
|
|
errors++;
|
|
}
|
|
if (!has_rule)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny link::rule");
|
|
errors++;
|
|
}
|
|
if (!has_type)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny link::type");
|
|
errors++;
|
|
}
|
|
}
|
|
else if (!strcmp(ce->ce_vardata, "version"))
|
|
{
|
|
char has_mask = 0, has_version = 0, has_flags = 0;
|
|
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
|
{
|
|
if (config_is_blankorempty(cep, "deny version"))
|
|
{
|
|
errors++;
|
|
continue;
|
|
}
|
|
if (!strcmp(cep->ce_varname, "mask"))
|
|
{
|
|
if (has_mask)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny version::mask");
|
|
continue;
|
|
}
|
|
has_mask = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "version"))
|
|
{
|
|
if (has_version)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny version::version");
|
|
continue;
|
|
}
|
|
has_version = 1;
|
|
}
|
|
else if (!strcmp(cep->ce_varname, "flags"))
|
|
{
|
|
if (has_flags)
|
|
{
|
|
config_warn_duplicate(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny version::flags");
|
|
continue;
|
|
}
|
|
has_flags = 1;
|
|
}
|
|
else
|
|
{
|
|
config_error_unknown(cep->ce_fileptr->cf_filename,
|
|
cep->ce_varlinenum, "deny version", cep->ce_varname);
|
|
errors++;
|
|
}
|
|
}
|
|
if (!has_mask)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny version::mask");
|
|
errors++;
|
|
}
|
|
if (!has_version)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny version::version");
|
|
errors++;
|
|
}
|
|
if (!has_flags)
|
|
{
|
|
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
"deny version::flags");
|
|
errors++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int used = 0;
|
|
for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
|
|
{
|
|
int value, errs = 0;
|
|
if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
|
|
&& !(h->owner->options & MOD_OPT_PERM))
|
|
continue;
|
|
value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY, &errs);
|
|
if (value == 2)
|
|
used = 1;
|
|
if (value == 1)
|
|
{
|
|
used = 1;
|
|
break;
|
|
}
|
|
if (value == -1)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
break;
|
|
}
|
|
if (value == -2)
|
|
{
|
|
used = 1;
|
|
errors += errs;
|
|
}
|
|
}
|
|
if (!used) {
|
|
config_error("%s:%i: unknown deny type %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata);
|
|
return 1;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
#ifdef USE_LIBCURL
|
|
static void conf_download_complete(char *url, char *file, char *errorbuf, int cached)
|
|
{
|
|
ConfigItem_include *inc;
|
|
if (!loop.ircd_rehashing)
|
|
{
|
|
remove(file);
|
|
return;
|
|
}
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if (!(inc->flag.type & INCLUDE_REMOTE))
|
|
continue;
|
|
if (inc->flag.type & INCLUDE_NOTLOADED)
|
|
continue;
|
|
if (!stricmp(url, inc->url))
|
|
{
|
|
inc->flag.type &= ~INCLUDE_DLQUEUED;
|
|
break;
|
|
}
|
|
}
|
|
if (!file && !cached)
|
|
add_remote_include(file, url, 0, errorbuf); /* DOWNLOAD FAILED */
|
|
else
|
|
{
|
|
if (cached)
|
|
{
|
|
char *urlfile = url_getfilename(url);
|
|
char *file = unreal_getfilename(urlfile);
|
|
char *tmp = unreal_mktemp("tmp", file);
|
|
unreal_copyfileex(inc->file, tmp, 1);
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
unreal_copyfileex(inc->file, unreal_mkcache(url), 0);
|
|
#endif
|
|
add_remote_include(tmp, url, 0, NULL);
|
|
free(urlfile);
|
|
}
|
|
else {
|
|
add_remote_include(file, url, 0, NULL);
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
unreal_copyfileex(file, unreal_mkcache(url), 0);
|
|
#endif
|
|
}
|
|
}
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if (inc->flag.type & INCLUDE_DLQUEUED)
|
|
return;
|
|
}
|
|
rehash_internal(loop.rehash_save_cptr, loop.rehash_save_sptr, loop.rehash_save_sig);
|
|
}
|
|
#endif
|
|
|
|
int rehash(aClient *cptr, aClient *sptr, int sig)
|
|
{
|
|
#ifdef USE_LIBCURL
|
|
ConfigItem_include *inc;
|
|
char found_remote = 0;
|
|
if (loop.ircd_rehashing)
|
|
{
|
|
if (!sig)
|
|
sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress",
|
|
me.name, sptr->name);
|
|
return 0;
|
|
}
|
|
|
|
loop.ircd_rehashing = 1;
|
|
loop.rehash_save_cptr = cptr;
|
|
loop.rehash_save_sptr = sptr;
|
|
loop.rehash_save_sig = sig;
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
time_t modtime;
|
|
if (!(inc->flag.type & INCLUDE_REMOTE))
|
|
continue;
|
|
|
|
if (inc->flag.type & INCLUDE_NOTLOADED)
|
|
continue;
|
|
found_remote = 1;
|
|
modtime = unreal_getfilemodtime(inc->file);
|
|
inc->flag.type |= INCLUDE_DLQUEUED;
|
|
download_file_async(inc->url, modtime, conf_download_complete);
|
|
}
|
|
if (!found_remote)
|
|
return rehash_internal(cptr, sptr, sig);
|
|
return 0;
|
|
#else
|
|
loop.ircd_rehashing = 1;
|
|
return rehash_internal(cptr, sptr, sig);
|
|
#endif
|
|
}
|
|
|
|
int rehash_internal(aClient *cptr, aClient *sptr, int sig)
|
|
{
|
|
flush_connections(&me);
|
|
if (sig == 1)
|
|
{
|
|
sendto_ops("Got signal SIGHUP, reloading %s file", configfile);
|
|
#ifdef ULTRIX
|
|
if (fork() > 0)
|
|
exit(0);
|
|
write_pidfile();
|
|
#endif
|
|
}
|
|
loop.ircd_rehashing = 1; /* double checking.. */
|
|
if (init_conf(configfile, 1) == 0)
|
|
run_configuration();
|
|
if (sig == 1)
|
|
reread_motdsandrules();
|
|
unload_all_unused_snomasks();
|
|
unload_all_unused_umodes();
|
|
unload_all_unused_extcmodes();
|
|
loop.ircd_rehashing = 0;
|
|
return 1;
|
|
}
|
|
|
|
void link_cleanup(ConfigItem_link *link_ptr)
|
|
{
|
|
ircfree(link_ptr->servername);
|
|
ircfree(link_ptr->username);
|
|
ircfree(link_ptr->bindip);
|
|
ircfree(link_ptr->hostname);
|
|
ircfree(link_ptr->hubmask);
|
|
ircfree(link_ptr->leafmask);
|
|
ircfree(link_ptr->connpwd);
|
|
#ifdef USE_SSL
|
|
ircfree(link_ptr->ciphers);
|
|
#endif
|
|
Auth_DeleteAuthStruct(link_ptr->recvauth);
|
|
link_ptr->recvauth = NULL;
|
|
}
|
|
|
|
void delete_linkblock(ConfigItem_link *link_ptr)
|
|
{
|
|
Debug((DEBUG_ERROR, "delete_linkblock: deleting %s, refcount=%d",
|
|
link_ptr->servername, link_ptr->refcount));
|
|
if (link_ptr->class)
|
|
{
|
|
link_ptr->class->xrefcount--;
|
|
/* Perhaps the class is temporary too and we need to free it... */
|
|
if (link_ptr->class->flag.temporary &&
|
|
!link_ptr->class->clients && !link_ptr->class->xrefcount)
|
|
{
|
|
delete_classblock(link_ptr->class);
|
|
link_ptr->class = NULL;
|
|
}
|
|
}
|
|
link_cleanup(link_ptr);
|
|
DelListItem(link_ptr, conf_link);
|
|
MyFree(link_ptr);
|
|
}
|
|
|
|
void delete_cgiircblock(ConfigItem_cgiirc *e)
|
|
{
|
|
Debug((DEBUG_ERROR, "delete_cgiircblock: deleting %s", e->hostname));
|
|
if (e->auth)
|
|
Auth_DeleteAuthStruct(e->auth);
|
|
ircfree(e->hostname);
|
|
ircfree(e->username);
|
|
DelListItem(e, conf_cgiirc);
|
|
MyFree(e);
|
|
}
|
|
|
|
void delete_classblock(ConfigItem_class *class_ptr)
|
|
{
|
|
Debug((DEBUG_ERROR, "delete_classblock: deleting %s, clients=%d, xrefcount=%d",
|
|
class_ptr->name, class_ptr->clients, class_ptr->xrefcount));
|
|
ircfree(class_ptr->name);
|
|
DelListItem(class_ptr, conf_class);
|
|
MyFree(class_ptr);
|
|
}
|
|
|
|
void listen_cleanup()
|
|
{
|
|
int i = 0;
|
|
ConfigItem_listen *listen_ptr;
|
|
ListStruct *next;
|
|
for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)next)
|
|
{
|
|
next = (ListStruct *)listen_ptr->next;
|
|
if (listen_ptr->flag.temporary && !listen_ptr->clients)
|
|
{
|
|
ircfree(listen_ptr->ip);
|
|
DelListItem(listen_ptr, conf_listen);
|
|
MyFree(listen_ptr);
|
|
i++;
|
|
}
|
|
}
|
|
if (i)
|
|
close_listeners();
|
|
}
|
|
|
|
#ifdef USE_LIBCURL
|
|
char *find_remote_include(char *url, char **errorbuf)
|
|
{
|
|
ConfigItem_include *inc;
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if (!(inc->flag.type & INCLUDE_NOTLOADED))
|
|
continue;
|
|
if (!(inc->flag.type & INCLUDE_REMOTE))
|
|
continue;
|
|
if (!stricmp(url, inc->url))
|
|
{
|
|
*errorbuf = inc->errorbuf;
|
|
return inc->file;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *find_loaded_remote_include(char *url)
|
|
{
|
|
ConfigItem_include *inc;
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if ((inc->flag.type & INCLUDE_NOTLOADED))
|
|
continue;
|
|
if (!(inc->flag.type & INCLUDE_REMOTE))
|
|
continue;
|
|
if (!stricmp(url, inc->url))
|
|
return inc->file;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int remote_include(ConfigEntry *ce)
|
|
{
|
|
char *errorbuf = NULL;
|
|
char *file = find_remote_include(ce->ce_vardata, &errorbuf);
|
|
int ret;
|
|
if (!loop.ircd_rehashing || (loop.ircd_rehashing && !file && !errorbuf))
|
|
{
|
|
char *error;
|
|
if (config_verbose > 0)
|
|
config_status("Downloading %s", ce->ce_vardata);
|
|
file = download_file(ce->ce_vardata, &error);
|
|
if (!file)
|
|
{
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
if (has_cached_version(ce->ce_vardata))
|
|
{
|
|
config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, error);
|
|
file = strdup(unreal_mkcache(ce->ce_vardata));
|
|
/* Let it pass to load_conf()... */
|
|
} else {
|
|
#endif
|
|
config_error("%s:%i: include: error downloading '%s': %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, error);
|
|
return -1;
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
}
|
|
#endif
|
|
}
|
|
if ((ret = load_conf(file)) >= 0)
|
|
add_remote_include(file, ce->ce_vardata, INCLUDE_USED, NULL);
|
|
free(file);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
if (errorbuf)
|
|
{
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
if (has_cached_version(ce->ce_vardata))
|
|
{
|
|
config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, errorbuf);
|
|
/* Let it pass to load_conf()... */
|
|
file = strdup(unreal_mkcache(ce->ce_vardata));
|
|
} else {
|
|
#endif
|
|
config_error("%s:%i: include: error downloading '%s': %s",
|
|
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
|
|
ce->ce_vardata, errorbuf);
|
|
return -1;
|
|
#ifdef REMOTEINC_SPECIALCACHE
|
|
}
|
|
#endif
|
|
}
|
|
if (config_verbose > 0)
|
|
config_status("Loading %s from download", ce->ce_vardata);
|
|
if ((ret = load_conf(file)) >= 0)
|
|
add_remote_include(file, ce->ce_vardata, INCLUDE_USED, NULL);
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void add_include(char *file)
|
|
{
|
|
ConfigItem_include *inc;
|
|
if (!stricmp(file, CPATH))
|
|
return;
|
|
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if (!(inc->flag.type & INCLUDE_NOTLOADED))
|
|
continue;
|
|
if (inc->flag.type & INCLUDE_REMOTE)
|
|
continue;
|
|
if (!stricmp(file, inc->file))
|
|
return;
|
|
}
|
|
inc = MyMallocEx(sizeof(ConfigItem_include));
|
|
inc->file = strdup(file);
|
|
inc->flag.type = INCLUDE_NOTLOADED|INCLUDE_USED;
|
|
AddListItem(inc, conf_include);
|
|
}
|
|
|
|
#ifdef USE_LIBCURL
|
|
void add_remote_include(char *file, char *url, int flags, char *errorbuf)
|
|
{
|
|
ConfigItem_include *inc;
|
|
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
{
|
|
if (!(inc->flag.type & INCLUDE_REMOTE))
|
|
continue;
|
|
if (!(inc->flag.type & INCLUDE_NOTLOADED))
|
|
continue;
|
|
if (!stricmp(url, inc->url))
|
|
{
|
|
inc->flag.type |= flags;
|
|
return;
|
|
}
|
|
}
|
|
|
|
inc = MyMallocEx(sizeof(ConfigItem_include));
|
|
if (file)
|
|
inc->file = strdup(file);
|
|
inc->url = strdup(url);
|
|
inc->flag.type = (INCLUDE_NOTLOADED|INCLUDE_REMOTE|flags);
|
|
if (errorbuf)
|
|
inc->errorbuf = strdup(errorbuf);
|
|
AddListItem(inc, conf_include);
|
|
}
|
|
#endif
|
|
|
|
void unload_notloaded_includes(void)
|
|
{
|
|
ConfigItem_include *inc, *next;
|
|
|
|
for (inc = conf_include; inc; inc = next)
|
|
{
|
|
next = (ConfigItem_include *)inc->next;
|
|
if ((inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
|
|
{
|
|
#ifdef USE_LIBCURL
|
|
if (inc->flag.type & INCLUDE_REMOTE)
|
|
{
|
|
remove(inc->file);
|
|
free(inc->url);
|
|
if (inc->errorbuf)
|
|
free(inc->errorbuf);
|
|
}
|
|
#endif
|
|
free(inc->file);
|
|
DelListItem(inc, conf_include);
|
|
free(inc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void unload_loaded_includes(void)
|
|
{
|
|
ConfigItem_include *inc, *next;
|
|
|
|
for (inc = conf_include; inc; inc = next)
|
|
{
|
|
next = (ConfigItem_include *)inc->next;
|
|
if (!(inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
|
|
{
|
|
#ifdef USE_LIBCURL
|
|
if (inc->flag.type & INCLUDE_REMOTE)
|
|
{
|
|
remove(inc->file);
|
|
free(inc->url);
|
|
if (inc->errorbuf)
|
|
free(inc->errorbuf);
|
|
}
|
|
#endif
|
|
free(inc->file);
|
|
DelListItem(inc, conf_include);
|
|
free(inc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void load_includes(void)
|
|
{
|
|
ConfigItem_include *inc;
|
|
|
|
/* Doing this for all the modules should actually be faster
|
|
* than only doing it for modules that are not-loaded
|
|
*/
|
|
for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
|
|
inc->flag.type &= ~INCLUDE_NOTLOADED;
|
|
}
|