Advertisement
Guest User

UnrealIRCd

a guest
Mar 19th, 2016
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 257.28 KB | None | 0 0
  1. /*
  2.  *   Unreal Internet Relay Chat Daemon, src/s_conf.c
  3.  *   (C) 1998-2000 Chris Behrens & Fred Jacobs (comstud, moogle)
  4.  *   (C) 2000-2002 Carsten V. Munk and the UnrealIRCd Team
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 1, or (at your option)
  9.  *   any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20. #include "struct.h"
  21. #include "url.h"
  22. #include "common.h"
  23. #include "sys.h"
  24. #include "numeric.h"
  25. #include "channel.h"
  26. #include "macros.h"
  27. #include <fcntl.h>
  28. #ifndef _WIN32
  29. #include <sys/socket.h>
  30. #include <sys/wait.h>
  31. #else
  32. #include <io.h>
  33. #endif
  34. #include <sys/stat.h>
  35. #ifdef __hpux
  36. #include "inet.h"
  37. #endif
  38. #if defined(PCS) || defined(AIX) || defined(SVR3)
  39. #include <time.h>
  40. #endif
  41. #include <string.h>
  42. #ifdef GLOBH
  43. #include <glob.h>
  44. #endif
  45. #include "h.h"
  46. #include "inet.h"
  47. #include "proto.h"
  48. #ifdef _WIN32
  49. #undef GLOBH
  50. #endif
  51.  
  52. /*
  53.  * Some typedefs..
  54. */
  55. typedef struct _confcommand ConfigCommand;
  56. struct  _confcommand
  57. {
  58.     char    *name;
  59.     int (*conffunc)(ConfigFile *conf, ConfigEntry *ce);
  60.     int     (*testfunc)(ConfigFile *conf, ConfigEntry *ce);
  61. };
  62.  
  63. typedef struct _conf_namevalue NameValue;
  64. struct _conf_namevalue
  65. {
  66.     long    flag;
  67.     char    *name;
  68. };
  69.  
  70.  
  71. /* Config commands */
  72.  
  73. static int  _conf_admin     (ConfigFile *conf, ConfigEntry *ce);
  74. static int  _conf_me        (ConfigFile *conf, ConfigEntry *ce);
  75. static int  _conf_files     (ConfigFile *conf, ConfigEntry *ce);
  76. static int  _conf_oper      (ConfigFile *conf, ConfigEntry *ce);
  77. static int  _conf_operclass     (ConfigFile *conf, ConfigEntry *ce);
  78. static int  _conf_class     (ConfigFile *conf, ConfigEntry *ce);
  79. static int  _conf_drpass        (ConfigFile *conf, ConfigEntry *ce);
  80. static int  _conf_ulines        (ConfigFile *conf, ConfigEntry *ce);
  81. static int  _conf_include       (ConfigFile *conf, ConfigEntry *ce);
  82. static int  _conf_tld       (ConfigFile *conf, ConfigEntry *ce);
  83. static int  _conf_listen        (ConfigFile *conf, ConfigEntry *ce);
  84. static int  _conf_allow     (ConfigFile *conf, ConfigEntry *ce);
  85. static int  _conf_except        (ConfigFile *conf, ConfigEntry *ce);
  86. static int  _conf_vhost     (ConfigFile *conf, ConfigEntry *ce);
  87. static int  _conf_link      (ConfigFile *conf, ConfigEntry *ce);
  88. static int  _conf_ban       (ConfigFile *conf, ConfigEntry *ce);
  89. static int  _conf_set       (ConfigFile *conf, ConfigEntry *ce);
  90. static int  _conf_deny      (ConfigFile *conf, ConfigEntry *ce);
  91. static int  _conf_deny_dcc      (ConfigFile *conf, ConfigEntry *ce);
  92. static int  _conf_deny_link     (ConfigFile *conf, ConfigEntry *ce);
  93. static int  _conf_deny_channel  (ConfigFile *conf, ConfigEntry *ce);
  94. static int  _conf_deny_version  (ConfigFile *conf, ConfigEntry *ce);
  95. static int  _conf_allow_channel (ConfigFile *conf, ConfigEntry *ce);
  96. static int  _conf_allow_dcc     (ConfigFile *conf, ConfigEntry *ce);
  97. static int  _conf_loadmodule    (ConfigFile *conf, ConfigEntry *ce);
  98. static int  _conf_log       (ConfigFile *conf, ConfigEntry *ce);
  99. static int  _conf_alias     (ConfigFile *conf, ConfigEntry *ce);
  100. static int  _conf_help      (ConfigFile *conf, ConfigEntry *ce);
  101. static int  _conf_offchans      (ConfigFile *conf, ConfigEntry *ce);
  102. static int  _conf_spamfilter    (ConfigFile *conf, ConfigEntry *ce);
  103.  
  104. /*
  105.  * Validation commands
  106. */
  107.  
  108. static int  _test_admin     (ConfigFile *conf, ConfigEntry *ce);
  109. static int  _test_me        (ConfigFile *conf, ConfigEntry *ce);
  110. static int  _test_files     (ConfigFile *conf, ConfigEntry *ce);
  111. static int  _test_oper      (ConfigFile *conf, ConfigEntry *ce);
  112. static int  _test_operclass     (ConfigFile *conf, ConfigEntry *ce);
  113. static int  _test_class     (ConfigFile *conf, ConfigEntry *ce);
  114. static int  _test_drpass        (ConfigFile *conf, ConfigEntry *ce);
  115. static int  _test_ulines        (ConfigFile *conf, ConfigEntry *ce);
  116. static int  _test_include       (ConfigFile *conf, ConfigEntry *ce);
  117. static int  _test_tld       (ConfigFile *conf, ConfigEntry *ce);
  118. static int  _test_listen        (ConfigFile *conf, ConfigEntry *ce);
  119. static int  _test_allow     (ConfigFile *conf, ConfigEntry *ce);
  120. static int  _test_except        (ConfigFile *conf, ConfigEntry *ce);
  121. static int  _test_vhost     (ConfigFile *conf, ConfigEntry *ce);
  122. static int  _test_link      (ConfigFile *conf, ConfigEntry *ce);
  123. static int  _test_ban       (ConfigFile *conf, ConfigEntry *ce);
  124. static int  _test_set       (ConfigFile *conf, ConfigEntry *ce);
  125. static int  _test_deny      (ConfigFile *conf, ConfigEntry *ce);
  126. static int  _test_allow_channel (ConfigFile *conf, ConfigEntry *ce);
  127. static int  _test_allow_dcc     (ConfigFile *conf, ConfigEntry *ce);
  128. static int  _test_loadmodule    (ConfigFile *conf, ConfigEntry *ce);
  129. static int  _test_log       (ConfigFile *conf, ConfigEntry *ce);
  130. static int  _test_alias     (ConfigFile *conf, ConfigEntry *ce);
  131. static int  _test_help      (ConfigFile *conf, ConfigEntry *ce);
  132. static int  _test_offchans      (ConfigFile *conf, ConfigEntry *ce);
  133. static int  _test_spamfilter    (ConfigFile *conf, ConfigEntry *ce);
  134.  
  135. /* This MUST be alphabetized */
  136. static ConfigCommand _ConfigCommands[] = {
  137.     { "admin",      _conf_admin,        _test_admin     },
  138.     { "alias",      _conf_alias,        _test_alias },
  139.     { "allow",      _conf_allow,        _test_allow },
  140.     { "ban",        _conf_ban,      _test_ban   },
  141.     { "class",      _conf_class,        _test_class },
  142.     { "deny",       _conf_deny,     _test_deny  },
  143.     { "drpass",     _conf_drpass,       _test_drpass    },
  144.     { "except",     _conf_except,       _test_except    },
  145.     { "files",      _conf_files,        _test_files },
  146.     { "help",       _conf_help,     _test_help  },
  147.     { "include",        NULL,           _test_include   },
  148.     { "link",       _conf_link,     _test_link  },
  149.     { "listen",         _conf_listen,       _test_listen    },
  150.     { "loadmodule",     NULL,           _test_loadmodule},
  151.     { "log",        _conf_log,      _test_log   },
  152.     { "me",         _conf_me,       _test_me    },
  153.     { "official-channels",      _conf_offchans,     _test_offchans  },
  154.     { "oper",       _conf_oper,     _test_oper  },
  155.     { "operclass",      _conf_operclass,    _test_operclass },
  156.     { "set",        _conf_set,      _test_set   },
  157.     { "spamfilter", _conf_spamfilter,   _test_spamfilter    },
  158.     { "tld",        _conf_tld,      _test_tld   },
  159.     { "ulines",     _conf_ulines,       _test_ulines    },
  160.     { "vhost",      _conf_vhost,        _test_vhost },
  161. };
  162.  
  163. /* This MUST be alphabetized */
  164. static NameValue _ListenerFlags[] = {
  165.     { LISTENER_CLIENTSONLY,  "clientsonly"},
  166.     { LISTENER_DEFER_ACCEPT, "defer-accept"},
  167.     { LISTENER_SERVERSONLY,  "serversonly"},
  168.     { LISTENER_SSL,      "ssl"},
  169.     { LISTENER_NORMAL,   "standard"},
  170. };
  171.  
  172. /* This MUST be alphabetized */
  173. static NameValue _LinkFlags[] = {
  174.     { CONNECT_AUTO, "autoconnect" },
  175.     { CONNECT_INSECURE, "insecure" },
  176.     { CONNECT_QUARANTINE, "quarantine"},
  177.     { CONNECT_SSL, "ssl" },
  178. };
  179.  
  180. /* This MUST be alphabetized */
  181. static NameValue _LogFlags[] = {
  182.     { LOG_CHGCMDS, "chg-commands" },
  183.     { LOG_CLIENT, "connects" },
  184.     { LOG_ERROR, "errors" },
  185.     { LOG_KILL, "kills" },
  186.     { LOG_KLINE, "kline" },
  187.     { LOG_OPER, "oper" },
  188.     { LOG_OVERRIDE, "oper-override" },
  189.     { LOG_SACMDS, "sadmin-commands" },
  190.     { LOG_SERVER, "server-connects" },
  191.     { LOG_SPAMFILTER, "spamfilter" },
  192.     { LOG_TKL, "tkl" },
  193. };
  194.  
  195. /* This MUST be alphabetized */
  196. static NameValue ExceptTklFlags[] = {
  197.     { 0, "all" },
  198.     { TKL_GLOBAL|TKL_KILL,  "gline" },
  199.     { TKL_GLOBAL|TKL_NICK,  "gqline" },
  200.     { TKL_GLOBAL|TKL_ZAP,   "gzline" },
  201.     { TKL_NICK,     "qline" },
  202.     { TKL_GLOBAL|TKL_SHUN,  "shun" }
  203. };
  204.  
  205. /* This MUST be alphabetized */
  206. static NameValue _SSLFlags[] = {
  207.     { SSLFLAG_FAILIFNOCERT, "fail-if-no-clientcert" },
  208.     { SSLFLAG_DONOTACCEPTSELFSIGNED, "no-self-signed" },
  209.     { SSLFLAG_NOSTARTTLS, "no-starttls" },
  210.     { SSLFLAG_VERIFYCERT, "verify-certificate" },
  211. };
  212.  
  213. struct {
  214.     unsigned conf_me : 1;
  215.     unsigned conf_admin : 1;
  216.     unsigned conf_listen : 1;
  217. } requiredstuff;
  218. struct SetCheck settings;
  219. /*
  220.  * Utilities
  221. */
  222.  
  223. void    port_range(char *string, int *start, int *end);
  224. long    config_checkval(char *value, unsigned short flags);
  225.  
  226. /*
  227.  * Parser
  228. */
  229.  
  230. ConfigFile      *config_load(char *filename);
  231. void            config_free(ConfigFile *cfptr);
  232. static ConfigFile   *config_parse(char *filename, char *confdata);
  233. static void         config_entry_free(ConfigEntry *ceptr);
  234. ConfigEntry     *config_find_entry(ConfigEntry *ce, char *name);
  235. /*
  236.  * Error handling
  237. */
  238.  
  239. void            config_warn(char *format, ...);
  240. void            config_error(char *format, ...);
  241. void            config_status(char *format, ...);
  242. void            config_progress(char *format, ...);
  243.  
  244. #ifdef _WIN32
  245. extern void     win_log(char *format, ...);
  246. extern void     win_error();
  247. #endif
  248. extern void add_entropy_configfile(struct stat *st, char *buf);
  249. extern void unload_all_unused_snomasks(void);
  250. extern void unload_all_unused_umodes(void);
  251. extern void unload_all_unused_extcmodes(void);
  252.  
  253. extern int charsys_test_language(char *name);
  254. extern void charsys_add_language(char *name);
  255. extern void charsys_reset_pretest(void);
  256. int charsys_postconftest(void);
  257. void charsys_finish(void);
  258. int reloadable_perm_module_unloaded(void);
  259.  
  260. /*
  261.  * Config parser (IRCd)
  262. */
  263. int         init_conf(char *rootconf, int rehash);
  264. int         load_conf(char *filename, const char *original_path);
  265. void            config_rehash();
  266. int         config_run();
  267. /*
  268.  * Configuration linked lists
  269. */
  270. ConfigItem_me       *conf_me = NULL;
  271. ConfigItem_files    *conf_files = NULL;
  272. ConfigItem_class    *conf_class = NULL;
  273. ConfigItem_class    *default_class = NULL;
  274. ConfigItem_admin    *conf_admin = NULL;
  275. ConfigItem_admin    *conf_admin_tail = NULL;
  276. ConfigItem_drpass   *conf_drpass = NULL;
  277. ConfigItem_ulines   *conf_ulines = NULL;
  278. ConfigItem_tld      *conf_tld = NULL;
  279. ConfigItem_oper     *conf_oper = NULL;
  280. ConfigItem_operclass    *conf_operclass = NULL;
  281. ConfigItem_listen   *conf_listen = NULL;
  282. ConfigItem_allow    *conf_allow = NULL;
  283. ConfigItem_except   *conf_except = NULL;
  284. ConfigItem_vhost    *conf_vhost = NULL;
  285. ConfigItem_link     *conf_link = NULL;
  286. ConfigItem_ban      *conf_ban = NULL;
  287. ConfigItem_deny_dcc     *conf_deny_dcc = NULL;
  288. ConfigItem_deny_channel *conf_deny_channel = NULL;
  289. ConfigItem_allow_channel *conf_allow_channel = NULL;
  290. ConfigItem_allow_dcc    *conf_allow_dcc = NULL;
  291. ConfigItem_deny_link    *conf_deny_link = NULL;
  292. ConfigItem_deny_version *conf_deny_version = NULL;
  293. ConfigItem_log      *conf_log = NULL;
  294. ConfigItem_alias    *conf_alias = NULL;
  295. ConfigItem_include  *conf_include = NULL;
  296. ConfigItem_help     *conf_help = NULL;
  297. ConfigItem_offchans *conf_offchans = NULL;
  298.  
  299. MODVAR aConfiguration       iConf;
  300. MODVAR aConfiguration       tempiConf;
  301. MODVAR ConfigFile       *conf = NULL;
  302. MODVAR int ipv6_disabled = 0;
  303. MODVAR aClient *remote_rehash_client = NULL;
  304.  
  305. MODVAR int          config_error_flag = 0;
  306. int         config_verbose = 0;
  307.  
  308. MODVAR int need_34_upgrade = 0;
  309.  
  310. void add_include(const char *filename, const char *included_from, int included_from_line);
  311. #ifdef USE_LIBCURL
  312. void add_remote_include(const char *, const char *, int, const char *, const char *included_from, int included_from_line);
  313. void update_remote_include(ConfigItem_include *inc, const char *file, int, const char *errorbuf);
  314. int remote_include(ConfigEntry *ce);
  315. #endif
  316. void unload_notloaded_includes(void);
  317. void load_includes(void);
  318. void unload_loaded_includes(void);
  319. int rehash_internal(aClient *cptr, aClient *sptr, int sig);
  320.  
  321.  
  322. void port_range(char *string, int *start, int *end)
  323. {
  324.     char *c = strchr(string, '-');
  325.     if (!c)
  326.     {
  327.         int tmp = atoi(string);
  328.         *start = tmp;
  329.         *end = tmp;
  330.         return;
  331.     }
  332.     *c = '\0';
  333.     *start = atoi(string);
  334.     *end = atoi((c+1));
  335.     *c = '-';
  336. }
  337.  
  338. /** Parses '5:60s' config values.
  339.  * orig: original string
  340.  * times: pointer to int, first value (before the :)
  341.  * period: pointer to int, second value (after the :) in seconds
  342.  * RETURNS: 0 for parse error, 1 if ok.
  343.  * REMARK: times&period should be ints!
  344.  */
  345. int config_parse_flood(char *orig, int *times, int *period)
  346. {
  347. char *x;
  348.  
  349.     *times = *period = 0;
  350.     x = strchr(orig, ':');
  351.     /* 'blah', ':blah', '1:' */
  352.     if (!x || (x == orig) || (*(x+1) == '\0'))
  353.         return 0;
  354.  
  355.     *x = '\0';
  356.     *times = atoi(orig);
  357.     *period = config_checkval(x+1, CFG_TIME);
  358.     *x = ':'; /* restore */
  359.     return 1;
  360. }
  361.  
  362. long config_checkval(char *orig, unsigned short flags) {
  363.     char *value;
  364.     char *text;
  365.     long ret = 0;
  366.  
  367.     value = strdup(orig);
  368.  
  369.     if (flags == CFG_YESNO) {
  370.         for (text = value; *text; text++) {
  371.             if (!isalnum(*text))
  372.                 continue;
  373.             if (tolower(*text) == 'y' || (tolower(*text) == 'o' &&
  374.                 tolower(*(text+1)) == 'n') || *text == '1' || tolower(*text) == 't') {
  375.                 ret = 1;
  376.                 break;
  377.             }
  378.         }
  379.     }
  380.     else if (flags == CFG_SIZE) {
  381.         int mfactor = 1;
  382.         char *sz;
  383.         for (text = value; *text; text++) {
  384.             if (isalpha(*text)) {
  385.                 if (tolower(*text) == 'k')
  386.                     mfactor = 1024;
  387.                 else if (tolower(*text) == 'm')
  388.                     mfactor = 1048576;
  389.                 else if (tolower(*text) == 'g')
  390.                     mfactor = 1073741824;
  391.                 else
  392.                     mfactor = 1;
  393.                 sz = text;
  394.                 while (isalpha(*text))
  395.                     text++;
  396.  
  397.                 *sz-- = 0;
  398.                 while (sz-- > value && *sz) {
  399.                     if (isspace(*sz))
  400.                         *sz = 0;
  401.                     if (!isdigit(*sz))
  402.                         break;
  403.                 }
  404.                 ret += atoi(sz+1)*mfactor;
  405.                 if (*text == '\0') {
  406.                     text++;
  407.                     break;
  408.                 }
  409.             }
  410.         }
  411.         mfactor = 1;
  412.         sz = text;
  413.         sz--;
  414.         while (sz-- > value) {
  415.             if (isspace(*sz))
  416.                 *sz = 0;
  417.             if (!isdigit(*sz))
  418.                 break;
  419.         }
  420.         ret += atoi(sz+1)*mfactor;
  421.     }
  422.     else if (flags == CFG_TIME) {
  423.         int mfactor = 1;
  424.         char *sz;
  425.         for (text = value; *text; text++) {
  426.             if (isalpha(*text)) {
  427.                 if (tolower(*text) == 'w')
  428.                     mfactor = 604800;
  429.                 else if (tolower(*text) == 'd')
  430.                     mfactor = 86400;
  431.                 else if (tolower(*text) == 'h')
  432.                     mfactor = 3600;
  433.                 else if (tolower(*text) == 'm')
  434.                     mfactor = 60;
  435.                 else
  436.                     mfactor = 1;
  437.                 sz = text;
  438.                 while (isalpha(*text))
  439.                     text++;
  440.  
  441.                 *sz-- = 0;
  442.                 while (sz-- > value && *sz) {
  443.                     if (isspace(*sz))
  444.                         *sz = 0;
  445.                     if (!isdigit(*sz))
  446.                         break;
  447.                 }
  448.                 ret += atoi(sz+1)*mfactor;
  449.                 if (*text == '\0') {
  450.                     text++;
  451.                     break;
  452.                 }
  453.             }
  454.         }
  455.         mfactor = 1;
  456.         sz = text;
  457.         sz--;
  458.         while (sz-- > value) {
  459.             if (isspace(*sz))
  460.                 *sz = 0;
  461.             if (!isdigit(*sz))
  462.                 break;
  463.         }
  464.         ret += atoi(sz+1)*mfactor;
  465.     }
  466.     free(value);
  467.     return ret;
  468. }
  469.  
  470. void set_channelmodes(char *modes, struct ChMode *store, int warn)
  471. {
  472.     aCtab *tab;
  473.     char *params = strchr(modes, ' ');
  474.     char *parambuf = NULL;
  475.     char *param = NULL;
  476.     char *save = NULL;
  477.  
  478.     warn = 0; // warn is broken
  479.  
  480.     if (params)
  481.     {
  482.         params++;
  483.         parambuf = strdup(params);
  484.         param = strtoken(&save, parambuf, " ");
  485.     }
  486.  
  487.     for (; *modes && *modes != ' '; modes++)
  488.     {
  489.         if (*modes == '+')
  490.             continue;
  491.         if (*modes == '-')
  492.         /* When a channel is created it has no modes, so just ignore if the
  493.          * user asks us to unset anything -- codemastr
  494.          */
  495.         {
  496.             while (*modes && *modes != '+')
  497.                 modes++;
  498.             continue;
  499.         }
  500.         for (tab = &cFlagTab[0]; tab->mode; tab++)
  501.         {
  502.             if (tab->flag == *modes)
  503.             {
  504.                 if (tab->parameters)
  505.                 {
  506.                     /* INCOMPATIBLE */
  507.                     break;
  508.                 }
  509.                 store->mode |= tab->mode;
  510.                 break;
  511.             }
  512.         }
  513.         /* Try extcmodes */
  514.         if (!tab->mode)
  515.         {
  516.             int i;
  517.             for (i=0; i <= Channelmode_highest; i++)
  518.             {
  519.                 if (!(Channelmode_Table[i].flag))
  520.                     continue;
  521.                 if (*modes == Channelmode_Table[i].flag)
  522.                 {
  523.                     if (Channelmode_Table[i].paracount)
  524.                     {
  525.                         if (!param)
  526.                             break;
  527.                         param = Channelmode_Table[i].conv_param(param, NULL);
  528.                         if (!param)
  529.                             break; /* invalid parameter fmt, do not set mode. */
  530.                         store->extparams[i] = strdup(param);
  531.                         /* Get next parameter */
  532.                         param = strtoken(&save, NULL, " ");
  533.                     }
  534.                     store->extmodes |= Channelmode_Table[i].mode;
  535.                     break;
  536.                 }
  537.             }
  538.         }
  539.     }
  540.     if (parambuf)
  541.         free(parambuf);
  542. }
  543.  
  544. void chmode_str(struct ChMode *modes, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size)
  545. {
  546.     aCtab *tab;
  547.     int i;
  548.  
  549.         if (!(mbuf_size && pbuf_size)) return;
  550.  
  551.     *pbuf = 0;
  552.     *mbuf++ = '+';
  553.     if (--mbuf_size == 0) return;
  554.     for (tab = &cFlagTab[0]; tab->mode; tab++)
  555.     {
  556.         if (modes->mode & tab->mode)
  557.         {
  558.             if (!tab->parameters) {
  559.                 *mbuf++ = tab->flag;
  560.                 if (!--mbuf_size) {
  561.                     *--mbuf=0;
  562.                     break;
  563.                 }
  564.                         }
  565.         }
  566.     }
  567.     for (i=0; i <= Channelmode_highest; i++)
  568.     {
  569.         if (!(Channelmode_Table[i].flag))
  570.             continue;
  571.  
  572.         if (modes->extmodes & Channelmode_Table[i].mode)
  573.         {
  574.             if (mbuf_size) {
  575.                 *mbuf++ = Channelmode_Table[i].flag;
  576.                 if (!--mbuf_size) {
  577.                     *--mbuf=0;
  578.                     break;
  579.                 }
  580.             }
  581.             if (Channelmode_Table[i].paracount)
  582.             {
  583.                 strncat(pbuf, modes->extparams[i], pbuf_size-1);
  584.                 pbuf_size-=strlen(modes->extparams[i]);
  585.                 if (!pbuf_size) break;
  586.                 strncat(pbuf, " ", pbuf_size-1);
  587.                 if (!--pbuf_size) break;
  588.             }
  589.         }
  590.     }
  591.     *mbuf=0;
  592. }
  593.  
  594. int channellevel_to_int(char *s)
  595. {
  596.     /* Requested at http://bugs.unrealircd.org/view.php?id=3852 */
  597.     if (!strcmp(s, "none"))
  598.         return CHFL_DEOPPED;
  599.     if (!strcmp(s, "voice"))
  600.         return CHFL_VOICE;
  601.     if (!strcmp(s, "halfop"))
  602.         return CHFL_HALFOP;
  603.     if (!strcmp(s, "op") || !strcmp(s, "chanop"))
  604.         return CHFL_CHANOP;
  605.     if (!strcmp(s, "protect") || !strcmp(s, "chanprot"))
  606. #ifdef PREFIX_AQ
  607.         return CHFL_CHANPROT;
  608. #else
  609.         return CHFL_CHANOP|CHFL_CHANPROT;
  610. #endif
  611.     if (!strcmp(s, "owner") || !strcmp(s, "chanowner"))
  612. #ifdef PREFIX_AQ
  613.         return CHFL_CHANOWNER;
  614. #else
  615.         return CHFL_CHANOP|CHFL_CHANOWNER;
  616. #endif
  617.  
  618.     return 0; /* unknown or unsupported */
  619. }
  620.  
  621. /* Channel flag (eg: CHFL_CHANOWNER) to SJOIN symbol (eg: *).
  622.  * WARNING: Do not confuse SJOIN symbols with prefixes in /NAMES!
  623.  */
  624. char *chfl_to_sjoin_symbol(int s)
  625. {
  626.     switch(s)
  627.     {
  628.         case CHFL_VOICE:
  629.             return "+";
  630.         case CHFL_HALFOP:
  631.             return "%";
  632.         case CHFL_CHANOP:
  633.             return "@";
  634.         case CHFL_CHANPROT:
  635. #ifdef PREFIX_AQ
  636.             return "~";
  637. #else
  638.             return "~@";
  639. #endif
  640.         case CHFL_CHANOWNER:
  641. #ifdef PREFIX_AQ
  642.             return "*";
  643. #else
  644.             return "*@";
  645. #endif
  646.         case CHFL_DEOPPED:
  647.         default:
  648.             return "";
  649.     }
  650.     /* NOT REACHED */
  651. }
  652.  
  653. char chfl_to_chanmode(int s)
  654. {
  655.     switch(s)
  656.     {
  657.         case CHFL_VOICE:
  658.             return 'v';
  659.         case CHFL_HALFOP:
  660.             return 'h';
  661.         case CHFL_CHANOP:
  662.             return 'o';
  663.         case CHFL_CHANPROT:
  664.             return 'a';
  665.         case CHFL_CHANOWNER:
  666.             return 'q';
  667.         case CHFL_DEOPPED:
  668.         default:
  669.             return '\0';
  670.     }
  671.     /* NOT REACHED */
  672. }
  673.  
  674. ConfigFile *config_load(char *filename)
  675. {
  676.     struct stat sb;
  677.     int         fd;
  678.     int         ret;
  679.     char        *buf = NULL;
  680.     ConfigFile  *cfptr;
  681.  
  682. #ifndef _WIN32
  683.     fd = open(filename, O_RDONLY);
  684. #else
  685.     fd = open(filename, O_RDONLY|O_BINARY);
  686. #endif
  687.     if (fd == -1)
  688.     {
  689.         config_error("Couldn't open \"%s\": %s\n", filename, strerror(errno));
  690.         return NULL;
  691.     }
  692.     if (fstat(fd, &sb) == -1)
  693.     {
  694.         config_error("Couldn't fstat \"%s\": %s\n", filename, strerror(errno));
  695.         close(fd);
  696.         return NULL;
  697.     }
  698.     if (!sb.st_size)
  699.     {
  700.         /* Workaround for empty files */
  701.         cfptr = config_parse(filename, " ");
  702.         close(fd);
  703.         return cfptr;
  704.     }
  705.     buf = MyMalloc(sb.st_size+1);
  706.     if (buf == NULL)
  707.     {
  708.         config_error("Out of memory trying to load \"%s\"\n", filename);
  709.         close(fd);
  710.         return NULL;
  711.     }
  712.     ret = read(fd, buf, sb.st_size);
  713.     if (ret != sb.st_size)
  714.     {
  715.         config_error("Error reading \"%s\": %s\n", filename,
  716.             ret == -1 ? strerror(errno) : strerror(EFAULT));
  717.         free(buf);
  718.         close(fd);
  719.         return NULL;
  720.     }
  721.     /* Just me or could this cause memory corrupted when ret <0 ? */
  722.     buf[ret] = '\0';
  723.     close(fd);
  724.     add_entropy_configfile(&sb, buf);
  725.     cfptr = config_parse(filename, buf);
  726.     free(buf);
  727.     return cfptr;
  728. }
  729.  
  730. void config_free(ConfigFile *cfptr)
  731. {
  732.     ConfigFile  *nptr;
  733.  
  734.     for(;cfptr;cfptr=nptr)
  735.     {
  736.         nptr = cfptr->cf_next;
  737.         if (cfptr->cf_entries)
  738.             config_entry_free(cfptr->cf_entries);
  739.         if (cfptr->cf_filename)
  740.             free(cfptr->cf_filename);
  741.         free(cfptr);
  742.     }
  743. }
  744.  
  745. /** Remove quotes so that 'hello \"all\" \\ lala' becomes 'hello "all" \ lala' */
  746. void unreal_delquotes(char *i)
  747. {
  748.     char *o;
  749.  
  750.     for (o = i; *i; i++)
  751.     {
  752.         if (*i == '\\')
  753.         {
  754.             if ((i[1] == '\\') || (i[1] == '"'))
  755.             {
  756.                 i++; /* skip original \ */
  757.                 if (*i == '\0')
  758.                     break;
  759.             }
  760.         }
  761.         *o++ = *i;
  762.     }
  763.     *o = '\0';
  764. }
  765.  
  766. /* This is the internal parser, made by Chris Behrens & Fred Jacobs */
  767. static ConfigFile *config_parse(char *filename, char *confdata)
  768. {
  769.     char        *ptr;
  770.     char        *start;
  771.     int     linenumber = 1;
  772.     int errors = 0;
  773.     ConfigEntry *curce;
  774.     ConfigEntry **lastce;
  775.     ConfigEntry *cursection;
  776.  
  777.     ConfigFile  *curcf;
  778.     ConfigFile  *lastcf;
  779.  
  780.     lastcf = curcf = MyMalloc(sizeof(ConfigFile));
  781.     memset(curcf, 0, sizeof(ConfigFile));
  782.     curcf->cf_filename = strdup(filename);
  783.     lastce = &(curcf->cf_entries);
  784.     curce = NULL;
  785.     cursection = NULL;
  786.     /* Replace \r's with spaces .. ugly ugly -Stskeeps */
  787.     for (ptr=confdata; *ptr; ptr++)
  788.         if (*ptr == '\r')
  789.             *ptr = ' ';
  790.  
  791.     for(ptr=confdata;*ptr;ptr++)
  792.     {
  793.         switch(*ptr)
  794.         {
  795.             case ';':
  796.                 if (!curce)
  797.                 {
  798.                     config_status("%s:%i Ignoring extra semicolon\n",
  799.                         filename, linenumber);
  800.                     break;
  801.                 }
  802.                 *lastce = curce;
  803.                 lastce = &(curce->ce_next);
  804.                 curce->ce_fileposend = (ptr - confdata);
  805.                 curce = NULL;
  806.                 break;
  807.             case '{':
  808.                 if (!curce)
  809.                 {
  810.                     config_error("%s:%i: New section start detected on line %d but the section has no name. "
  811.                                  "Sections should start with a name like 'oper {' or 'set {'.",
  812.                             filename, linenumber, linenumber);
  813.                     errors++;
  814.                     continue;
  815.                 }
  816.                 else if (curce->ce_entries)
  817.                 {
  818.                     config_error("%s:%i: New section start but previous section did not end properly. "
  819.                                  "Check line %d and the line(s) before, you are likely missing a '};' there.\n",
  820.                             filename, linenumber, linenumber);
  821.                     errors++;
  822.                     continue;
  823.                 }
  824.                 curce->ce_sectlinenum = linenumber;
  825.                 lastce = &(curce->ce_entries);
  826.                 cursection = curce;
  827.                 curce = NULL;
  828.                 break;
  829.             case '}':
  830.                 if (curce)
  831.                 {
  832.                     config_error("%s:%i: Missing semicolon (';') before close brace. Check line %d and the line(s) before.\n",
  833.                         filename, linenumber, linenumber);
  834.                     config_entry_free(curce);
  835.                     config_free(curcf);
  836.                     errors++;
  837.                     return NULL;
  838.                 }
  839.                 else if (!cursection)
  840.                 {
  841.                     config_error("%s:%i: You have a close brace ('};') too many. "
  842.                                   "Check line %d AND the lines above it from the previous block.\n",
  843.                         filename, linenumber, linenumber);
  844.                     errors++;
  845.                     continue;
  846.                 }
  847.                 curce = cursection;
  848.                 cursection->ce_fileposend = (ptr - confdata);
  849.                 cursection = cursection->ce_prevlevel;
  850.                 if (!cursection)
  851.                     lastce = &(curcf->cf_entries);
  852.                 else
  853.                     lastce = &(cursection->ce_entries);
  854.                 for(;*lastce;lastce = &((*lastce)->ce_next))
  855.                     continue;
  856.                 break;
  857.             case '#':
  858.                 ptr++;
  859.                 while(*ptr && (*ptr != '\n'))
  860.                      ptr++;
  861.                 if (!*ptr)
  862.                     break;
  863.                 ptr--;
  864.                 continue;
  865.             case '/':
  866.                 if (*(ptr+1) == '/')
  867.                 {
  868.                     ptr += 2;
  869.                     while(*ptr && (*ptr != '\n'))
  870.                         ptr++;
  871.                     if (!*ptr)
  872.                         break;
  873.                     ptr--; /* grab the \n on next loop thru */
  874.                     continue;
  875.                 }
  876.                 else if (*(ptr+1) == '*')
  877.                 {
  878.                     int commentstart = linenumber;
  879.                     int commentlevel = 1;
  880.  
  881.                     for(ptr+=2;*ptr;ptr++)
  882.                     {
  883.                         if ((*ptr == '/') && (*(ptr+1) == '*'))
  884.                         {
  885.                             commentlevel++;
  886.                             ptr++;
  887.                         }
  888.  
  889.                         else if ((*ptr == '*') && (*(ptr+1) == '/'))
  890.                         {
  891.                             commentlevel--;
  892.                             ptr++;
  893.                         }
  894.  
  895.                         else if (*ptr == '\n')
  896.                             linenumber++;
  897.  
  898.                         if (!commentlevel)
  899.                             break;
  900.                     }
  901.                     if (!*ptr)
  902.                     {
  903.                         config_error("%s:%i Comment on line %d does not end\n",
  904.                             filename, commentstart, commentstart);
  905.                         errors++;
  906.                         config_entry_free(curce);
  907.                         config_free(curcf);
  908.                         return NULL;
  909.                     }
  910.                 }
  911.                 break;
  912.             case '\"':
  913.                 if (curce && curce->ce_varlinenum != linenumber && cursection)
  914.                 {
  915.                     config_error("%s:%i: Missing semicolon (';') at end of line. "
  916.                                  "Line %d must end with a ; character\n",
  917.                         filename, curce->ce_varlinenum, curce->ce_varlinenum);
  918.                     errors++;
  919.  
  920.                     *lastce = curce;
  921.                     lastce = &(curce->ce_next);
  922.                     curce->ce_fileposend = (ptr - confdata);
  923.                     curce = NULL;
  924.                 }
  925.  
  926.                 start = ++ptr;
  927.                 for(;*ptr;ptr++)
  928.                 {
  929.                     if (*ptr == '\\')
  930.                     {
  931.                         if ((ptr[1] == '\\') || (ptr[1] == '"'))
  932.                         {
  933.                             /* \\ or \" in config file (escaped) */
  934.                             ptr++; /* skip */
  935.                             continue;
  936.                         }
  937.                     }
  938.                     else if ((*ptr == '\"') || (*ptr == '\n'))
  939.                         break;
  940.                 }
  941.                 if (!*ptr || (*ptr == '\n'))
  942.                 {
  943.                     config_error("%s:%i: Unterminated quote found\n",
  944.                             filename, linenumber);
  945.                     errors++;
  946.                     config_entry_free(curce);
  947.                     config_free(curcf);
  948.                     return NULL;
  949.                 }
  950.                 if (curce)
  951.                 {
  952.                     if (curce->ce_vardata)
  953.                     {
  954.                         config_error("%s:%i: Extra data detected. Perhaps missing a ';' or one too many?\n",
  955.                             filename, linenumber);
  956.                         errors++;
  957.                     }
  958.                     else
  959.                     {
  960.                         curce->ce_vardata = MyMalloc(ptr-start+1);
  961.                         strlcpy(curce->ce_vardata, start, ptr-start+1);
  962.                         unreal_delquotes(curce->ce_vardata);
  963.                     }
  964.                 }
  965.                 else
  966.                 {
  967.                     curce = MyMalloc(sizeof(ConfigEntry));
  968.                     memset(curce, 0, sizeof(ConfigEntry));
  969.                     curce->ce_varname = MyMalloc((ptr-start)+1);
  970.                     strlcpy(curce->ce_varname, start, ptr-start+1);
  971.                     unreal_delquotes(curce->ce_varname);
  972.                     curce->ce_varlinenum = linenumber;
  973.                     curce->ce_fileptr = curcf;
  974.                     curce->ce_prevlevel = cursection;
  975.                     curce->ce_fileposstart = (start - confdata);
  976.                 }
  977.                 break;
  978.             case '\n':
  979.                 linenumber++;
  980.                 /* fall through */
  981.             case '\t':
  982.             case ' ':
  983.             case '=':
  984.             case '\r':
  985.                 break;
  986.             default:
  987.                 if ((*ptr == '*') && (*(ptr+1) == '/'))
  988.                 {
  989.                     config_status("%s:%i Ignoring extra end comment\n",
  990.                         filename, linenumber);
  991.                     ptr++;
  992.                     break;
  993.                 }
  994.                 start = ptr;
  995.                 for(;*ptr;ptr++)
  996.                 {
  997.                     if ((*ptr == ' ') || (*ptr == '=') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == ';'))
  998.                         break;
  999.                 }
  1000.                 if (!*ptr)
  1001.                 {
  1002.                     if (curce)
  1003.                         config_error("%s: End of file reached but directive or block at line %i did not end properly. "
  1004.                                      "Perhaps a missing ; (semicolon) somewhere?\n",
  1005.                             filename, curce->ce_varlinenum);
  1006.                     else if (cursection)
  1007.                         config_error("%s: End of file reached but the section which starts at line %i did never end properly. "
  1008.                                      "Perhaps a missing }; ?\n",
  1009.                                 filename, cursection->ce_sectlinenum);
  1010.                     else
  1011.                         config_error("%s: Unexpected end of file. Some line or block did not end properly. "
  1012.                                      "Look for any missing } and };\n", filename);
  1013.                     errors++;
  1014.                     config_entry_free(curce);
  1015.                     config_free(curcf);
  1016.                     return NULL;
  1017.                 }
  1018.                 if (curce)
  1019.                 {
  1020.                     if (curce->ce_vardata)
  1021.                     {
  1022.                         config_error("%s:%i: Extra data detected. Check for a missing ; character at or around line %d\n",
  1023.                             filename, linenumber, linenumber-1);
  1024.                         errors++;
  1025.                     }
  1026.                     else
  1027.                     {
  1028.                         curce->ce_vardata = MyMalloc(ptr-start+1);
  1029.                         strlcpy(curce->ce_vardata, start, ptr-start+1);
  1030.                     }
  1031.                 }
  1032.                 else
  1033.                 {
  1034.                     curce = MyMalloc(sizeof(ConfigEntry));
  1035.                     memset(curce, 0, sizeof(ConfigEntry));
  1036.                     curce->ce_varname = MyMalloc((ptr-start)+1);
  1037.                     strlcpy(curce->ce_varname, start, ptr-start+1);
  1038.                     curce->ce_varlinenum = linenumber;
  1039.                     curce->ce_fileptr = curcf;
  1040.                     curce->ce_prevlevel = cursection;
  1041.                     curce->ce_fileposstart = (start - confdata);
  1042.                 }
  1043.                 if ((*ptr == ';') || (*ptr == '\n'))
  1044.                     ptr--;
  1045.                 break;
  1046.         } /* switch */
  1047.         if (!*ptr) /* This IS possible. -- Syzop */
  1048.             break;
  1049.     } /* for */
  1050.  
  1051.     if (curce)
  1052.     {
  1053.         config_error("%s: End of file reached but directive or block at line %i did not end properly. "
  1054.                      "Perhaps a missing ; (semicolon) somewhere?\n",
  1055.             filename, curce->ce_varlinenum);
  1056.         errors++;
  1057.         config_entry_free(curce);
  1058.     }
  1059.     else if (cursection)
  1060.     {
  1061.         config_error("%s: End of file reached but the section which starts at line %i did never end properly. "
  1062.                      "Perhaps a missing }; ?\n",
  1063.                 filename, cursection->ce_sectlinenum);
  1064.         errors++;
  1065.     }
  1066.  
  1067.     if (errors)
  1068.     {
  1069.         config_free(curcf);
  1070.         return NULL;
  1071.     }
  1072.     return curcf;
  1073. }
  1074.  
  1075. static void config_entry_free(ConfigEntry *ceptr)
  1076. {
  1077.     ConfigEntry *nptr;
  1078.  
  1079.     for(;ceptr;ceptr=nptr)
  1080.     {
  1081.         nptr = ceptr->ce_next;
  1082.         if (ceptr->ce_entries)
  1083.             config_entry_free(ceptr->ce_entries);
  1084.         if (ceptr->ce_varname)
  1085.             free(ceptr->ce_varname);
  1086.         if (ceptr->ce_vardata)
  1087.             free(ceptr->ce_vardata);
  1088.         free(ceptr);
  1089.     }
  1090. }
  1091.  
  1092. ConfigEntry     *config_find_entry(ConfigEntry *ce, char *name)
  1093. {
  1094.     ConfigEntry *cep;
  1095.  
  1096.     for (cep = ce; cep; cep = cep->ce_next)
  1097.         if (cep->ce_varname && !strcmp(cep->ce_varname, name))
  1098.             break;
  1099.     return cep;
  1100. }
  1101.  
  1102. void config_error(char *format, ...)
  1103. {
  1104.     va_list     ap;
  1105.     char        buffer[1024];
  1106.     char        *ptr;
  1107.  
  1108.     va_start(ap, format);
  1109.     vsnprintf(buffer, sizeof(buffer), format, ap);
  1110.     va_end(ap);
  1111.     if ((ptr = strchr(buffer, '\n')) != NULL)
  1112.         *ptr = '\0';
  1113. #ifdef _WIN32
  1114.     if (!loop.ircd_booted)
  1115.         win_log("[error] %s", buffer);
  1116. #endif
  1117.     ircd_log(LOG_ERROR, "config error: %s", buffer);
  1118.     sendto_realops("error: %s", buffer);
  1119.     if (remote_rehash_client)
  1120.         sendto_one(remote_rehash_client, ":%s NOTICE %s :error: %s", me.name, remote_rehash_client->name, buffer);
  1121.     /* We cannot live with this */
  1122.     config_error_flag = 1;
  1123. }
  1124.  
  1125. void config_error_missing(const char *filename, int line, const char *entry)
  1126. {
  1127.     config_error("%s:%d: %s is missing", filename, line, entry);
  1128. }
  1129.  
  1130. void config_error_unknown(const char *filename, int line, const char *block,
  1131.     const char *entry)
  1132. {
  1133.     config_error("%s:%d: Unknown directive '%s::%s'", filename, line, block, entry);
  1134. }
  1135.  
  1136. void config_error_unknownflag(const char *filename, int line, const char *block,
  1137.     const char *entry)
  1138. {
  1139.     config_error("%s:%d: Unknown %s flag '%s'", filename, line, block, entry);
  1140. }
  1141.  
  1142. void config_error_unknownopt(const char *filename, int line, const char *block,
  1143.     const char *entry)
  1144. {
  1145.     config_error("%s:%d: Unknown %s option '%s'", filename, line, block, entry);
  1146. }
  1147.  
  1148. void config_error_noname(const char *filename, int line, const char *block)
  1149. {
  1150.     config_error("%s:%d: %s block has no name", filename, line, block);
  1151. }
  1152.  
  1153. void config_error_blank(const char *filename, int line, const char *block)
  1154. {
  1155.     config_error("%s:%d: Blank %s entry", filename, line, block);
  1156. }
  1157.  
  1158. void config_error_empty(const char *filename, int line, const char *block,
  1159.     const char *entry)
  1160. {
  1161.     config_error("%s:%d: %s::%s specified without a value",
  1162.         filename, line, block, entry);
  1163. }
  1164.  
  1165. void config_status(char *format, ...)
  1166. {
  1167.     va_list     ap;
  1168.     char        buffer[1024];
  1169.     char        *ptr;
  1170.  
  1171.     va_start(ap, format);
  1172.     vsnprintf(buffer, 1023, format, ap);
  1173.     va_end(ap);
  1174.     if ((ptr = strchr(buffer, '\n')) != NULL)
  1175.         *ptr = '\0';
  1176. #ifdef _WIN32
  1177.     if (!loop.ircd_booted)
  1178.         win_log("* %s", buffer);
  1179. #endif
  1180.     ircd_log(LOG_ERROR, "%s", buffer);
  1181.     sendto_realops("%s", buffer);
  1182.     if (remote_rehash_client)
  1183.         sendto_one(remote_rehash_client, ":%s NOTICE %s :%s", me.name, remote_rehash_client->name, buffer);
  1184. }
  1185.  
  1186. void config_warn(char *format, ...)
  1187. {
  1188.     va_list     ap;
  1189.     char        buffer[1024];
  1190.     char        *ptr;
  1191.  
  1192.     va_start(ap, format);
  1193.     vsnprintf(buffer, 1023, format, ap);
  1194.     va_end(ap);
  1195.     if ((ptr = strchr(buffer, '\n')) != NULL)
  1196.         *ptr = '\0';
  1197. #ifdef _WIN32
  1198.     if (!loop.ircd_booted)
  1199.         win_log("[warning] %s", buffer);
  1200. #endif
  1201.     ircd_log(LOG_ERROR, "[warning] %s", buffer);
  1202.     sendto_realops("[warning] %s", buffer);
  1203.     if (remote_rehash_client)
  1204.         sendto_one(remote_rehash_client, ":%s NOTICE %s :[warning] %s", me.name, remote_rehash_client->name, buffer);
  1205. }
  1206.  
  1207. void config_warn_duplicate(const char *filename, int line, const char *entry)
  1208. {
  1209.     config_warn("%s:%d: Duplicate %s directive", filename, line, entry);
  1210. }
  1211.  
  1212. /* returns 1 if the test fails */
  1213. int config_test_openfile(ConfigEntry *cep, int flags, mode_t mode, const char *entry, int fatal, int allow_url)
  1214. {
  1215.     int fd;
  1216.  
  1217.     if(!cep->ce_vardata)
  1218.     {
  1219.         if(fatal)
  1220.             config_error("%s:%i: %s: <no file specified>: no file specified",
  1221.                      cep->ce_fileptr->cf_filename,
  1222.                      cep->ce_varlinenum,
  1223.                      entry);
  1224.         else
  1225.  
  1226.             config_warn("%s:%i: %s: <no file specified>: no file specified",
  1227.                     cep->ce_fileptr->cf_filename,
  1228.                     cep->ce_varlinenum,
  1229.                     entry);
  1230.         return 1;
  1231.     }
  1232.  
  1233.     /* There's not much checking that can be done for asynchronously downloaded files */
  1234. #ifdef USE_LIBCURL
  1235.     if(url_is_valid(cep->ce_vardata))
  1236.     {
  1237.         if(allow_url)
  1238.             return 0;
  1239.  
  1240.         /* but we can check if a URL is used wrongly :-) */
  1241.         config_warn("%s:%i: %s: %s: URL used where not allowed",
  1242.                 cep->ce_fileptr->cf_filename,
  1243.                 cep->ce_varlinenum,
  1244.                 entry, cep->ce_vardata);
  1245.         if(fatal)
  1246.             return 1;
  1247.         else
  1248.             return 0;
  1249.     }
  1250. #endif /* USE_LIBCURL */
  1251.  
  1252.     /*
  1253.      * Make sure that files are created with the correct mode. This is
  1254.      * because we don't feel like unlink()ing them...which would require
  1255.      * stat()ing them to make sure that we don't delete existing ones
  1256.      * and that we deal with all of the bugs that come with complexity.
  1257.      * The only files we may be creating are the tunefile and pidfile so far.
  1258.      */
  1259.     if(flags & O_CREAT)
  1260.         fd = open(cep->ce_vardata, flags, mode);
  1261.     else
  1262.         fd = open(cep->ce_vardata, flags);
  1263.     if(fd == -1)
  1264.     {
  1265.         if(fatal)
  1266.             config_error("%s:%i: %s: %s: %s",
  1267.                      cep->ce_fileptr->cf_filename,
  1268.                      cep->ce_varlinenum,
  1269.                      entry,
  1270.                      cep->ce_vardata,
  1271.                      strerror(errno));
  1272.         else
  1273.             config_warn("%s:%i: %s: %s: %s",
  1274.                      cep->ce_fileptr->cf_filename,
  1275.                      cep->ce_varlinenum,
  1276.                      entry,
  1277.                      cep->ce_vardata,
  1278.                      strerror(errno));
  1279.         return 1;
  1280.     }
  1281.     close(fd);
  1282.     return 0;
  1283. }
  1284.  
  1285. void config_progress(char *format, ...)
  1286. {
  1287.     va_list     ap;
  1288.     char        buffer[1024];
  1289.     char        *ptr;
  1290.  
  1291.     va_start(ap, format);
  1292.     vsnprintf(buffer, 1023, format, ap);
  1293.     va_end(ap);
  1294.     if ((ptr = strchr(buffer, '\n')) != NULL)
  1295.         *ptr = '\0';
  1296. #ifdef _WIN32
  1297.     if (!loop.ircd_booted)
  1298.         win_log("* %s", buffer);
  1299. #endif
  1300.     sendto_realops("%s", buffer);
  1301. }
  1302.  
  1303. int config_is_blankorempty(ConfigEntry *cep, const char *block)
  1304. {
  1305.     if (!cep->ce_varname)
  1306.     {
  1307.         config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block);
  1308.         return 1;
  1309.     }
  1310.     if (!cep->ce_vardata)
  1311.     {
  1312.         config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block,
  1313.             cep->ce_varname);
  1314.         return 1;
  1315.     }
  1316.     return 0;
  1317. }
  1318.  
  1319. ConfigCommand *config_binary_search(char *cmd) {
  1320.     int start = 0;
  1321.     int stop = ARRAY_SIZEOF(_ConfigCommands)-1;
  1322.     int mid;
  1323.     while (start <= stop) {
  1324.         mid = (start+stop)/2;
  1325.         if (smycmp(cmd,_ConfigCommands[mid].name) < 0) {
  1326.             stop = mid-1;
  1327.         }
  1328.         else if (strcmp(cmd,_ConfigCommands[mid].name) == 0) {
  1329.             return &_ConfigCommands[mid];
  1330.         }
  1331.         else
  1332.             start = mid+1;
  1333.     }
  1334.     return NULL;
  1335. }
  1336.  
  1337. void    free_iConf(aConfiguration *i)
  1338. {
  1339.     safefree(i->kline_address);
  1340.     safefree(i->gline_address);
  1341.     safefree(i->auto_join_chans);
  1342.     safefree(i->oper_auto_join_chans);
  1343.     safefree(i->oper_only_stats);
  1344.     safefree(i->channel_command_prefix);
  1345.     safefree(i->oper_snomask);
  1346.     safefree(i->user_snomask);
  1347.     safefree(i->egd_path);
  1348.     safefree(i->static_quit);
  1349.     safefree(i->x_server_cert_pem);
  1350.     safefree(i->x_server_key_pem);
  1351.     safefree(i->x_server_cipher_list);
  1352.     safefree(i->trusted_ca_file);
  1353.     safefree(i->restrict_usermodes);
  1354.     safefree(i->restrict_channelmodes);
  1355.     safefree(i->restrict_extendedbans);
  1356.     safefree(i->network.x_ircnetwork);
  1357.     safefree(i->network.x_ircnet005);
  1358.     safefree(i->network.x_defserv);
  1359.     safefree(i->network.x_services_name);
  1360.     safefree(i->network.x_hidden_host);
  1361.     safefree(i->network.x_prefix_quit);
  1362.     safefree(i->network.x_helpchan);
  1363.     safefree(i->network.x_stats_server);
  1364.     safefree(i->spamfilter_ban_reason);
  1365.     safefree(i->spamfilter_virus_help_channel);
  1366.     safefree(i->spamexcept_line);
  1367.     safefree(i->timesynch_server);
  1368.     safefree(i->link_bindip);
  1369. }
  1370.  
  1371. int config_test();
  1372.  
  1373. void config_setdefaultsettings(aConfiguration *i)
  1374. {
  1375.     char tmp[512];
  1376.  
  1377.     i->unknown_flood_amount = 4;
  1378.     i->unknown_flood_bantime = 600;
  1379.     i->oper_snomask = strdup(SNO_DEFOPER);
  1380.     i->ident_read_timeout = 30;
  1381.     i->ident_connect_timeout = 3;
  1382.     i->nick_count = 3; i->nick_period = 60; /* nickflood protection: max 3 per 60s */
  1383. #ifdef NO_FLOOD_AWAY
  1384.     i->away_count = 4; i->away_period = 120; /* awayflood protection: max 4 per 120s */
  1385. #endif
  1386.     i->throttle_count = 3; i->throttle_period = 60; /* throttle protection: max 3 per 60s */
  1387.     i->modef_default_unsettime = 0;
  1388.     i->modef_max_unsettime = 60; /* 1 hour seems enough :p */
  1389.     i->ban_version_tkl_time = 86400; /* 1d */
  1390.     i->spamfilter_ban_time = 86400; /* 1d */
  1391.     i->spamfilter_ban_reason = strdup("Spam/advertising");
  1392.     i->spamfilter_virus_help_channel = strdup("#help");
  1393.     i->spamfilter_detectslow_warn = 250;
  1394.     i->spamfilter_detectslow_fatal = 500;
  1395.     i->spamfilter_stop_on_first_match = 1;
  1396.     i->maxdccallow = 10;
  1397.     i->channel_command_prefix = strdup("`!.");
  1398.     i->check_target_nick_bans = 1;
  1399.     i->maxbans = 60;
  1400.     i->maxbanlength = 2048;
  1401.     i->timesynch_enabled = 1;
  1402.     i->timesynch_timeout = 3;
  1403.     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. */
  1404.     i->level_on_join = CHFL_CHANOP;
  1405.     i->watch_away_notification = 1;
  1406.     i->new_linking_protocol = 1;
  1407.     i->uhnames = 1;
  1408.     i->ping_cookie = 1;
  1409.     i->default_ipv6_clone_mask = 64;
  1410.     i->nicklen = NICKLEN;
  1411.     i->link_bindip = strdup("*");
  1412.     i->oper_only_stats = strdup("*");
  1413.     snprintf(tmp, sizeof(tmp), "%s/ssl/server.cert.pem", CONFDIR);
  1414.     i->x_server_cert_pem = strdup(tmp);
  1415.     snprintf(tmp, sizeof(tmp), "%s/ssl/server.key.pem", CONFDIR);
  1416.     i->x_server_key_pem = strdup(tmp);
  1417.     if (!ipv6_capable())
  1418.         DISABLE_IPV6 = 1;
  1419.     i->network.x_prefix_quit = strdup("Quit");
  1420. }
  1421.  
  1422. /* 1: needed for set::options::allow-part-if-shunned,
  1423.  * we can't just make it M_SHUN and do a ALLOW_PART_IF_SHUNNED in
  1424.  * m_part itself because that will also block internal calls (like sapart). -- Syzop
  1425.  * 2: now also used by spamfilter entries added by config...
  1426.  * we got a chicken-and-egg problem here.. antries added without reason or ban-time
  1427.  * field should use the config default (set::spamfilter::ban-reason/ban-time) but
  1428.  * this isn't (or might not) be known yet when parsing spamfilter entries..
  1429.  * so we do a VERY UGLY mass replace here.. unless someone else has a better idea.
  1430.  */
  1431. static void do_weird_shun_stuff()
  1432. {
  1433. aCommand *cmptr;
  1434. aTKline *tk;
  1435. char *encoded;
  1436.  
  1437.     if ((cmptr = find_Command_simple("PART")))
  1438.     {
  1439.         if (ALLOW_PART_IF_SHUNNED)
  1440.             cmptr->flags |= M_SHUN;
  1441.         else
  1442.             cmptr->flags &= ~M_SHUN;
  1443.     }
  1444.  
  1445.     encoded = unreal_encodespace(SPAMFILTER_BAN_REASON);
  1446.     if (!encoded)
  1447.         abort(); /* hack to trace 'impossible' bug... */
  1448.     for (tk = tklines[tkl_hash('q')]; tk; tk = tk->next)
  1449.     {
  1450.         if (tk->type != TKL_NICK)
  1451.             continue;
  1452.         if (!tk->setby)
  1453.         {
  1454.             if (me.name[0] != '\0')
  1455.                 tk->setby = strdup(me.name);
  1456.             else
  1457.                 tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
  1458.         }
  1459.     }
  1460.  
  1461.     for (tk = tklines[tkl_hash('f')]; tk; tk = tk->next)
  1462.     {
  1463.         if (tk->type != TKL_SPAMF)
  1464.             continue; /* global entry or something else.. */
  1465.         if (!strcmp(tk->ptr.spamf->tkl_reason, "<internally added by ircd>"))
  1466.         {
  1467.             MyFree(tk->ptr.spamf->tkl_reason);
  1468.             tk->ptr.spamf->tkl_reason = strdup(encoded);
  1469.             tk->ptr.spamf->tkl_duration = SPAMFILTER_BAN_TIME;
  1470.         }
  1471.         /* This one is even more ugly, but our config crap is VERY confusing :[ */
  1472.         if (!tk->setby)
  1473.         {
  1474.             if (me.name[0] != '\0')
  1475.                 tk->setby = strdup(me.name);
  1476.             else
  1477.                 tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
  1478.         }
  1479.     }
  1480.     if (loop.ircd_booted) /* only has to be done for rehashes, api-isupport takes care of boot */
  1481.     {
  1482.         if (WATCH_AWAY_NOTIFICATION)
  1483.         {
  1484.             IsupportAdd(NULL, "WATCHOPTS", "A");
  1485.         } else {
  1486.             Isupport *hunted = IsupportFind("WATCHOPTS");
  1487.             if (hunted)
  1488.                 IsupportDel(hunted);
  1489.         }
  1490.         if (UHNAMES_ENABLED)
  1491.         {
  1492.             IsupportAdd(NULL, "UHNAMES", NULL);
  1493.         } else {
  1494.             Isupport *hunted = IsupportFind("UHNAMES");
  1495.             if (hunted)
  1496.                 IsupportDel(hunted);
  1497.         }
  1498.     }
  1499. }
  1500.  
  1501. static void make_default_logblock(void)
  1502. {
  1503. ConfigItem_log *ca = MyMallocEx(sizeof(ConfigItem_log));
  1504.  
  1505.     config_status("No log { } block found -- using default: errors will be logged to 'ircd.log'");
  1506.  
  1507.     ca->file = strdup("ircd.log");
  1508.     ca->flags |= LOG_ERROR;
  1509.     ca->logfd = -1;
  1510.     AddListItem(ca, conf_log);
  1511. }
  1512.  
  1513. int isanyserverlinked(void)
  1514. {
  1515.     return !list_empty(&server_list);
  1516. }
  1517.  
  1518. void applymeblock(void)
  1519. {
  1520.     if (!conf_me)
  1521.         return; /* uh-huh? */
  1522.  
  1523.     /* Info text may always change, just wouldn't show up on other servers, that's all.. */
  1524.     strlcpy(me.info, conf_me->info, sizeof(me.info));
  1525.  
  1526.     /* Name can only be set once (on boot) */
  1527.     if (!*me.name)
  1528.         strlcpy(me.name, conf_me->name, sizeof(me.name));
  1529.  
  1530.     if (!*me.id)
  1531.         strlcpy(me.id, conf_me->sid, sizeof(me.id));
  1532. }
  1533.  
  1534. void upgrade_conf_to_34(void)
  1535. {
  1536.     config_error("******************************************************************");
  1537.     config_error("This *seems* an UnrealIRCd 3.2.x configuration file.");
  1538.  
  1539. #ifdef _WIN32
  1540.     if (!IsService)
  1541.         config_error("In next screen you will be prompted to automatically upgrade the configuration file(s).");
  1542.     else
  1543.     {
  1544.         config_error("We offer a configuration file converter to convert 3.2.x conf's to 4.0, however this "
  1545.                      "is not available when running as a service. If you want to use it, make UnrealIRCd "
  1546.                      "run in GUI mode by running 'unreal uninstall'. Then start UnrealIRCd.exe and when "
  1547.                      "it prompts you to convert the configuration click 'Yes'. Check if UnrealIRCd boots properly. "
  1548.                      "Once everything is looking good you can run 'unreal install' to make UnrealIRCd run "
  1549.                      "as a service again."); /* TODO: make this unnecessary :D */
  1550.     }
  1551. #else
  1552.     config_error("To upgrade it to the new 4.0 format, run: ./unrealircd upgrade-conf");
  1553. #endif
  1554.  
  1555.     config_error("******************************************************************");
  1556.     /* TODO: win32 may require a different error */
  1557. }
  1558.  
  1559. int init_conf(char *rootconf, int rehash)
  1560. {
  1561.     char *old_pid_file = NULL;
  1562.  
  1563.     config_status("Loading IRCd configuration..");
  1564.     if (conf)
  1565.     {
  1566.         config_error("%s:%i - Someone forgot to clean up", __FILE__, __LINE__);
  1567.         return -1;
  1568.     }
  1569.     bzero(&tempiConf, sizeof(iConf));
  1570.     bzero(&settings, sizeof(settings));
  1571.     bzero(&requiredstuff, sizeof(requiredstuff));
  1572.     config_setdefaultsettings(&tempiConf);
  1573.     /*
  1574.      * the rootconf must be listed in the conf_include for include
  1575.      * recursion prevention code and sanity checking code to be
  1576.      * made happy :-). Think of it as us implicitly making an
  1577.      * in-memory config file that looks like:
  1578.      *
  1579.      * include "unrealircd.conf";
  1580.      */
  1581.     add_include(rootconf, "[thin air]", -1);
  1582.     if (load_conf(rootconf, rootconf) > 0)
  1583.     {
  1584.         charsys_reset_pretest();
  1585.         if ((config_test() < 0) || (callbacks_check() < 0) || (efunctions_check() < 0) ||
  1586.             (charsys_postconftest() < 0) || ssl_used_in_config_but_unavail() || reloadable_perm_module_unloaded())
  1587.         {
  1588.             config_error("IRCd configuration failed to pass testing");
  1589. #ifdef _WIN32
  1590.             if (!rehash)
  1591.                 win_error();
  1592. #endif
  1593.             Unload_all_testing_modules();
  1594.             unload_notloaded_includes();
  1595.             config_free(conf);
  1596.             conf = NULL;
  1597.             free_iConf(&tempiConf);
  1598.             return -1;
  1599.         }
  1600.         callbacks_switchover();
  1601.         efunctions_switchover();
  1602.         if (rehash)
  1603.         {
  1604.             Hook *h;
  1605.             safestrdup(old_pid_file, conf_files->pid_file);
  1606.             unrealdns_delasyncconnects();
  1607.             config_rehash();
  1608.             Unload_all_loaded_modules();
  1609.  
  1610.             /* Notify permanent modules of the rehash */
  1611.             for (h = Hooks[HOOKTYPE_REHASH]; h; h = h->next)
  1612.                 {
  1613.                 if (!h->owner)
  1614.                     continue;
  1615.                 if (!(h->owner->options & MOD_OPT_PERM))
  1616.                     continue;
  1617.                 (*(h->func.intfunc))();
  1618.             }
  1619.             unload_loaded_includes();
  1620.         }
  1621.         load_includes();
  1622.         Init_all_testing_modules();
  1623.         charsys_reset();
  1624.         if (config_run() < 0)
  1625.         {
  1626.             config_error("Bad case of config errors. Server will now die. This really shouldn't happen");
  1627. #ifdef _WIN32
  1628.             if (!rehash)
  1629.                 win_error();
  1630. #endif
  1631.             abort();
  1632.         }
  1633.         charsys_finish();
  1634.         applymeblock();
  1635.         if (old_pid_file && strcmp(old_pid_file, conf_files->pid_file))
  1636.         {
  1637.             sendto_ops("pidfile is being rewritten to %s, please delete %s",
  1638.                    conf_files->pid_file,
  1639.                    old_pid_file);
  1640.             write_pidfile();
  1641.         }
  1642.         safefree(old_pid_file);
  1643.     }
  1644.     else
  1645.     {
  1646.         config_error("IRCd configuration failed to load");
  1647.         Unload_all_testing_modules();
  1648.         unload_notloaded_includes();
  1649.         config_free(conf);
  1650.         conf = NULL;
  1651.         free_iConf(&tempiConf);
  1652. #ifdef _WIN32
  1653.         if (!rehash)
  1654.             win_error();
  1655. #endif
  1656.         return -1;
  1657.     }
  1658.     config_free(conf);
  1659.     conf = NULL;
  1660.     if (rehash)
  1661.     {
  1662.         module_loadall();
  1663.         RunHook0(HOOKTYPE_REHASH_COMPLETE);
  1664.     }
  1665.     do_weird_shun_stuff();
  1666.     if (!conf_log)
  1667.         make_default_logblock();
  1668.     config_status("Configuration loaded without any problems.");
  1669.     return 0;
  1670. }
  1671.  
  1672. /**
  1673.  * Processes filename as part of the IRCd's configuration.
  1674.  *
  1675.  * One _must_ call add_include() or add_remote_include() before
  1676.  * calling load_conf(). This way, include recursion may be detected
  1677.  * and reported to the user as an error instead of causing the IRCd to
  1678.  * hang in an infinite recursion, eat up memory, and eventually
  1679.  * overflow its stack ;-). (reported by warg).
  1680.  *
  1681.  * This function will set INCLUDE_USED on the config_include list
  1682.  * entry if the config file loaded without error.
  1683.  *
  1684.  * @param filename the file where the conf may be read from
  1685.  * @param original_path the path or URL used to refer to this file.
  1686.  *        (mostly to support remote includes' URIs for recursive include detection).
  1687.  * @return 1 on success, a negative number on error
  1688.  */
  1689. int load_conf(char *filename, const char *original_path)
  1690. {
  1691.     ConfigFile  *cfptr, *cfptr2, **cfptr3;
  1692.     ConfigEntry     *ce;
  1693.     ConfigItem_include *inc, *my_inc;
  1694.     int ret;
  1695.     int fatal_ret;
  1696.     int counter;
  1697.  
  1698.     if (config_verbose > 0)
  1699.         config_status("Loading config file %s ..", filename);
  1700.  
  1701.     need_34_upgrade = 0;
  1702.  
  1703.     /*
  1704.      * Check if we're accidentally including a file a second
  1705.      * time. We should expect to find one entry in this list: the
  1706.      * entry for our current file.
  1707.      */
  1708.     counter = 0;
  1709.     my_inc = NULL;
  1710.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  1711.     {
  1712.         /*
  1713.          * ignore files which were part of a _previous_
  1714.          * successful rehash.
  1715.          */
  1716.         if (!(inc->flag.type & INCLUDE_NOTLOADED))
  1717.             continue;
  1718.  
  1719.         if (!counter)
  1720.             my_inc = inc;
  1721.  
  1722.         if (!strcmp(filename, inc->file))
  1723.         {
  1724.             counter ++;
  1725.             continue;
  1726.         }
  1727. #ifdef _WIN32
  1728.         if (!stricmp(filename, inc->file))
  1729.         {
  1730.             counter ++;
  1731.             continue;
  1732.         }
  1733. #endif
  1734. #ifdef USE_LIBCURL
  1735.         if (inc->url && !strcmp(original_path, inc->url))
  1736.         {
  1737.             counter ++;
  1738.             continue;
  1739.         }
  1740. #endif
  1741.     }
  1742.     if (counter < 1 || !my_inc)
  1743.     {
  1744.         /*
  1745.          * The following is simply for debugging/[sanity
  1746.          * checking]. To make sure that functions call
  1747.          * add_include() or add_remote_include() before
  1748.          * calling us.
  1749.          */
  1750.         config_error("I don't have a record for %s being included."
  1751.                  " Perhaps someone forgot to call add_include()?",
  1752.                  filename);
  1753.         abort();
  1754.     }
  1755.     if (counter > 1 || my_inc->flag.type & INCLUDE_USED)
  1756.     {
  1757.         config_error("%s:%d:include: Config file %s has been loaded before %d time."
  1758.                  " You may include each file only once.",
  1759.                  my_inc->included_from, my_inc->included_from_line,
  1760.                  filename, counter - 1);
  1761.         return -1;
  1762.     }
  1763.     /* end include recursion checking code */
  1764.  
  1765.     if ((cfptr = config_load(filename)))
  1766.     {
  1767.         for (cfptr3 = &conf, cfptr2 = conf; cfptr2; cfptr2 = cfptr2->cf_next)
  1768.             cfptr3 = &cfptr2->cf_next;
  1769.         *cfptr3 = cfptr;
  1770.  
  1771.         /* Load modules */
  1772.         if (config_verbose > 1)
  1773.             config_status("Loading modules in %s", filename);
  1774.  
  1775.         fatal_ret = 0;
  1776.         for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
  1777.             if (!strcmp(ce->ce_varname, "loadmodule"))
  1778.             {
  1779.                  ret = _conf_loadmodule(cfptr, ce);
  1780.                  if (ret < fatal_ret)
  1781.                     fatal_ret = ret; /* lowest wins */
  1782.             }
  1783.         ret = fatal_ret;
  1784.         if (need_34_upgrade)
  1785.             upgrade_conf_to_34();
  1786.         if (ret < 0)
  1787.             return ret;
  1788.  
  1789.         /* Load includes */
  1790.         if (config_verbose > 1)
  1791.             config_status("Searching through %s for include files..", filename);
  1792.         for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
  1793.             if (!strcmp(ce->ce_varname, "include"))
  1794.             {
  1795.                  ret = _conf_include(cfptr, ce);
  1796.                  if (need_34_upgrade)
  1797.                     upgrade_conf_to_34();
  1798.                  if (ret < 0)
  1799.                         return ret;
  1800.             }
  1801.         my_inc->flag.type |= INCLUDE_USED;
  1802.         return 1;
  1803.     }
  1804.     else
  1805.     {
  1806.         config_error("Could not load config file %s", filename);
  1807. #ifdef _WIN32
  1808.         if (!strcmp(filename, "conf/unrealircd.conf"))
  1809.         {
  1810.             if (file_exists("unrealircd.conf"))
  1811.             {
  1812.                 config_error("Note that 'unrealircd.conf' now belongs in the 'conf' subdirectory! (So move it to there)");
  1813.             } else {
  1814.                 config_error("New to UnrealIRCd? Be sure to read https://www.unrealircd.org/docs/Installing_%%28Windows%%29");
  1815.             }
  1816.         }
  1817. #endif
  1818.         return -1;
  1819.     }
  1820. }
  1821.  
  1822. void    config_rehash()
  1823. {
  1824.     ConfigItem_oper         *oper_ptr;
  1825.     ConfigItem_class        *class_ptr;
  1826.     ConfigItem_ulines       *uline_ptr;
  1827.     ConfigItem_allow        *allow_ptr;
  1828.     ConfigItem_except       *except_ptr;
  1829.     ConfigItem_ban          *ban_ptr;
  1830.     ConfigItem_link         *link_ptr;
  1831.     ConfigItem_listen       *listen_ptr;
  1832.     ConfigItem_tld          *tld_ptr;
  1833.     ConfigItem_vhost        *vhost_ptr;
  1834.     ConfigItem_deny_dcc     *deny_dcc_ptr;
  1835.     ConfigItem_allow_dcc        *allow_dcc_ptr;
  1836.     ConfigItem_deny_link        *deny_link_ptr;
  1837.     ConfigItem_deny_channel     *deny_channel_ptr;
  1838.     ConfigItem_allow_channel    *allow_channel_ptr;
  1839.     ConfigItem_admin        *admin_ptr;
  1840.     ConfigItem_deny_version     *deny_version_ptr;
  1841.     ConfigItem_log          *log_ptr;
  1842.     ConfigItem_alias        *alias_ptr;
  1843.     ConfigItem_help         *help_ptr;
  1844.     ConfigItem_offchans     *of_ptr;
  1845.     OperStat            *os_ptr;
  1846.     ListStruct  *next, *next2;
  1847.     aTKline *tk, *tk_next;
  1848.     SpamExcept *spamex_ptr;
  1849.     int i;
  1850.  
  1851.     USE_BAN_VERSION = 0;
  1852.  
  1853.     for (admin_ptr = conf_admin; admin_ptr; admin_ptr = (ConfigItem_admin *)next)
  1854.     {
  1855.         next = (ListStruct *)admin_ptr->next;
  1856.         safefree(admin_ptr->line);
  1857.         DelListItem(admin_ptr, conf_admin);
  1858.         MyFree(admin_ptr);
  1859.     }
  1860.  
  1861.     for (oper_ptr = conf_oper; oper_ptr; oper_ptr = (ConfigItem_oper *)next)
  1862.     {
  1863.         ConfigItem_mask *oper_mask;
  1864.         SWhois *s, *s_next;
  1865.         next = (ListStruct *)oper_ptr->next;
  1866.         safefree(oper_ptr->name);
  1867.         safefree(oper_ptr->snomask);
  1868.         safefree(oper_ptr->operclass);
  1869.         safefree(oper_ptr->vhost);
  1870.         Auth_DeleteAuthStruct(oper_ptr->auth);
  1871.         unreal_delete_masks(oper_ptr->mask);
  1872.         DelListItem(oper_ptr, conf_oper);
  1873.         for (s = oper_ptr->swhois; s; s = s_next)
  1874.         {
  1875.             s_next = s->next;
  1876.             safefree(s->line);
  1877.             safefree(s->setby);
  1878.             MyFree(s);
  1879.         }
  1880.         MyFree(oper_ptr);
  1881.     }
  1882.  
  1883.     for (link_ptr = conf_link; link_ptr; link_ptr = (ConfigItem_link *) next)
  1884.     {
  1885.         next = (ListStruct *)link_ptr->next;
  1886.         if (link_ptr->refcount == 0)
  1887.         {
  1888.             Debug((DEBUG_ERROR, "s_conf: deleting block %s (refcount 0)", link_ptr->servername));
  1889.             delete_linkblock(link_ptr);
  1890.         }
  1891.         else
  1892.         {
  1893.             Debug((DEBUG_ERROR, "s_conf: marking block %s (refcount %d) as temporary",
  1894.                 link_ptr->servername, link_ptr->refcount));
  1895.             link_ptr->flag.temporary = 1;
  1896.         }
  1897.     }
  1898.     for (class_ptr = conf_class; class_ptr; class_ptr = (ConfigItem_class *) next)
  1899.     {
  1900.         next = (ListStruct *)class_ptr->next;
  1901.         if (class_ptr->flag.permanent == 1)
  1902.             continue;
  1903.         class_ptr->flag.temporary = 1;
  1904.         /* We'll wipe it out when it has no clients */
  1905.         if (!class_ptr->clients && !class_ptr->xrefcount)
  1906.         {
  1907.             delete_classblock(class_ptr);
  1908.         }
  1909.     }
  1910.     for (uline_ptr = conf_ulines; uline_ptr; uline_ptr = (ConfigItem_ulines *) next)
  1911.     {
  1912.         next = (ListStruct *)uline_ptr->next;
  1913.         /* We'll wipe it out when it has no clients */
  1914.         safefree(uline_ptr->servername);
  1915.         DelListItem(uline_ptr, conf_ulines);
  1916.         MyFree(uline_ptr);
  1917.     }
  1918.     for (allow_ptr = conf_allow; allow_ptr; allow_ptr = (ConfigItem_allow *) next)
  1919.     {
  1920.         next = (ListStruct *)allow_ptr->next;
  1921.         safefree(allow_ptr->ip);
  1922.         safefree(allow_ptr->hostname);
  1923.         Auth_DeleteAuthStruct(allow_ptr->auth);
  1924.         DelListItem(allow_ptr, conf_allow);
  1925.         MyFree(allow_ptr);
  1926.     }
  1927.     for (except_ptr = conf_except; except_ptr; except_ptr = (ConfigItem_except *) next)
  1928.     {
  1929.         next = (ListStruct *)except_ptr->next;
  1930.         safefree(except_ptr->mask);
  1931.         DelListItem(except_ptr, conf_except);
  1932.         MyFree(except_ptr);
  1933.     }
  1934.     for (ban_ptr = conf_ban; ban_ptr; ban_ptr = (ConfigItem_ban *) next)
  1935.     {
  1936.         next = (ListStruct *)ban_ptr->next;
  1937.         if (ban_ptr->flag.type2 == CONF_BAN_TYPE_CONF || ban_ptr->flag.type2 == CONF_BAN_TYPE_TEMPORARY)
  1938.         {
  1939.             safefree(ban_ptr->mask);
  1940.             safefree(ban_ptr->reason);
  1941.             DelListItem(ban_ptr, conf_ban);
  1942.             MyFree(ban_ptr);
  1943.         }
  1944.     }
  1945.     for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)listen_ptr->next)
  1946.     {
  1947.         listen_ptr->flag.temporary = 1;
  1948.     }
  1949.     for (tld_ptr = conf_tld; tld_ptr; tld_ptr = (ConfigItem_tld *) next)
  1950.     {
  1951.         next = (ListStruct *)tld_ptr->next;
  1952.         safefree(tld_ptr->motd_file);
  1953.         safefree(tld_ptr->rules_file);
  1954.         safefree(tld_ptr->smotd_file);
  1955.         safefree(tld_ptr->opermotd_file);
  1956.         safefree(tld_ptr->botmotd_file);
  1957.  
  1958.         free_motd(&tld_ptr->motd);
  1959.         free_motd(&tld_ptr->rules);
  1960.         free_motd(&tld_ptr->smotd);
  1961.         free_motd(&tld_ptr->opermotd);
  1962.         free_motd(&tld_ptr->botmotd);
  1963.  
  1964.         DelListItem(tld_ptr, conf_tld);
  1965.         MyFree(tld_ptr);
  1966.     }
  1967.     for (vhost_ptr = conf_vhost; vhost_ptr; vhost_ptr = (ConfigItem_vhost *) next)
  1968.     {
  1969.         ConfigItem_mask *vhost_mask;
  1970.         SWhois *s, *s_next;
  1971.  
  1972.         next = (ListStruct *)vhost_ptr->next;
  1973.  
  1974.         safefree(vhost_ptr->login);
  1975.         Auth_DeleteAuthStruct(vhost_ptr->auth);
  1976.         safefree(vhost_ptr->virthost);
  1977.         safefree(vhost_ptr->virtuser);
  1978.         unreal_delete_masks(vhost_ptr->mask);
  1979.         for (s = vhost_ptr->swhois; s; s = s_next)
  1980.         {
  1981.             s_next = s->next;
  1982.             safefree(s->line);
  1983.             safefree(s->setby);
  1984.             MyFree(s);
  1985.         }
  1986.         DelListItem(vhost_ptr, conf_vhost);
  1987.         MyFree(vhost_ptr);
  1988.     }
  1989.  
  1990.     /* Clean up local spamfilter entries... */
  1991.     for (tk = tklines[tkl_hash('f')]; tk; tk = tk_next)
  1992.     {
  1993.         if (tk->type == TKL_SPAMF)
  1994.             tk_next = tkl_del_line(tk);
  1995.         else /* global spamfilter.. don't touch! */
  1996.             tk_next = tk->next;
  1997.     }
  1998.  
  1999.     for (tk = tklines[tkl_hash('q')]; tk; tk = tk_next)
  2000.     {
  2001.         if (tk->type == TKL_NICK)
  2002.             tk_next = tkl_del_line(tk);
  2003.         else
  2004.             tk_next = tk->next;
  2005.     }
  2006.  
  2007.     for (deny_dcc_ptr = conf_deny_dcc; deny_dcc_ptr; deny_dcc_ptr = (ConfigItem_deny_dcc *)next)
  2008.     {
  2009.         next = (ListStruct *)deny_dcc_ptr->next;
  2010.         if (deny_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
  2011.         {
  2012.             safefree(deny_dcc_ptr->filename);
  2013.             safefree(deny_dcc_ptr->reason);
  2014.             DelListItem(deny_dcc_ptr, conf_deny_dcc);
  2015.             MyFree(deny_dcc_ptr);
  2016.         }
  2017.     }
  2018.     for (deny_link_ptr = conf_deny_link; deny_link_ptr; deny_link_ptr = (ConfigItem_deny_link *) next) {
  2019.         next = (ListStruct *)deny_link_ptr->next;
  2020.         safefree(deny_link_ptr->prettyrule);
  2021.         safefree(deny_link_ptr->mask);
  2022.         crule_free(&deny_link_ptr->rule);
  2023.         DelListItem(deny_link_ptr, conf_deny_link);
  2024.         MyFree(deny_link_ptr);
  2025.     }
  2026.     for (deny_version_ptr = conf_deny_version; deny_version_ptr; deny_version_ptr = (ConfigItem_deny_version *) next) {
  2027.         next = (ListStruct *)deny_version_ptr->next;
  2028.         safefree(deny_version_ptr->mask);
  2029.         safefree(deny_version_ptr->version);
  2030.         safefree(deny_version_ptr->flags);
  2031.         DelListItem(deny_version_ptr, conf_deny_version);
  2032.         MyFree(deny_version_ptr);
  2033.     }
  2034.     for (deny_channel_ptr = conf_deny_channel; deny_channel_ptr; deny_channel_ptr = (ConfigItem_deny_channel *) next)
  2035.     {
  2036.         next = (ListStruct *)deny_channel_ptr->next;
  2037.         safefree(deny_channel_ptr->redirect);
  2038.         safefree(deny_channel_ptr->channel);
  2039.         safefree(deny_channel_ptr->reason);
  2040.         safefree(deny_channel_ptr->class);
  2041.         DelListItem(deny_channel_ptr, conf_deny_channel);
  2042.         MyFree(deny_channel_ptr);
  2043.     }
  2044.  
  2045.     for (allow_channel_ptr = conf_allow_channel; allow_channel_ptr; allow_channel_ptr = (ConfigItem_allow_channel *) next)
  2046.     {
  2047.         next = (ListStruct *)allow_channel_ptr->next;
  2048.         safefree(allow_channel_ptr->channel);
  2049.         safefree(allow_channel_ptr->class);
  2050.         DelListItem(allow_channel_ptr, conf_allow_channel);
  2051.         MyFree(allow_channel_ptr);
  2052.     }
  2053.     for (allow_dcc_ptr = conf_allow_dcc; allow_dcc_ptr; allow_dcc_ptr = (ConfigItem_allow_dcc *)next)
  2054.     {
  2055.         next = (ListStruct *)allow_dcc_ptr->next;
  2056.         if (allow_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
  2057.         {
  2058.             safefree(allow_dcc_ptr->filename);
  2059.             DelListItem(allow_dcc_ptr, conf_allow_dcc);
  2060.             MyFree(allow_dcc_ptr);
  2061.         }
  2062.     }
  2063.  
  2064.     if (conf_drpass)
  2065.     {
  2066.         Auth_DeleteAuthStruct(conf_drpass->restartauth);
  2067.         conf_drpass->restartauth = NULL;
  2068.         Auth_DeleteAuthStruct(conf_drpass->dieauth);
  2069.         conf_drpass->dieauth = NULL;
  2070.         safefree(conf_drpass);
  2071.     }
  2072.     for (log_ptr = conf_log; log_ptr; log_ptr = (ConfigItem_log *)next) {
  2073.         next = (ListStruct *)log_ptr->next;
  2074.         if (log_ptr->logfd != -1)
  2075.             fd_close(log_ptr->logfd);
  2076.         safefree(log_ptr->file);
  2077.         DelListItem(log_ptr, conf_log);
  2078.         MyFree(log_ptr);
  2079.     }
  2080.     for (alias_ptr = conf_alias; alias_ptr; alias_ptr = (ConfigItem_alias *)next) {
  2081.         aCommand *cmptr = find_Command(alias_ptr->alias, 0, 0);
  2082.         ConfigItem_alias_format *fmt;
  2083.         next = (ListStruct *)alias_ptr->next;
  2084.         safefree(alias_ptr->nick);
  2085.         if (cmptr)
  2086.             del_Command(alias_ptr->alias, cmptr->func);
  2087.         safefree(alias_ptr->alias);
  2088.         if (alias_ptr->format && (alias_ptr->type == ALIAS_COMMAND)) {
  2089.             for (fmt = (ConfigItem_alias_format *) alias_ptr->format; fmt; fmt = (ConfigItem_alias_format *) next2)
  2090.             {
  2091.                 next2 = (ListStruct *)fmt->next;
  2092.                 safefree(fmt->format);
  2093.                 safefree(fmt->nick);
  2094.                 safefree(fmt->parameters);
  2095.                 unreal_delete_match(fmt->expr);
  2096.                 DelListItem(fmt, alias_ptr->format);
  2097.                 MyFree(fmt);
  2098.             }
  2099.         }
  2100.         DelListItem(alias_ptr, conf_alias);
  2101.         MyFree(alias_ptr);
  2102.     }
  2103.     for (help_ptr = conf_help; help_ptr; help_ptr = (ConfigItem_help *)next) {
  2104.         aMotdLine *text;
  2105.         next = (ListStruct *)help_ptr->next;
  2106.         safefree(help_ptr->command);
  2107.         while (help_ptr->text) {
  2108.             text = help_ptr->text->next;
  2109.             safefree(help_ptr->text->line);
  2110.             safefree(help_ptr->text);
  2111.             help_ptr->text = text;
  2112.         }
  2113.         DelListItem(help_ptr, conf_help);
  2114.         MyFree(help_ptr);
  2115.     }
  2116.     for (os_ptr = iConf.oper_only_stats_ext; os_ptr; os_ptr = (OperStat *)next)
  2117.     {
  2118.         next = (ListStruct *)os_ptr->next;
  2119.         safefree(os_ptr->flag);
  2120.         MyFree(os_ptr);
  2121.     }
  2122.     iConf.oper_only_stats_ext = NULL;
  2123.     for (spamex_ptr = iConf.spamexcept; spamex_ptr; spamex_ptr = (SpamExcept *)next)
  2124.     {
  2125.         next = (ListStruct *)spamex_ptr->next;
  2126.         MyFree(spamex_ptr);
  2127.     }
  2128.     iConf.spamexcept = NULL;
  2129.     for (of_ptr = conf_offchans; of_ptr; of_ptr = (ConfigItem_offchans *)next)
  2130.     {
  2131.         next = (ListStruct *)of_ptr->next;
  2132.         safefree(of_ptr->topic);
  2133.         MyFree(of_ptr);
  2134.     }
  2135.     conf_offchans = NULL;
  2136.  
  2137.     for (i = 0; i < EXTCMODETABLESZ; i++)
  2138.     {
  2139.         if (iConf.modes_on_join.extparams[i])
  2140.             free(iConf.modes_on_join.extparams[i]);
  2141.     }
  2142.    
  2143.     /*
  2144.       reset conf_files -- should this be in its own function? no, because
  2145.       it's only used here
  2146.      */
  2147.     safefree(conf_files->motd_file);
  2148.     safefree(conf_files->smotd_file);
  2149.     safefree(conf_files->opermotd_file);
  2150.     safefree(conf_files->svsmotd_file);
  2151.     safefree(conf_files->botmotd_file);
  2152.     safefree(conf_files->rules_file);
  2153.     safefree(conf_files->pid_file);
  2154.     safefree(conf_files->tune_file);
  2155.     /*
  2156.        Don't free conf_files->pid_file here; the old value is used to determine if
  2157.        the pidfile location has changed and write_pidfile() needs to be called
  2158.        again.
  2159.     */
  2160.     safefree(conf_files);
  2161.     conf_files = NULL;
  2162. }
  2163.  
  2164. int config_post_test()
  2165. {
  2166. #define Error(x) { config_error((x)); errors++; }
  2167.     int     errors = 0;
  2168.     Hook *h;
  2169.  
  2170.     if (!requiredstuff.conf_me)
  2171.         Error("me {} block is missing");
  2172.     if (!requiredstuff.conf_admin)
  2173.         Error("admin {} block is missing");
  2174.     if (!requiredstuff.conf_listen)
  2175.         Error("listen {} block is missing");
  2176.     if (!settings.has_kline_address)
  2177.         Error("set::kline-address is missing");
  2178.     if (!settings.has_maxchannelsperuser)
  2179.         Error("set::maxchannelsperuser is missing");
  2180.     if (!settings.has_services_server)
  2181.         Error("set::services-server is missing");
  2182.     if (!settings.has_default_server)
  2183.         Error("set::default-server is missing");
  2184.     if (!settings.has_network_name)
  2185.         Error("set::network-name is missing");
  2186.     if (!settings.has_help_channel)
  2187.         Error("set::help-channel is missing");
  2188.     if (!settings.has_hiddenhost_prefix)
  2189.         Error("set::hiddenhost-prefix is missing");
  2190.  
  2191.     for (h = Hooks[HOOKTYPE_CONFIGPOSTTEST]; h; h = h->next)
  2192.     {
  2193.         int value, errs = 0;
  2194.         if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
  2195.                         !(h->owner->options & MOD_OPT_PERM))
  2196.             continue;
  2197.         value = (*(h->func.intfunc))(&errs);
  2198.         if (value == -1)
  2199.         {
  2200.             errors += errs;
  2201.             break;
  2202.         }
  2203.         if (value == -2)
  2204.             errors += errs;
  2205.     }
  2206.     return errors;
  2207. }
  2208.  
  2209. int config_run()
  2210. {
  2211.     ConfigEntry     *ce;
  2212.     ConfigFile  *cfptr;
  2213.     ConfigCommand   *cc;
  2214.     int     errors = 0;
  2215.     Hook *h;
  2216.     ConfigItem_allow *allow;
  2217.  
  2218.     for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
  2219.     {
  2220.         if (config_verbose > 1)
  2221.             config_status("Running %s", cfptr->cf_filename);
  2222.         for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
  2223.         {
  2224.             if ((cc = config_binary_search(ce->ce_varname))) {
  2225.                 if ((cc->conffunc) && (cc->conffunc(cfptr, ce) < 0))
  2226.                     errors++;
  2227.             }
  2228.             else
  2229.             {
  2230.                 int value;
  2231.                 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  2232.                 {
  2233.                     value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN);
  2234.                     if (value == 1)
  2235.                         break;
  2236.                 }
  2237.             }
  2238.         }
  2239.     }
  2240.     /*
  2241.      * transfer default values from set::ipv6_clones_mask into
  2242.      * each individual allow block. If other similar things like
  2243.      * this stack up here, perhaps this shoul be moved to another
  2244.      * function.
  2245.      */
  2246.     for(allow = conf_allow; allow; allow = (ConfigItem_allow *)allow->next)
  2247.         if(!allow->ipv6_clone_mask)
  2248.             allow->ipv6_clone_mask = tempiConf.default_ipv6_clone_mask;
  2249.  
  2250.     close_listeners();
  2251.     listen_cleanup();
  2252.     close_listeners();
  2253.     loop.do_bancheck = 1;
  2254.     free_iConf(&iConf);
  2255.     bcopy(&tempiConf, &iConf, sizeof(aConfiguration));
  2256.     bzero(&tempiConf, sizeof(aConfiguration));
  2257.  
  2258.     {
  2259.         EventInfo eInfo;
  2260.         long v;
  2261.         eInfo.flags = EMOD_EVERY;
  2262.         if (!THROTTLING_PERIOD)
  2263.             v = 120;
  2264.         else
  2265.         {
  2266.             v = THROTTLING_PERIOD/2;
  2267.             if (v > 5)
  2268.                 v = 5; /* accuracy, please */
  2269.         }
  2270.         eInfo.every = v;
  2271.         EventMod(EventFind("bucketcleaning"), &eInfo);
  2272.     }
  2273.  
  2274.  
  2275.     /* initialize conf_files with defaults if the block isn't set: */
  2276.     if(!conf_files)
  2277.       _conf_files(NULL, NULL);
  2278.  
  2279.     if (errors > 0)
  2280.     {
  2281.         config_error("%i fatal errors encountered", errors);
  2282.     }
  2283.     return (errors > 0 ? -1 : 1);
  2284. }
  2285.  
  2286.  
  2287. NameValue *config_binary_flags_search(NameValue *table, char *cmd, int size) {
  2288.     int start = 0;
  2289.     int stop = size-1;
  2290.     int mid;
  2291.     while (start <= stop) {
  2292.         mid = (start+stop)/2;
  2293.  
  2294.         if (smycmp(cmd,table[mid].name) < 0) {
  2295.             stop = mid-1;
  2296.         }
  2297.         else if (strcmp(cmd,table[mid].name) == 0) {
  2298.             return &(table[mid]);
  2299.         }
  2300.         else
  2301.             start = mid+1;
  2302.     }
  2303.     return NULL;
  2304. }
  2305.  
  2306. int config_test()
  2307. {
  2308.     ConfigEntry     *ce;
  2309.     ConfigFile  *cfptr;
  2310.     ConfigCommand   *cc;
  2311.     int     errors = 0;
  2312.     Hook *h;
  2313.  
  2314.     need_34_upgrade = 0;
  2315.  
  2316.     for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
  2317.     {
  2318.         if (config_verbose > 1)
  2319.             config_status("Testing %s", cfptr->cf_filename);
  2320.         for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
  2321.         {
  2322.             if (!ce->ce_varname)
  2323.             {
  2324.                 config_error("%s:%i: %s:%i: null ce->ce_varname",
  2325.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  2326.                     __FILE__, __LINE__);
  2327.                 return -1;
  2328.             }
  2329.             if ((cc = config_binary_search(ce->ce_varname))) {
  2330.                 if (cc->testfunc)
  2331.                     errors += (cc->testfunc(cfptr, ce));
  2332.             }
  2333.             else
  2334.             {
  2335.                 int used = 0;
  2336.                 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  2337.                 {
  2338.                     int value, errs = 0;
  2339.                     if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  2340.                         && !(h->owner->options & MOD_OPT_PERM))
  2341.  
  2342.  
  2343.                         continue;
  2344.                     value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN,&errs);
  2345.                     if (value == 2)
  2346.                         used = 1;
  2347.                     if (value == 1)
  2348.                     {
  2349.                         used = 1;
  2350.                         break;
  2351.                     }
  2352.                     if (value == -1)
  2353.                     {
  2354.                         used = 1;
  2355.                         errors += errs;
  2356.                         break;
  2357.                     }
  2358.                     if (value == -2)
  2359.                     {
  2360.                         used = 1;
  2361.                         errors += errs;
  2362.                     }
  2363.  
  2364.                 }
  2365.                 if (!used)
  2366.                     config_status("%s:%i: unknown directive %s",
  2367.                         ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  2368.                         ce->ce_varname);
  2369.             }
  2370.         }
  2371.     }
  2372.     errors += config_post_test();
  2373.     if (errors > 0)
  2374.     {
  2375.         config_error("%i errors encountered", errors);
  2376.     }
  2377.  
  2378.     if (need_34_upgrade)
  2379.     {
  2380.         upgrade_conf_to_34();
  2381.     }
  2382.     return (errors > 0 ? -1 : 1);
  2383. }
  2384.  
  2385. /*
  2386.  * Service functions
  2387. */
  2388.  
  2389. ConfigItem_deny_dcc *Find_deny_dcc(char *name)
  2390. {
  2391.     ConfigItem_deny_dcc *p;
  2392.  
  2393.     if (!name)
  2394.         return NULL;
  2395.  
  2396.     for (p = conf_deny_dcc; p; p = (ConfigItem_deny_dcc *) p->next)
  2397.     {
  2398.         if (!match(name, p->filename))
  2399.             return (p);
  2400.     }
  2401.     return NULL;
  2402. }
  2403.  
  2404. ConfigItem_alias *Find_alias(char *name) {
  2405.     ConfigItem_alias *alias;
  2406.  
  2407.     if (!name)
  2408.         return NULL;
  2409.  
  2410.     for (alias = conf_alias; alias; alias = (ConfigItem_alias *)alias->next) {
  2411.         if (!stricmp(alias->alias, name))
  2412.             return alias;
  2413.     }
  2414.     return NULL;
  2415. }
  2416.  
  2417. ConfigItem_class    *Find_class(char *name)
  2418. {
  2419.     ConfigItem_class    *p;
  2420.  
  2421.     if (!name)
  2422.         return NULL;
  2423.  
  2424.     for (p = conf_class; p; p = (ConfigItem_class *) p->next)
  2425.     {
  2426.         if (!strcmp(name, p->name))
  2427.             return (p);
  2428.     }
  2429.     return NULL;
  2430. }
  2431.  
  2432.  
  2433. ConfigItem_oper *Find_oper(char *name)
  2434. {
  2435.     ConfigItem_oper *p;
  2436.  
  2437.     if (!name)
  2438.         return NULL;
  2439.  
  2440.     for (p = conf_oper; p; p = (ConfigItem_oper *) p->next)
  2441.     {
  2442.         if (!strcmp(name, p->name))
  2443.             return (p);
  2444.     }
  2445.     return NULL;
  2446. }
  2447.  
  2448. ConfigItem_operclass *Find_operclass(char *name)
  2449. {
  2450.     ConfigItem_operclass *p;
  2451.     if (!name)
  2452.         return NULL;
  2453.  
  2454.     for (p = conf_operclass; p; p= (ConfigItem_operclass *) p->next)
  2455.     {
  2456.         if (!strcmp(name,p->classStruct->name))
  2457.             return (p);
  2458.     }
  2459.     return NULL;
  2460. }
  2461.  
  2462. int count_oper_sessions(char *name)
  2463. {
  2464.     int count = 0;
  2465.     aClient *cptr;
  2466.  
  2467.     list_for_each_entry(cptr, &oper_list, special_node)
  2468.     {
  2469.         if (cptr->user->operlogin != NULL && !strcmp(cptr->user->operlogin, name))
  2470.             count++;
  2471.     }
  2472.  
  2473.     return count;
  2474. }
  2475.  
  2476. ConfigItem_listen *Find_listen(char *ipmask, int port, int ipv6)
  2477. {
  2478.     ConfigItem_listen   *p;
  2479.  
  2480.     if (!ipmask)
  2481.         return NULL;
  2482.  
  2483.     for (p = conf_listen; p; p = (ConfigItem_listen *) p->next)
  2484.     {
  2485.         if (p->ipv6 != ipv6)
  2486.             continue;
  2487.  
  2488.         if (!match(p->ip, ipmask) && (port == p->port))
  2489.             return (p);
  2490.  
  2491.         if (!match(ipmask, p->ip) && (port == p->port))
  2492.             return (p);
  2493.     }
  2494.     return NULL;
  2495. }
  2496.  
  2497. ConfigItem_ulines *Find_uline(char *host) {
  2498.     ConfigItem_ulines *ulines;
  2499.  
  2500.     if (!host)
  2501.         return NULL;
  2502.  
  2503.     for(ulines = conf_ulines; ulines; ulines =(ConfigItem_ulines *) ulines->next) {
  2504.         if (!stricmp(host, ulines->servername))
  2505.             return ulines;
  2506.     }
  2507.     return NULL;
  2508. }
  2509.  
  2510.  
  2511. ConfigItem_except *Find_except(aClient *sptr, short type)
  2512. {
  2513.     ConfigItem_except *excepts;
  2514.  
  2515.     for(excepts = conf_except; excepts; excepts =(ConfigItem_except *) excepts->next)
  2516.     {
  2517.         if (excepts->flag.type == type)
  2518.         {
  2519.             if (match_user(excepts->mask, sptr, MATCH_CHECK_REAL))
  2520.                 return excepts;
  2521.         }
  2522.     }
  2523.     return NULL;
  2524. }
  2525.  
  2526. ConfigItem_tld *Find_tld(aClient *cptr)
  2527. {
  2528.     ConfigItem_tld *tld;
  2529.  
  2530.     for (tld = conf_tld; tld; tld = (ConfigItem_tld *) tld->next)
  2531.     {
  2532.         if (match_user(tld->mask, cptr, MATCH_CHECK_REAL))
  2533.         {
  2534.             if ((tld->options & TLD_SSL) && !IsSecure(cptr))
  2535.                 continue;
  2536.             if ((tld->options & TLD_REMOTE) && MyClient(cptr))
  2537.                 continue;
  2538.             return tld;
  2539.         }
  2540.     }
  2541.  
  2542.     return NULL;
  2543. }
  2544.  
  2545.  
  2546. ConfigItem_link *Find_link(char *servername, aClient *acptr)
  2547. {
  2548.     ConfigItem_link *link;
  2549.  
  2550.     for (link = conf_link; link; link = (ConfigItem_link *)link->next)
  2551.     {
  2552.         if (!match(link->servername, servername) && unreal_mask_match(acptr, link->incoming.mask))
  2553.         {
  2554.             return link;
  2555.         }
  2556.     }
  2557.     return NULL;
  2558. }
  2559.  
  2560. ConfigItem_ban  *Find_ban(aClient *sptr, char *host, short type)
  2561. {
  2562.     ConfigItem_ban *ban;
  2563.  
  2564.     /* Check for an except ONLY if we find a ban, makes it
  2565.      * faster since most users will not have a ban so excepts
  2566.      * don't need to be searched -- codemastr
  2567.      */
  2568.  
  2569.     for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
  2570.     {
  2571.         if (ban->flag.type == type)
  2572.         {
  2573.             if (sptr)
  2574.             {
  2575.                 if (match_user(ban->mask, sptr, MATCH_CHECK_REAL))
  2576.                 {
  2577.                     /* Person got a exception */
  2578.                     if ((type == CONF_BAN_USER || type == CONF_BAN_IP)
  2579.                         && Find_except(sptr, CONF_EXCEPT_BAN))
  2580.                         return NULL;
  2581.                     return ban;
  2582.                 }
  2583.             }
  2584.             else if (!match(ban->mask, host)) /* We don't worry about exceptions */
  2585.                 return ban;
  2586.         }
  2587.     }
  2588.     return NULL;
  2589. }
  2590.  
  2591. ConfigItem_ban  *Find_banEx(aClient *sptr, char *host, short type, short type2)
  2592. {
  2593.     ConfigItem_ban *ban;
  2594.  
  2595.     /* Check for an except ONLY if we find a ban, makes it
  2596.      * faster since most users will not have a ban so excepts
  2597.      * don't need to be searched -- codemastr
  2598.      */
  2599.  
  2600.     for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
  2601.     {
  2602.         if ((ban->flag.type == type) && (ban->flag.type2 == type2))
  2603.         {
  2604.             if (sptr)
  2605.             {
  2606.                 if (match_user(ban->mask, sptr, MATCH_CHECK_REAL))
  2607.                 {
  2608.                     /* Person got a exception */
  2609.                     if (Find_except(sptr, type))
  2610.                         return NULL;
  2611.                     return ban;
  2612.                 }
  2613.             }
  2614.             else if (!match(ban->mask, host)) /* We don't worry about exceptions */
  2615.                 return ban;
  2616.         }
  2617.     }
  2618.     return NULL;
  2619. }
  2620.  
  2621. int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *username)
  2622. {
  2623.     ConfigItem_allow *aconf;
  2624.     char *hname;
  2625.     int  i, ii = 0;
  2626.     static char uhost[HOSTLEN + USERLEN + 3];
  2627.     static char fullname[HOSTLEN + 1];
  2628.  
  2629.     for (aconf = conf_allow; aconf; aconf = (ConfigItem_allow *) aconf->next)
  2630.     {
  2631.         if (!aconf->hostname || !aconf->ip)
  2632.             goto attach;
  2633.         if (aconf->auth && !cptr->local->passwd && aconf->flags.nopasscont)
  2634.             continue;
  2635.         if (aconf->flags.ssl && !IsSecure(cptr))
  2636.             continue;
  2637.         if (hp && hp->h_name)
  2638.         {
  2639.             hname = hp->h_name;
  2640.             strlcpy(fullname, hname, sizeof(fullname));
  2641.             add_local_domain(fullname, HOSTLEN - strlen(fullname));
  2642.             Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
  2643.             if (index(aconf->hostname, '@'))
  2644.             {
  2645.                 if (aconf->flags.noident)
  2646.                     strlcpy(uhost, username, sizeof(uhost));
  2647.                 else
  2648.                     strlcpy(uhost, cptr->username, sizeof(uhost));
  2649.                 strlcat(uhost, "@", sizeof(uhost));
  2650.             }
  2651.             else
  2652.                 *uhost = '\0';
  2653.             strlcat(uhost, fullname, sizeof(uhost));
  2654.             if (!match(aconf->hostname, uhost))
  2655.                 goto attach;
  2656.         }
  2657.  
  2658.         if (index(aconf->ip, '@'))
  2659.         {
  2660.             if (aconf->flags.noident)
  2661.                 strlcpy(uhost, username, sizeof(uhost));
  2662.             else
  2663.                 strlcpy(uhost, cptr->username, sizeof(uhost));
  2664.             (void)strlcat(uhost, "@", sizeof(uhost));
  2665.         }
  2666.         else
  2667.             *uhost = '\0';
  2668.         strlcat(uhost, sockhost, sizeof(uhost));
  2669.         /* Check the IP */
  2670.         if (match_user(aconf->ip, cptr, MATCH_CHECK_IP))
  2671.             goto attach;
  2672.  
  2673.         /* Hmm, localhost is a special case, hp == NULL and sockhost contains
  2674.          * 'localhost' instead of an ip... -- Syzop. */
  2675.         if (!strcmp(sockhost, "localhost"))
  2676.         {
  2677.             if (index(aconf->hostname, '@'))
  2678.             {
  2679.                 if (aconf->flags.noident)
  2680.                     strlcpy(uhost, username, sizeof(uhost));
  2681.                 else
  2682.                     strlcpy(uhost, cptr->username, sizeof(uhost));
  2683.                 strlcat(uhost, "@localhost", sizeof(uhost));
  2684.             }
  2685.             else
  2686.                 strcpy(uhost, "localhost");
  2687.  
  2688.             if (!match(aconf->hostname, uhost))
  2689.                 goto attach;
  2690.         }
  2691.  
  2692.         continue;
  2693.           attach:
  2694. /*      if (index(uhost, '@'))  now flag based -- codemastr */
  2695.         if (!aconf->flags.noident)
  2696.             cptr->flags |= FLAGS_DOID;
  2697.         if (!aconf->flags.useip && hp)
  2698.             strlcpy(uhost, fullname, sizeof(uhost));
  2699.         else
  2700.             strlcpy(uhost, sockhost, sizeof(uhost));
  2701.         set_sockhost(cptr, uhost);
  2702.  
  2703.         if (aconf->maxperip)
  2704.         {
  2705.             aClient *acptr, *acptr2;
  2706.  
  2707.             ii = 1;
  2708.             list_for_each_entry_safe(acptr, acptr2, &lclient_list, lclient_node)
  2709.             {
  2710.                 if (!strcmp(GetIP(acptr), GetIP(cptr)))
  2711.                 {
  2712.                     ii++;
  2713.                     if (ii > aconf->maxperip)
  2714.                     {
  2715.                         exit_client(cptr, cptr, &me,
  2716.                             "Too many connections from your IP");
  2717.                         return -5;  /* Already got too many with that ip# */
  2718.                     }
  2719.                 }
  2720.             }
  2721.         }
  2722.         if ((i = Auth_Check(cptr, aconf->auth, cptr->local->passwd)) == -1)
  2723.         {
  2724.             exit_client(cptr, cptr, &me,
  2725.                 "Password mismatch");
  2726.             return -5;
  2727.         }
  2728.         if ((i == 2) && (cptr->local->passwd))
  2729.         {
  2730.             MyFree(cptr->local->passwd);
  2731.             cptr->local->passwd = NULL;
  2732.         }
  2733.         if (!((aconf->class->clients + 1) > aconf->class->maxclients))
  2734.         {
  2735.             cptr->local->class = aconf->class;
  2736.             cptr->local->class->clients++;
  2737.         }
  2738.         else
  2739.         {
  2740.             sendto_one(cptr, rpl_str(RPL_REDIR), me.name, cptr->name, aconf->server ? aconf->server : defserv, aconf->port ? aconf->port : 6667);
  2741.             return -3;
  2742.         }
  2743.         return 0;
  2744.     }
  2745.     return -1;
  2746. }
  2747.  
  2748. ConfigItem_vhost *Find_vhost(char *name) {
  2749.     ConfigItem_vhost *vhost;
  2750.  
  2751.     for (vhost = conf_vhost; vhost; vhost = (ConfigItem_vhost *)vhost->next) {
  2752.         if (!strcmp(name, vhost->login))
  2753.             return vhost;
  2754.     }
  2755.     return NULL;
  2756. }
  2757.  
  2758.  
  2759. /** returns NULL if allowed and struct if denied */
  2760. ConfigItem_deny_channel *Find_channel_allowed(aClient *cptr, char *name)
  2761. {
  2762.     ConfigItem_deny_channel *dchannel;
  2763.     ConfigItem_allow_channel *achannel;
  2764.  
  2765.     for (dchannel = conf_deny_channel; dchannel; dchannel = (ConfigItem_deny_channel *)dchannel->next)
  2766.     {
  2767.         if (!match(dchannel->channel, name) && (dchannel->class ? !strcmp(cptr->local->class->name, dchannel->class) : 1))
  2768.             break;
  2769.     }
  2770.     if (dchannel)
  2771.     {
  2772.         for (achannel = conf_allow_channel; achannel; achannel = (ConfigItem_allow_channel *)achannel->next)
  2773.         {
  2774.             if (!match(achannel->channel, name) && (achannel->class ? !strcmp(cptr->local->class->name, achannel->class) : 1))
  2775.                 break;
  2776.         }
  2777.         if (achannel)
  2778.             return NULL;
  2779.         else
  2780.             return (dchannel);
  2781.     }
  2782.     return NULL;
  2783. }
  2784.  
  2785. void init_dynconf(void)
  2786. {
  2787.     bzero(&iConf, sizeof(iConf));
  2788.     bzero(&tempiConf, sizeof(iConf));
  2789. }
  2790.  
  2791. char *pretty_time_val(long timeval)
  2792. {
  2793.     static char buf[512];
  2794.  
  2795.     if (timeval == 0)
  2796.         return "0";
  2797.  
  2798.     buf[0] = 0;
  2799.  
  2800.     if (timeval/86400)
  2801.         snprintf(buf, sizeof(buf), "%ld day%s ", timeval/86400, timeval/86400 != 1 ? "s" : "");
  2802.     if ((timeval/3600) % 24)
  2803.         snprintf(buf, sizeof(buf), "%s%ld hour%s ", buf, (timeval/3600)%24, (timeval/3600)%24 != 1 ? "s" : "");
  2804.     if ((timeval/60)%60)
  2805.         snprintf(buf, sizeof(buf), "%s%ld minute%s ", buf, (timeval/60)%60, (timeval/60)%60 != 1 ? "s" : "");
  2806.     if ((timeval%60))
  2807.         snprintf(buf, sizeof(buf), "%s%ld second%s", buf, timeval%60, timeval%60 != 1 ? "s" : "");
  2808.     return buf;
  2809. }
  2810.  
  2811. /* This converts a relative path to an absolute path, but only if necessary. */
  2812. void convert_to_absolute_path(char **path, char *reldir)
  2813. {
  2814.     char *s;
  2815.    
  2816.     if (!*path || !**path)
  2817.         return; /* NULL or empty */
  2818.    
  2819.     if (strstr(*path, "://"))
  2820.         return; /* URL: don't touch */
  2821.    
  2822.     if ((**path == '/') || (**path == '\\'))
  2823.         return; /* already absolute path */
  2824.    
  2825.     if (!strncmp(*path, reldir, strlen(reldir)))
  2826.         return; /* already contains reldir */
  2827.    
  2828.     s = MyMallocEx(strlen(reldir) + strlen(*path) + 2);
  2829.     sprintf(s, "%s/%s", reldir, *path); /* safe, see line above */
  2830.     MyFree(*path);
  2831.     *path = s;
  2832. }
  2833.  
  2834. /*
  2835.  * Actual config parser funcs
  2836. */
  2837.  
  2838. int _conf_include(ConfigFile *conf, ConfigEntry *ce)
  2839. {
  2840.     int ret = 0;
  2841. #ifdef GLOBH
  2842.     glob_t files;
  2843.     int i;
  2844. #elif defined(_WIN32)
  2845.     HANDLE hFind;
  2846.     WIN32_FIND_DATA FindData;
  2847.     char cPath[MAX_PATH], *cSlash = NULL, *path;
  2848. #endif
  2849.     if (!ce->ce_vardata)
  2850.     {
  2851.         config_status("%s:%i: include: no filename given",
  2852.             ce->ce_fileptr->cf_filename,
  2853.             ce->ce_varlinenum);
  2854.         return -1;
  2855.     }
  2856.  
  2857.     if (!strcmp(ce->ce_vardata, "help.conf"))
  2858.         need_34_upgrade = 1;
  2859.  
  2860.     convert_to_absolute_path(&ce->ce_vardata, CONFDIR);
  2861.  
  2862. #ifdef USE_LIBCURL
  2863.     if (url_is_valid(ce->ce_vardata))
  2864.         return remote_include(ce);
  2865. #endif
  2866. #if !defined(_WIN32) && !defined(_AMIGA) && !defined(OSXTIGER) && DEFAULT_PERMISSIONS != 0
  2867.     (void)chmod(ce->ce_vardata, DEFAULT_PERMISSIONS);
  2868. #endif
  2869. #ifdef GLOBH
  2870. #if defined(__OpenBSD__) && defined(GLOB_LIMIT)
  2871.     glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK|GLOB_LIMIT, NULL, &files);
  2872. #else
  2873.     glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK, NULL, &files);
  2874. #endif
  2875.     if (!files.gl_pathc) {
  2876.         globfree(&files);
  2877.         config_status("%s:%i: include %s: invalid file given",
  2878.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  2879.             ce->ce_vardata);
  2880.         return -1;
  2881.     }
  2882.     for (i = 0; i < files.gl_pathc; i++) {
  2883.         add_include(files.gl_pathv[i], ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2884.         ret = load_conf(files.gl_pathv[i], files.gl_pathv[i]);
  2885.         if (ret < 0)
  2886.         {
  2887.             globfree(&files);
  2888.             return ret;
  2889.         }
  2890.     }
  2891.     globfree(&files);
  2892. #elif defined(_WIN32)
  2893.     bzero(cPath,MAX_PATH);
  2894.     if (strchr(ce->ce_vardata, '/') || strchr(ce->ce_vardata, '\\')) {
  2895.         strlcpy(cPath,ce->ce_vardata,MAX_PATH);
  2896.         cSlash=cPath+strlen(cPath);
  2897.         while(*cSlash != '\\' && *cSlash != '/' && cSlash > cPath)
  2898.             cSlash--;
  2899.         *(cSlash+1)=0;
  2900.     }
  2901.     if ( (hFind = FindFirstFile(ce->ce_vardata, &FindData)) == INVALID_HANDLE_VALUE )
  2902.     {
  2903.         config_status("%s:%i: include %s: invalid file given",
  2904.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  2905.             ce->ce_vardata);
  2906.         return -1;
  2907.     }
  2908.     if (cPath) {
  2909.         path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
  2910.         strcpy(path, cPath);
  2911.         strcat(path, FindData.cFileName);
  2912.  
  2913.         add_include(path, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2914.         ret = load_conf(path, path);
  2915.         free(path);
  2916.  
  2917.     }
  2918.     else
  2919.     {
  2920.         add_include(FindData.cFileName, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2921.         ret = load_conf(FindData.cFileName, FindData.cFileName);
  2922.     }
  2923.     if (ret < 0)
  2924.     {
  2925.         FindClose(hFind);
  2926.         return ret;
  2927.     }
  2928.  
  2929.     ret = 0;
  2930.     while (FindNextFile(hFind, &FindData) != 0) {
  2931.         if (cPath) {
  2932.             path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
  2933.             strcpy(path,cPath);
  2934.             strcat(path,FindData.cFileName);
  2935.  
  2936.             add_include(path, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2937.             ret = load_conf(path, path);
  2938.             free(path);
  2939.             if (ret < 0)
  2940.                 break;
  2941.         }
  2942.         else
  2943.         {
  2944.             add_include(FindData.cFileName, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2945.             ret = load_conf(FindData.cFileName, FindData.cFileName);
  2946.         }
  2947.     }
  2948.     FindClose(hFind);
  2949.     if (ret < 0)
  2950.         return ret;
  2951. #else
  2952.     add_include(ce->ce_vardata, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  2953.     ret = load_conf(ce->ce_vardata, ce->ce_vardata);
  2954.     return ret;
  2955. #endif
  2956.     return 1;
  2957. }
  2958.  
  2959. int _test_include(ConfigFile *conf, ConfigEntry *ce)
  2960. {
  2961.     return 0;
  2962. }
  2963.  
  2964. int _conf_admin(ConfigFile *conf, ConfigEntry *ce)
  2965. {
  2966.     ConfigEntry *cep;
  2967.     ConfigItem_admin *ca;
  2968.  
  2969.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  2970.     {
  2971.         ca = MyMallocEx(sizeof(ConfigItem_admin));
  2972.         if (!conf_admin)
  2973.             conf_admin_tail = ca;
  2974.         safestrdup(ca->line, cep->ce_varname);
  2975.         AddListItem(ca, conf_admin);
  2976.     }
  2977.     return 1;
  2978. }
  2979.  
  2980. int _test_admin(ConfigFile *conf, ConfigEntry *ce)
  2981. {
  2982.     ConfigEntry *cep;
  2983.     int         errors = 0;
  2984.  
  2985.     if (requiredstuff.conf_admin)
  2986.     {
  2987.         config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "admin");
  2988.         return 0;
  2989.     }
  2990.  
  2991.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  2992.     {
  2993.         if (!cep->ce_varname)
  2994.         {
  2995.             config_error("%s:%i: blank admin item",
  2996.                 cep->ce_fileptr->cf_filename,
  2997.                 cep->ce_varlinenum);
  2998.             errors++;
  2999.             continue;
  3000.         }
  3001.     }
  3002.     requiredstuff.conf_admin = 1;
  3003.     return errors;
  3004. }
  3005.  
  3006. int _conf_me(ConfigFile *conf, ConfigEntry *ce)
  3007. {
  3008.     ConfigEntry *cep;
  3009.  
  3010.     if (!conf_me)
  3011.         conf_me = MyMallocEx(sizeof(ConfigItem_me));
  3012.  
  3013.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3014.     {
  3015.         if (!strcmp(cep->ce_varname, "name"))
  3016.         {
  3017.             safestrdup(conf_me->name, cep->ce_vardata);
  3018.         }
  3019.         else if (!strcmp(cep->ce_varname, "info"))
  3020.         {
  3021.             safestrdup(conf_me->info, cep->ce_vardata);
  3022.         }
  3023.         else if (!strcmp(cep->ce_varname, "sid"))
  3024.         {
  3025.             safestrdup(conf_me->sid, cep->ce_vardata);
  3026.         }
  3027.     }
  3028.     return 1;
  3029. }
  3030.  
  3031. int _test_me(ConfigFile *conf, ConfigEntry *ce)
  3032. {
  3033.     char has_name = 0, has_info = 0, has_sid = 0;
  3034.     ConfigEntry *cep;
  3035.     int     errors = 0;
  3036.  
  3037.     if (requiredstuff.conf_me)
  3038.     {
  3039.         config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me");
  3040.         return 0;
  3041.     }
  3042.  
  3043.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3044.     {
  3045.         if (config_is_blankorempty(cep, "me"))
  3046.             continue;
  3047.  
  3048.         /* me::name */
  3049.         if (!strcmp(cep->ce_varname, "name"))
  3050.         {
  3051.             if (has_name)
  3052.             {
  3053.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3054.                     cep->ce_varlinenum, "me::name");
  3055.                 continue;
  3056.             }
  3057.             has_name = 1;
  3058.             if (!strchr(cep->ce_vardata, '.'))
  3059.             {
  3060.                 config_error("%s:%i: illegal me::name, must be fully qualified hostname",
  3061.                     cep->ce_fileptr->cf_filename,
  3062.                     cep->ce_varlinenum);
  3063.                 errors++;
  3064.             }
  3065.             if (!valid_host(cep->ce_vardata))
  3066.             {
  3067.                 config_error("%s:%i: illegal me::name contains invalid character(s) [only a-z, 0-9, _, -, . are allowed]",
  3068.                     cep->ce_fileptr->cf_filename,
  3069.                     cep->ce_varlinenum);
  3070.                 errors++;
  3071.             }
  3072.             if (strlen(cep->ce_vardata) > HOSTLEN)
  3073.             {
  3074.                 config_error("%s:%i: illegal me::name, must be less or equal to %i characters",
  3075.                     cep->ce_fileptr->cf_filename,
  3076.                     cep->ce_varlinenum, HOSTLEN);
  3077.                 errors++;
  3078.             }
  3079.         }
  3080.         /* me::info */
  3081.         else if (!strcmp(cep->ce_varname, "info"))
  3082.         {
  3083.             char *p;
  3084.             char valid = 0;
  3085.             if (has_info)
  3086.             {
  3087.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3088.                     cep->ce_varlinenum, "me::info");
  3089.                 continue;
  3090.             }
  3091.             has_info = 1;
  3092.             if (strlen(cep->ce_vardata) > (REALLEN-1))
  3093.             {
  3094.                 config_error("%s:%i: too long me::info, must be max. %i characters",
  3095.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  3096.                     REALLEN-1);
  3097.                 errors++;
  3098.             }
  3099.  
  3100.             /* Valid me::info? Any data except spaces is ok */
  3101.             for (p=cep->ce_vardata; *p; p++)
  3102.             {
  3103.                 if (*p != ' ')
  3104.                 {
  3105.                     valid = 1;
  3106.                     break;
  3107.                 }
  3108.             }
  3109.             if (!valid)
  3110.             {
  3111.                 config_error("%s:%i: empty me::info, should be a server description.",
  3112.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3113.                 errors++;
  3114.             }
  3115.         }
  3116.         else if (!strcmp(cep->ce_varname, "numeric"))
  3117.         {
  3118.             config_error("%s:%i: me::numeric has been removed, you must now specify a Server ID (SID) instead. "
  3119.                          "Edit your configuration file and change 'numeric' to 'sid' and make up "
  3120.                          "a server id of exactly 3 characters, starting with a digit, eg: \"001\" or \"0AB\".",
  3121.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3122.             errors++;
  3123.         }
  3124.         else if (!strcmp(cep->ce_varname, "sid"))
  3125.         {
  3126.             if (has_sid)
  3127.             {
  3128.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3129.                     cep->ce_varlinenum, "me::sid");
  3130.                 continue;
  3131.             }
  3132.             has_sid = 1;
  3133.  
  3134.             if (strlen(cep->ce_vardata) != 3)
  3135.             {
  3136.                 config_error("%s:%i: me::sid must be 3 characters long and begin with a number",
  3137.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3138.                 errors++;
  3139.             }
  3140.  
  3141.             if (!isdigit(*cep->ce_vardata))
  3142.             {
  3143.                 config_error("%s:%i: me::sid must be 3 characters long and begin with a number",
  3144.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3145.                 errors++;
  3146.             }
  3147.         }
  3148.         /* Unknown entry */
  3149.         else
  3150.         {
  3151.             config_error_unknown(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3152.                 "me", cep->ce_varname);
  3153.             errors++;
  3154.         }
  3155.     }
  3156.     if (!has_name)
  3157.     {
  3158.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::name");
  3159.         errors++;
  3160.     }
  3161.     if (!has_info)
  3162.     {
  3163.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::info");
  3164.         errors++;
  3165.     }
  3166.     if (!has_sid)
  3167.     {
  3168.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::sid");
  3169.         errors++;
  3170.     }
  3171.     requiredstuff.conf_me = 1;
  3172.     return errors;
  3173. }
  3174.  
  3175. /*
  3176.  * The files {} block
  3177.  */
  3178. int _conf_files(ConfigFile *conf, ConfigEntry *ce)
  3179. {
  3180.     ConfigEntry *cep;
  3181.  
  3182.     if (!conf_files)
  3183.     {
  3184.         conf_files = MyMallocEx(sizeof(ConfigItem_files));
  3185.  
  3186.         /* set defaults */
  3187.         conf_files->motd_file = strdup(MPATH);
  3188.         conf_files->rules_file = strdup(RPATH);
  3189.         conf_files->smotd_file = strdup(SMPATH);
  3190.         conf_files->botmotd_file = strdup(BPATH);
  3191.         conf_files->opermotd_file = strdup(OPATH);
  3192.         conf_files->svsmotd_file = strdup(VPATH);
  3193.  
  3194.         conf_files->pid_file = strdup(IRCD_PIDFILE);
  3195.         conf_files->tune_file = strdup(IRCDTUNE);
  3196.  
  3197.         /* we let actual files get read in later by the motd caching mechanism */
  3198.     }
  3199.     /*
  3200.      * hack to allow initialization of conf_files (above) when there is no files block in
  3201.      * CPATH. The caller calls _conf_files(NULL, NULL); to do this. We return here because
  3202.      * the for loop's initialization of cep would segfault otherwise. We return 1 because
  3203.      * if config_run() calls us with a NULL ce, it's got a bug...but we can't detect that.
  3204.      */
  3205.     if(!ce)
  3206.       return 1;
  3207.  
  3208.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3209.     {
  3210.         if (!strcmp(cep->ce_varname, "motd"))
  3211.             safestrdup(conf_files->motd_file, cep->ce_vardata);
  3212.         else if (!strcmp(cep->ce_varname, "shortmotd"))
  3213.             safestrdup(conf_files->smotd_file, cep->ce_vardata);
  3214.         else if (!strcmp(cep->ce_varname, "opermotd"))
  3215.             safestrdup(conf_files->opermotd_file, cep->ce_vardata);
  3216.         else if (!strcmp(cep->ce_varname, "svsmotd"))
  3217.             safestrdup(conf_files->svsmotd_file, cep->ce_vardata);
  3218.         else if (!strcmp(cep->ce_varname, "botmotd"))
  3219.             safestrdup(conf_files->botmotd_file, cep->ce_vardata);
  3220.         else if (!strcmp(cep->ce_varname, "rules"))
  3221.             safestrdup(conf_files->rules_file, cep->ce_vardata);
  3222.         else if (!strcmp(cep->ce_varname, "tunefile"))
  3223.             safestrdup(conf_files->tune_file, cep->ce_vardata);
  3224.         else if (!strcmp(cep->ce_varname, "pidfile"))
  3225.             safestrdup(conf_files->pid_file, cep->ce_vardata);
  3226.     }
  3227.     return 1;
  3228. }
  3229.  
  3230. int _test_files(ConfigFile *conf, ConfigEntry *ce)
  3231. {
  3232.     ConfigEntry *cep;
  3233.     int     errors = 0;
  3234.     char has_motd = 0, has_smotd = 0, has_rules = 0;
  3235.     char has_botmotd = 0, has_opermotd = 0, has_svsmotd = 0;
  3236.     char has_pidfile = 0, has_tunefile = 0;
  3237.  
  3238.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3239.     {
  3240.         /* files::motd */
  3241.         if (!strcmp(cep->ce_varname, "motd"))
  3242.         {
  3243.             if (has_motd)
  3244.             {
  3245.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3246.                     cep->ce_varlinenum, "files::motd");
  3247.                 continue;
  3248.             }
  3249.             config_test_openfile(cep, O_RDONLY, 0, "files::motd", 0, 1);
  3250.             has_motd = 1;
  3251.         }
  3252.         /* files::smotd */
  3253.         else if (!strcmp(cep->ce_varname, "shortmotd"))
  3254.         {
  3255.             if (has_smotd)
  3256.             {
  3257.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3258.                     cep->ce_varlinenum, "files::shortmotd");
  3259.                 continue;
  3260.             }
  3261.             config_test_openfile(cep, O_RDONLY, 0, "files::shortmotd", 0, 1);
  3262.             has_smotd = 1;
  3263.         }
  3264.         /* files::rules */
  3265.         else if (!strcmp(cep->ce_varname, "rules"))
  3266.         {
  3267.             if (has_rules)
  3268.             {
  3269.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3270.                     cep->ce_varlinenum, "files::rules");
  3271.                 continue;
  3272.             }
  3273.             config_test_openfile(cep, O_RDONLY, 0, "files::rules", 0, 1);
  3274.             has_rules = 1;
  3275.         }
  3276.         /* files::botmotd */
  3277.         else if (!strcmp(cep->ce_varname, "botmotd"))
  3278.         {
  3279.             if (has_botmotd)
  3280.             {
  3281.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3282.                     cep->ce_varlinenum, "files::botmotd");
  3283.                 continue;
  3284.             }
  3285.             config_test_openfile(cep, O_RDONLY, 0, "files::botmotd", 0, 1);
  3286.             has_botmotd = 1;
  3287.         }
  3288.         /* files::opermotd */
  3289.         else if (!strcmp(cep->ce_varname, "opermotd"))
  3290.         {
  3291.             if (has_opermotd)
  3292.             {
  3293.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3294.                     cep->ce_varlinenum, "files::opermotd");
  3295.                 continue;
  3296.             }
  3297.             config_test_openfile(cep, O_RDONLY, 0, "files::opermotd", 0, 1);
  3298.             has_opermotd = 1;
  3299.         }
  3300.         /* files::svsmotd
  3301.          * This config stuff should somehow be inside of modules/m_svsmotd.c!!!... right?
  3302.          */
  3303.         else if (!strcmp(cep->ce_varname, "svsmotd"))
  3304.         {
  3305.             if (has_svsmotd)
  3306.             {
  3307.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3308.                     cep->ce_varlinenum, "files::svsmotd");
  3309.                 continue;
  3310.             }
  3311.             /* svsmotd can't be a URL because we have to be able to write to it */
  3312.             config_test_openfile(cep, O_RDONLY, 0, "files::svsmotd", 0, 0);
  3313.             has_svsmotd = 1;
  3314.         }
  3315.         /* files::pidfile */
  3316.         else if (!strcmp(cep->ce_varname, "pidfile"))
  3317.         {
  3318.             if (has_pidfile)
  3319.             {
  3320.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3321.                     cep->ce_varlinenum, "files::pidfile");
  3322.                 continue;
  3323.             }
  3324.  
  3325.             errors += config_test_openfile(cep, O_WRONLY | O_CREAT, 0600, "files::pidfile", 1, 0);
  3326.             has_pidfile = 1;
  3327.         }
  3328.         /* files::tunefile */
  3329.         else if (!strcmp(cep->ce_varname, "tunefile"))
  3330.         {
  3331.             if (has_tunefile)
  3332.             {
  3333.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3334.                     cep->ce_varlinenum, "files::tunefile");
  3335.                 continue;
  3336.             }
  3337.             errors += config_test_openfile(cep, O_RDWR | O_CREAT, 0600, "files::tunefile", 1, 0);
  3338.             has_tunefile = 1;
  3339.         }
  3340.         /* <random directive here> */
  3341.         else
  3342.         {
  3343.             config_error("%s:%d: Unknown directive: \"%s\" in files {}", cep->ce_fileptr->cf_filename,
  3344.                      cep->ce_varlinenum, cep->ce_varname);
  3345.             errors ++;
  3346.         }
  3347.     }
  3348.     return errors;
  3349. }
  3350.  
  3351. /*
  3352.  * The operclass {} block parser
  3353.  */
  3354.  
  3355. OperClassACLEntry* _conf_parseACLEntry(ConfigEntry *ce)
  3356. {
  3357.     ConfigEntry *cep;
  3358.     OperClassACLEntry *entry = NULL;
  3359.     entry = MyMallocEx(sizeof(OperClassACLEntry));
  3360.  
  3361.     if (!strcmp(ce->ce_varname,"allow"))
  3362.         entry->type = OPERCLASSENTRY_ALLOW;
  3363.     else
  3364.         entry->type = OPERCLASSENTRY_DENY;
  3365.  
  3366.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3367.     {
  3368.         OperClassACLEntryVar *var = MyMallocEx(sizeof(OperClassACLEntryVar));
  3369.         var->name = strdup(cep->ce_varname);
  3370.         if (cep->ce_vardata)
  3371.         {
  3372.             var->value = strdup(cep->ce_vardata);
  3373.         }
  3374.         AddListItem(var,entry->variables);
  3375.     }
  3376.  
  3377.     return entry;
  3378. }
  3379.  
  3380. OperClassACL* _conf_parseACL(char* name, ConfigEntry *ce)
  3381. {
  3382.     ConfigEntry *cep;
  3383.     ConfigEntry *cepp;
  3384.     OperClassACL *acl = NULL;
  3385.     acl = MyMallocEx(sizeof(OperClassACL));
  3386.     acl->name = strdup(name);
  3387.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3388.     {
  3389.         if (!strcmp(cep->ce_varname, "deny") || !strcmp(cep->ce_varname, "allow"))
  3390.         {
  3391.             OperClassACLEntry *entry = _conf_parseACLEntry(cep);
  3392.             AddListItem(entry,acl->entries);
  3393.         }
  3394.         else {
  3395.             OperClassACL *subAcl = _conf_parseACL(cep->ce_varname,cep);
  3396.             AddListItem(subAcl,acl->acls);
  3397.         }
  3398.     }
  3399.  
  3400.     return acl;
  3401. }
  3402.  
  3403. int _conf_operclass(ConfigFile *conf, ConfigEntry *ce)
  3404. {
  3405.     ConfigEntry *cep;
  3406.     ConfigEntry *cepp;
  3407.     ConfigItem_operclass *operClass = NULL;
  3408.     operClass = MyMallocEx(sizeof(ConfigItem_operclass));
  3409.     operClass->classStruct = MyMallocEx(sizeof(OperClass));
  3410.     operClass->classStruct->name = strdup(ce->ce_vardata);
  3411.  
  3412.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3413.     {
  3414.         if (!strcmp(cep->ce_varname, "parent"))
  3415.         {
  3416.             operClass->classStruct->ISA = strdup(cep->ce_vardata);
  3417.         }
  3418.         else if (!strcmp(cep->ce_varname, "privileges"))
  3419.         {
  3420.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  3421.             {
  3422.                 OperClassACL *acl = _conf_parseACL(cepp->ce_varname,cepp);
  3423.                 AddListItem(acl,operClass->classStruct->acls);
  3424.             }
  3425.         }
  3426.     }
  3427.  
  3428.     AddListItem(operClass, conf_operclass);
  3429.     return 1;
  3430. }
  3431.  
  3432. int     _test_operclass(ConfigFile *conf, ConfigEntry *ce)
  3433. {
  3434.     char has_privileges = 0, has_parent = 0;
  3435.     ConfigEntry *cep;
  3436.     ConfigEntry *cepp;
  3437.     NameValue *ofp;
  3438.     int errors = 0;
  3439.  
  3440.     if (!ce->ce_vardata)
  3441.     {
  3442.         config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "operclass");
  3443.         errors++;
  3444.     }
  3445.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3446.     {
  3447.         if (!cep->ce_varname)
  3448.         {
  3449.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  3450.                 "operclass");
  3451.             errors++;
  3452.             continue;
  3453.         }
  3454.         if (!strcmp(cep->ce_varname, "parent"))
  3455.         {
  3456.             if (has_parent)
  3457.             {
  3458.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3459.                     cep->ce_varlinenum, "operclass::parent");
  3460.                 continue;
  3461.             }
  3462.             has_parent = 1;
  3463.             continue;
  3464.         }
  3465.         if (!strcmp(cep->ce_varname, "privileges"))
  3466.         {
  3467.             if (has_privileges)
  3468.             {
  3469.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3470.                 cep->ce_varlinenum, "oper::privileges");
  3471.                 continue;
  3472.             }
  3473.             has_privileges = 1;
  3474.             continue;
  3475.         }
  3476.         /* Regular variables */
  3477.         if (!cep->ce_entries)
  3478.         {
  3479.             if (!strcmp(cep->ce_varname, "privileges") && !cep->ce_vardata)
  3480.             {
  3481.                 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  3482.                     "operclass::parent");
  3483.                 errors++;
  3484.                 continue;
  3485.             }
  3486.  
  3487.             else
  3488.             {
  3489.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  3490.                     cep->ce_varlinenum, "operclass", cep->ce_varname);
  3491.                 errors++;
  3492.                 continue;
  3493.             }
  3494.         }
  3495.  
  3496.         /* Sections */
  3497.         else
  3498.         {
  3499.             /* No that's not a typo, if it isn't privileges, we explode */
  3500.             if (strcmp(cep->ce_varname, "privileges"))
  3501.             {
  3502.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  3503.                     cep->ce_varlinenum, "operclass", cep->ce_varname);
  3504.                 errors++;
  3505.                 continue;
  3506.             }
  3507.         }
  3508.     }
  3509.  
  3510.     if (!has_privileges)
  3511.     {
  3512.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3513.             "oper::privileges");
  3514.         errors++;
  3515.     }
  3516.  
  3517.     return errors;
  3518. }
  3519.  
  3520. /*
  3521.  * The oper {} block parser
  3522. */
  3523.  
  3524. int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
  3525. {
  3526.     ConfigEntry *cep;
  3527.     ConfigEntry *cepp;
  3528.     ConfigItem_oper *oper = NULL;
  3529.  
  3530.     oper =  MyMallocEx(sizeof(ConfigItem_oper));
  3531.     oper->name = strdup(ce->ce_vardata);
  3532.  
  3533.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3534.     {
  3535.         if (!strcmp(cep->ce_varname, "operclass"))
  3536.             oper->operclass = strdup(cep->ce_vardata);
  3537.         if (!strcmp(cep->ce_varname, "password"))
  3538.             oper->auth = Auth_ConvertConf2AuthStruct(cep);
  3539.         else if (!strcmp(cep->ce_varname, "class"))
  3540.         {
  3541.             oper->class = Find_class(cep->ce_vardata);
  3542.             if (!oper->class || (oper->class->flag.temporary == 1))
  3543.             {
  3544.                 config_status("%s:%i: illegal oper::class, unknown class '%s' using default of class 'default'",
  3545.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  3546.                     cep->ce_vardata);
  3547.                 oper->class = default_class;
  3548.             }
  3549.         }
  3550.         else if (!strcmp(cep->ce_varname, "swhois"))
  3551.         {
  3552.             SWhois *s;
  3553.             if (cep->ce_entries)
  3554.             {
  3555.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  3556.                 {
  3557.                     s = MyMallocEx(sizeof(SWhois));
  3558.                     s->line = strdup(cepp->ce_varname);
  3559.                     s->setby = strdup("oper");
  3560.                     AddListItem(s, oper->swhois);
  3561.                 }
  3562.             } else
  3563.             if (cep->ce_vardata)
  3564.             {
  3565.                 s = MyMallocEx(sizeof(SWhois));
  3566.                 s->line = strdup(cep->ce_vardata);
  3567.                 s->setby = strdup("oper");
  3568.                 AddListItem(s, oper->swhois);
  3569.             }
  3570.         }
  3571.         else if (!strcmp(cep->ce_varname, "snomask"))
  3572.         {
  3573.             safestrdup(oper->snomask, cep->ce_vardata);
  3574.         }
  3575.         else if (!strcmp(cep->ce_varname, "modes"))
  3576.         {
  3577.             oper->modes = set_usermode(cep->ce_vardata);
  3578.         }
  3579.         else if (!strcmp(cep->ce_varname, "require-modes"))
  3580.         {
  3581.             oper->require_modes = set_usermode(cep->ce_vardata);
  3582.         }
  3583.         else if (!strcmp(cep->ce_varname, "maxlogins"))
  3584.         {
  3585.             oper->maxlogins = atoi(cep->ce_vardata);
  3586.         }
  3587.         else if (!strcmp(cep->ce_varname, "mask"))
  3588.         {
  3589.             unreal_add_masks(&oper->mask, cep);
  3590.         }
  3591.         else if (!strcmp(cep->ce_varname, "vhost"))
  3592.         {
  3593.             safestrdup(oper->vhost, cep->ce_vardata);
  3594.         }
  3595.     }
  3596.     AddListItem(oper, conf_oper);
  3597.     return 1;
  3598. }
  3599.  
  3600. int _test_oper(ConfigFile *conf, ConfigEntry *ce)
  3601. {
  3602.     char has_class = 0, has_password = 0, has_swhois = 0, has_snomask = 0;
  3603.     char has_modes = 0, has_require_modes = 0, has_mask = 0, has_maxlogins = 0;
  3604.     char has_operclass = 0, has_vhost = 0;
  3605.     int oper_flags = 0;
  3606.     ConfigEntry *cep;
  3607.     ConfigEntry *cepp;
  3608.     NameValue *ofp;
  3609.     int errors = 0;
  3610.  
  3611.     if (!ce->ce_vardata)
  3612.     {
  3613.         config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "oper");
  3614.         errors++;
  3615.     }
  3616.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3617.     {
  3618.         if (!cep->ce_varname)
  3619.         {
  3620.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  3621.                 "oper");
  3622.             errors++;
  3623.             continue;
  3624.         }
  3625.         /* Regular variables */
  3626.         if (!cep->ce_entries)
  3627.         {
  3628.             if (config_is_blankorempty(cep, "oper"))
  3629.             {
  3630.                 errors++;
  3631.                 continue;
  3632.             }
  3633.             /* oper::password */
  3634.             if (!strcmp(cep->ce_varname, "password"))
  3635.             {
  3636.                 if (has_password)
  3637.                 {
  3638.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3639.                         cep->ce_varlinenum, "oper::password");
  3640.                     continue;
  3641.                 }
  3642.                 has_password = 1;
  3643.                 if (Auth_CheckError(cep) < 0)
  3644.                     errors++;
  3645.  
  3646.                 if (ce->ce_vardata && cep->ce_vardata &&
  3647.                     !strcmp(ce->ce_vardata, "bobsmith") &&
  3648.                     !strcmp(cep->ce_vardata, "test"))
  3649.                 {
  3650.                     config_error("%s:%i: please change the the name and password of the "
  3651.                                  "default 'bobsmith' oper block",
  3652.                                  ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  3653.                     errors++;
  3654.                 }
  3655.                 continue;
  3656.             }
  3657.             /* oper::operclass */
  3658.             else if (!strcmp(cep->ce_varname, "operclass"))
  3659.             {
  3660.                 if (has_operclass)
  3661.                 {
  3662.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3663.                     cep->ce_varlinenum, "oper::operclass");
  3664.                     continue;
  3665.                 }
  3666.                 has_operclass = 1;
  3667.                 continue;
  3668.             }
  3669.             /* oper::class */
  3670.             else if (!strcmp(cep->ce_varname, "class"))
  3671.             {
  3672.                 if (has_class)
  3673.                 {
  3674.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3675.                         cep->ce_varlinenum, "oper::class");
  3676.                     continue;
  3677.                 }
  3678.                 has_class = 1;
  3679.             }
  3680.             /* oper::swhois */
  3681.             else if (!strcmp(cep->ce_varname, "swhois"))
  3682.             {
  3683.             }
  3684.             /* oper::vhost */
  3685.             else if (!strcmp(cep->ce_varname, "vhost"))
  3686.             {
  3687.                 if (has_vhost)
  3688.                 {
  3689.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3690.                         cep->ce_varlinenum, "oper::vhost");
  3691.                     continue;
  3692.                 }
  3693.                 has_vhost = 1;
  3694.             }
  3695.             /* oper::snomask */
  3696.             else if (!strcmp(cep->ce_varname, "snomask"))
  3697.             {
  3698.                 if (has_snomask)
  3699.                 {
  3700.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3701.                         cep->ce_varlinenum, "oper::snomask");
  3702.                     continue;
  3703.                 }
  3704.                 has_snomask = 1;
  3705.             }
  3706.             /* oper::modes */
  3707.             else if (!strcmp(cep->ce_varname, "modes"))
  3708.             {
  3709.                 char *p;
  3710.                 for (p = cep->ce_vardata; *p; p++)
  3711.                     if (strchr("oOaANCrzS", *p))
  3712.                     {
  3713.                         config_error("%s:%i: oper::modes may not include mode '%c'",
  3714.                             cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
  3715.                         errors++;
  3716.                     }
  3717.                 if (has_modes)
  3718.                 {
  3719.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3720.                         cep->ce_varlinenum, "oper::modes");
  3721.                     continue;
  3722.                 }
  3723.                 has_modes = 1;
  3724.             }
  3725.             /* oper::require-modes */
  3726.             else if (!strcmp(cep->ce_varname, "require-modes"))
  3727.             {
  3728.                 char *p;
  3729.                 for (p = cep->ce_vardata; *p; p++)
  3730.                     if (strchr("oOaANC", *p))
  3731.                     {
  3732.                         config_warn("%s:%i: oper::require-modes probably shouldn't include mode '%c'",
  3733.                             cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
  3734.                     }
  3735.                 if (has_require_modes)
  3736.                 {
  3737.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3738.                         cep->ce_varlinenum, "oper::require-modes");
  3739.                     continue;
  3740.                 }
  3741.                 has_require_modes = 1;
  3742.             }
  3743.             /* oper::maxlogins */
  3744.             else if (!strcmp(cep->ce_varname, "maxlogins"))
  3745.             {
  3746.                 int l;
  3747.  
  3748.                 if (has_maxlogins)
  3749.                 {
  3750.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3751.                         cep->ce_varlinenum, "oper::maxlogins");
  3752.                     continue;
  3753.                 }
  3754.                 has_maxlogins = 1;
  3755.  
  3756.                 l = atoi(cep->ce_vardata);
  3757.                 if ((l < 0) || (l > 5000))
  3758.                 {
  3759.                     config_error("%s:%i: oper::maxlogins: value out of range (%d) should be 0-5000",
  3760.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, l);
  3761.                     errors++;
  3762.                     continue;
  3763.                 }
  3764.             }
  3765.             /* oper::flags */
  3766.             else if (!strcmp(cep->ce_varname, "flags"))
  3767.             {
  3768.                 config_error("%s:%i: oper::flags no longer exists. UnrealIRCd 4 uses a new style oper block.",
  3769.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3770.                 errors++;
  3771.                 need_34_upgrade = 1;
  3772.             }
  3773.             else if (!strcmp(cep->ce_varname, "mask"))
  3774.             {
  3775.                 if (cep->ce_vardata || cep->ce_entries)
  3776.                     has_mask = 1;
  3777.             }
  3778.             else
  3779.             {
  3780.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  3781.                     cep->ce_varlinenum, "oper", cep->ce_varname);
  3782.                 errors++;
  3783.                 continue;
  3784.             }
  3785.         }
  3786.         /* Sections */
  3787.         else
  3788.         {
  3789.             /* oper::flags {} */
  3790.             if (!strcmp(cep->ce_varname, "flags"))
  3791.             {
  3792.                 config_error("%s:%i: oper::flags no longer exists. UnrealIRCd 4 uses a new style oper block.",
  3793.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3794.                 errors++;
  3795.                 need_34_upgrade = 1;
  3796.                 continue;
  3797.             }
  3798.             /* oper::from {} */
  3799.             else if (!strcmp(cep->ce_varname, "from"))
  3800.             {
  3801.                 config_error("%s:%i: oper::from::userhost is now called oper::mask",
  3802.                              cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3803.                 errors++;
  3804.                 need_34_upgrade = 1;
  3805.                 continue;
  3806.             }
  3807.             else if (!strcmp(cep->ce_varname, "swhois"))
  3808.             {
  3809.                 /* ok */
  3810.             }
  3811.             else if (!strcmp(cep->ce_varname, "mask"))
  3812.             {
  3813.                 if (cep->ce_vardata || cep->ce_entries)
  3814.                     has_mask = 1;
  3815.             }
  3816.             else if (!strcmp(cep->ce_varname, "password"))
  3817.             {
  3818.                 if (has_password)
  3819.                 {
  3820.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3821.                         cep->ce_varlinenum, "oper::password");
  3822.                     continue;
  3823.                 }
  3824.                 has_password = 1;
  3825.                 if (Auth_CheckError(cep) < 0)
  3826.                     errors++;
  3827.             }
  3828.             else
  3829.             {
  3830.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  3831.                     cep->ce_varlinenum, "oper", cep->ce_varname);
  3832.                 errors++;
  3833.                 continue;
  3834.             }
  3835.         }
  3836.     }
  3837.     if (!has_password)
  3838.     {
  3839.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3840.             "oper::password");
  3841.         errors++;
  3842.     }
  3843.     if (!has_mask)
  3844.     {
  3845.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3846.             "oper::mask");
  3847.         errors++;
  3848.     }
  3849.     if (!has_class)
  3850.     {
  3851.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3852.             "oper::class");
  3853.         errors++;
  3854.     }
  3855.     if (!has_operclass)
  3856.     {
  3857.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  3858.             "oper::operclass");
  3859.         need_34_upgrade = 1;
  3860.         errors++;
  3861.     }
  3862.  
  3863.     return errors;
  3864.  
  3865. }
  3866.  
  3867. /*
  3868.  * The class {} block parser
  3869. */
  3870. int _conf_class(ConfigFile *conf, ConfigEntry *ce)
  3871. {
  3872.     ConfigEntry *cep, *cep2;
  3873.     ConfigItem_class *class;
  3874.     unsigned char isnew = 0;
  3875.  
  3876.     if (!(class = Find_class(ce->ce_vardata)))
  3877.     {
  3878.         class = MyMallocEx(sizeof(ConfigItem_class));
  3879.         safestrdup(class->name, ce->ce_vardata);
  3880.         isnew = 1;
  3881.     }
  3882.     else
  3883.     {
  3884.         isnew = 0;
  3885.         class->flag.temporary = 0;
  3886.         class->options = 0; /* RESET OPTIONS */
  3887.     }
  3888.     safestrdup(class->name, ce->ce_vardata);
  3889.  
  3890.     class->connfreq = 15; /* default */
  3891.  
  3892.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3893.     {
  3894.         if (!strcmp(cep->ce_varname, "pingfreq"))
  3895.             class->pingfreq = config_checkval(cep->ce_vardata,CFG_TIME);
  3896.         else if (!strcmp(cep->ce_varname, "connfreq"))
  3897.             class->connfreq = config_checkval(cep->ce_vardata,CFG_TIME);
  3898.         else if (!strcmp(cep->ce_varname, "maxclients"))
  3899.             class->maxclients = atol(cep->ce_vardata);
  3900.         else if (!strcmp(cep->ce_varname, "sendq"))
  3901.             class->sendq = config_checkval(cep->ce_vardata,CFG_SIZE);
  3902.         else if (!strcmp(cep->ce_varname, "recvq"))
  3903.             class->recvq = config_checkval(cep->ce_vardata,CFG_SIZE);
  3904.         else if (!strcmp(cep->ce_varname, "options"))
  3905.         {
  3906.             for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
  3907.                 if (!strcmp(cep2->ce_varname, "nofakelag"))
  3908.                     class->options |= CLASS_OPT_NOFAKELAG;
  3909.         }
  3910.     }
  3911.     if (isnew)
  3912.         AddListItem(class, conf_class);
  3913.     return 1;
  3914. }
  3915.  
  3916. int _test_class(ConfigFile *conf, ConfigEntry *ce)
  3917. {
  3918.     ConfigEntry     *cep, *cep2;
  3919.     int     errors = 0;
  3920.     char has_pingfreq = 0, has_connfreq = 0, has_maxclients = 0, has_sendq = 0;
  3921.     char has_recvq = 0;
  3922.  
  3923.     if (!ce->ce_vardata)
  3924.     {
  3925.         config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "class");
  3926.         return 1;
  3927.     }
  3928.     if (!strcasecmp(ce->ce_vardata, "default"))
  3929.     {
  3930.         config_error("%s:%d: Class cannot be named 'default', this class name is reserved for internal use.",
  3931.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  3932.         errors++;
  3933.     }
  3934.  
  3935.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  3936.     {
  3937.         if (!strcmp(cep->ce_varname, "options"))
  3938.         {
  3939.             for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
  3940.             {
  3941. #ifdef FAKELAG_CONFIGURABLE
  3942.                 if (!strcmp(cep2->ce_varname, "nofakelag"))
  3943.                     ;
  3944.                 else
  3945. #endif
  3946.                 {
  3947.                     config_error("%s:%d: Unknown option '%s' in class::options",
  3948.                         cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep2->ce_varname);
  3949.                     errors++;
  3950.                 }
  3951.             }
  3952.         }
  3953.         else if (config_is_blankorempty(cep, "class"))
  3954.         {
  3955.             errors++;
  3956.             continue;
  3957.         }
  3958.         /* class::pingfreq */
  3959.         else if (!strcmp(cep->ce_varname, "pingfreq"))
  3960.         {
  3961.             int v = config_checkval(cep->ce_vardata,CFG_TIME);
  3962.             if (has_pingfreq)
  3963.             {
  3964.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3965.                     cep->ce_varlinenum, "class::pingfreq");
  3966.                 continue;
  3967.             }
  3968.             has_pingfreq = 1;
  3969.             if ((v < 30) || (v > 600))
  3970.             {
  3971.                 config_error("%s:%i: class::pingfreq should be a reasonable value (30-600)",
  3972.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3973.                 errors++;
  3974.                 continue;
  3975.             }
  3976.         }
  3977.         /* class::maxclients */
  3978.         else if (!strcmp(cep->ce_varname, "maxclients"))
  3979.         {
  3980.             long l;
  3981.             if (has_maxclients)
  3982.             {
  3983.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  3984.                     cep->ce_varlinenum, "class::maxclients");
  3985.                 continue;
  3986.             }
  3987.             has_maxclients = 1;
  3988.             l = atol(cep->ce_vardata);
  3989.             if ((l < 1) || (l > 1000000))
  3990.             {
  3991.                 config_error("%s:%i: class::maxclients with illegal value",
  3992.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  3993.                 errors++;
  3994.             }
  3995.         }
  3996.         /* class::connfreq */
  3997.         else if (!strcmp(cep->ce_varname, "connfreq"))
  3998.         {
  3999.             long l;
  4000.             if (has_connfreq)
  4001.             {
  4002.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4003.                     cep->ce_varlinenum, "class::connfreq");
  4004.                 continue;
  4005.             }
  4006.             has_connfreq = 1;
  4007.             l = config_checkval(cep->ce_vardata,CFG_TIME);
  4008.             if ((l < 5) || (l > 604800))
  4009.             {
  4010.                 config_error("%s:%i: class::connfreq with illegal value (must be >5 and <7d)",
  4011.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4012.                 errors++;
  4013.             }
  4014.         }
  4015.         /* class::sendq */
  4016.         else if (!strcmp(cep->ce_varname, "sendq"))
  4017.         {
  4018.             long l;
  4019.             if (has_sendq)
  4020.             {
  4021.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4022.                     cep->ce_varlinenum, "class::sendq");
  4023.                 continue;
  4024.             }
  4025.             has_sendq = 1;
  4026.             l = config_checkval(cep->ce_vardata,CFG_SIZE);
  4027.             if ((l <= 0) || (l > 2000000000))
  4028.             {
  4029.                 config_error("%s:%i: class::sendq with illegal value",
  4030.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4031.                 errors++;
  4032.             }
  4033.         }
  4034.         /* class::recvq */
  4035.         else if (!strcmp(cep->ce_varname, "recvq"))
  4036.         {
  4037.             long l;
  4038.             if (has_recvq)
  4039.             {
  4040.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4041.                     cep->ce_varlinenum, "class::recvq");
  4042.                 continue;
  4043.             }
  4044.             has_recvq = 1;
  4045.             l = config_checkval(cep->ce_vardata,CFG_SIZE);
  4046.             if ((l < 512) || (l > 32768))
  4047.             {
  4048.                 config_error("%s:%i: class::recvq with illegal value (must be >512 and <32k)",
  4049.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4050.                 errors++;
  4051.             }
  4052.         }
  4053.         /* Unknown */
  4054.         else
  4055.         {
  4056.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4057.                 "class", cep->ce_varname);
  4058.             errors++;
  4059.             continue;
  4060.         }
  4061.     }
  4062.     if (!has_pingfreq)
  4063.     {
  4064.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4065.             "class::pingfreq");
  4066.         errors++;
  4067.     }
  4068.     if (!has_maxclients)
  4069.     {
  4070.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4071.             "class::maxclients");
  4072.         errors++;
  4073.     }
  4074.     if (!has_sendq)
  4075.     {
  4076.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4077.             "class::sendq");
  4078.         errors++;
  4079.     }
  4080.  
  4081.     return errors;
  4082. }
  4083.  
  4084. int     _conf_drpass(ConfigFile *conf, ConfigEntry *ce)
  4085. {
  4086.     ConfigEntry *cep;
  4087.  
  4088.     if (!conf_drpass)
  4089.     {
  4090.         conf_drpass =  MyMallocEx(sizeof(ConfigItem_drpass));
  4091.     }
  4092.  
  4093.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4094.     {
  4095.         if (!strcmp(cep->ce_varname, "restart"))
  4096.         {
  4097.             if (conf_drpass->restartauth)
  4098.                 Auth_DeleteAuthStruct(conf_drpass->restartauth);
  4099.  
  4100.             conf_drpass->restartauth = Auth_ConvertConf2AuthStruct(cep);
  4101.         }
  4102.         else if (!strcmp(cep->ce_varname, "die"))
  4103.         {
  4104.             if (conf_drpass->dieauth)
  4105.                 Auth_DeleteAuthStruct(conf_drpass->dieauth);
  4106.  
  4107.             conf_drpass->dieauth = Auth_ConvertConf2AuthStruct(cep);
  4108.         }
  4109.     }
  4110.     return 1;
  4111. }
  4112.  
  4113. int     _test_drpass(ConfigFile *conf, ConfigEntry *ce)
  4114. {
  4115.     ConfigEntry *cep;
  4116.     int errors = 0;
  4117.     char has_restart = 0, has_die = 0;
  4118.  
  4119.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4120.     {
  4121.         if (config_is_blankorempty(cep, "drpass"))
  4122.         {
  4123.             errors++;
  4124.             continue;
  4125.         }
  4126.         /* drpass::restart */
  4127.         if (!strcmp(cep->ce_varname, "restart"))
  4128.         {
  4129.             if (has_restart)
  4130.             {
  4131.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4132.                     cep->ce_varlinenum, "drpass::restart");
  4133.                 continue;
  4134.             }
  4135.             has_restart = 1;
  4136.             if (Auth_CheckError(cep) < 0)
  4137.                 errors++;
  4138.             continue;
  4139.         }
  4140.         /* drpass::die */
  4141.         else if (!strcmp(cep->ce_varname, "die"))
  4142.         {
  4143.             if (has_die)
  4144.             {
  4145.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4146.                     cep->ce_varlinenum, "drpass::die");
  4147.                 continue;
  4148.             }
  4149.             has_die = 1;
  4150.             if (Auth_CheckError(cep) < 0)
  4151.                 errors++;
  4152.             continue;
  4153.         }
  4154.         /* Unknown */
  4155.         else
  4156.         {
  4157.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4158.                 "drpass", cep->ce_varname);
  4159.             errors++;
  4160.             continue;
  4161.         }
  4162.     }
  4163.     return errors;
  4164. }
  4165.  
  4166. /*
  4167.  * The ulines {} block parser
  4168. */
  4169. int _conf_ulines(ConfigFile *conf, ConfigEntry *ce)
  4170. {
  4171.     ConfigEntry *cep;
  4172.     ConfigItem_ulines *ca;
  4173.  
  4174.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4175.     {
  4176.         ca = MyMallocEx(sizeof(ConfigItem_ulines));
  4177.         safestrdup(ca->servername, cep->ce_varname);
  4178.         AddListItem(ca, conf_ulines);
  4179.     }
  4180.     return 1;
  4181. }
  4182.  
  4183. int _test_ulines(ConfigFile *conf, ConfigEntry *ce)
  4184. {
  4185.     ConfigEntry *cep;
  4186.     int         errors = 0;
  4187.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4188.     {
  4189.         if (!cep->ce_varname)
  4190.         {
  4191.             config_error_blank(cep->ce_fileptr->cf_filename,
  4192.                 cep->ce_varlinenum, "ulines");
  4193.             errors++;
  4194.             continue;
  4195.         }
  4196.     }
  4197.     return errors;
  4198. }
  4199.  
  4200. int     _conf_tld(ConfigFile *conf, ConfigEntry *ce)
  4201. {
  4202.     ConfigEntry *cep;
  4203.     ConfigItem_tld *ca;
  4204.  
  4205.     ca = MyMallocEx(sizeof(ConfigItem_tld));
  4206.  
  4207.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4208.     {
  4209.         if (!strcmp(cep->ce_varname, "mask"))
  4210.             ca->mask = strdup(cep->ce_vardata);
  4211.         else if (!strcmp(cep->ce_varname, "motd"))
  4212.         {
  4213.             ca->motd_file = strdup(cep->ce_vardata);
  4214.             read_motd(cep->ce_vardata, &ca->motd);
  4215.         }
  4216.         else if (!strcmp(cep->ce_varname, "shortmotd"))
  4217.         {
  4218.             ca->smotd_file = strdup(cep->ce_vardata);
  4219.             read_motd(cep->ce_vardata, &ca->smotd);
  4220.         }
  4221.         else if (!strcmp(cep->ce_varname, "opermotd"))
  4222.         {
  4223.             ca->opermotd_file = strdup(cep->ce_vardata);
  4224.             read_motd(cep->ce_vardata, &ca->opermotd);
  4225.         }
  4226.         else if (!strcmp(cep->ce_varname, "botmotd"))
  4227.         {
  4228.             ca->botmotd_file = strdup(cep->ce_vardata);
  4229.             read_motd(cep->ce_vardata, &ca->botmotd);
  4230.         }
  4231.         else if (!strcmp(cep->ce_varname, "rules"))
  4232.         {
  4233.             ca->rules_file = strdup(cep->ce_vardata);
  4234.             read_motd(cep->ce_vardata, &ca->rules);
  4235.         }
  4236.         else if (!strcmp(cep->ce_varname, "options"))
  4237.         {
  4238.             ConfigEntry *cepp;
  4239.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  4240.             {
  4241.                 if (!strcmp(cepp->ce_varname, "ssl"))
  4242.                     ca->options |= TLD_SSL;
  4243.                 else if (!strcmp(cepp->ce_varname, "remote"))
  4244.                     ca->options |= TLD_REMOTE;
  4245.             }
  4246.         }
  4247.         else if (!strcmp(cep->ce_varname, "channel"))
  4248.             ca->channel = strdup(cep->ce_vardata);
  4249.     }
  4250.     AddListItem(ca, conf_tld);
  4251.     return 1;
  4252. }
  4253.  
  4254. int     _test_tld(ConfigFile *conf, ConfigEntry *ce)
  4255. {
  4256.     ConfigEntry *cep;
  4257.     int     errors = 0;
  4258.     int     fd = -1;
  4259.     char has_mask = 0, has_motd = 0, has_rules = 0, has_shortmotd = 0, has_channel = 0;
  4260.     char has_opermotd = 0, has_botmotd = 0, has_options = 0;
  4261.  
  4262.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4263.     {
  4264.         if (!cep->ce_varname)
  4265.         {
  4266.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4267.                 "tld");
  4268.             errors++;
  4269.             continue;
  4270.         }
  4271.         if (!cep->ce_vardata && strcmp(cep->ce_varname, "options"))
  4272.         {
  4273.             config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4274.                 "tld", cep->ce_varname);
  4275.             errors++;
  4276.             continue;
  4277.         }
  4278.         /* tld::mask */
  4279.         if (!strcmp(cep->ce_varname, "mask"))
  4280.         {
  4281.             if (has_mask)
  4282.             {
  4283.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4284.                     cep->ce_varlinenum, "tld::mask");
  4285.                 continue;
  4286.             }
  4287.             has_mask = 1;
  4288.         }
  4289.         /* tld::motd */
  4290.         else if (!strcmp(cep->ce_varname, "motd"))
  4291.         {
  4292.             if (has_motd)
  4293.             {
  4294.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4295.                     cep->ce_varlinenum, "tld::motd");
  4296.                 continue;
  4297.             }
  4298.             has_motd = 1;
  4299.             convert_to_absolute_path(&cep->ce_vardata, CONFDIR);
  4300.             if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
  4301.             {
  4302.                 config_error("%s:%i: tld::motd: %s: %s",
  4303.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4304.                     cep->ce_vardata, strerror(errno));
  4305.                 errors++;
  4306.             }
  4307.             else
  4308.                 close(fd);
  4309.         }
  4310.         /* tld::rules */
  4311.         else if (!strcmp(cep->ce_varname, "rules"))
  4312.         {
  4313.             if (has_rules)
  4314.             {
  4315.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4316.                     cep->ce_varlinenum, "tld::rules");
  4317.                 continue;
  4318.             }
  4319.             has_rules = 1;
  4320.             convert_to_absolute_path(&cep->ce_vardata, CONFDIR);
  4321.             if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
  4322.             {
  4323.                 config_error("%s:%i: tld::rules: %s: %s",
  4324.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4325.                     cep->ce_vardata, strerror(errno));
  4326.                 errors++;
  4327.             }
  4328.             else
  4329.                 close(fd);
  4330.         }
  4331.         /* tld::channel */
  4332.         else if (!strcmp(cep->ce_varname, "channel"))
  4333.         {
  4334.             if (has_channel)
  4335.             {
  4336.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4337.                     cep->ce_varlinenum, "tld::channel");
  4338.                 continue;
  4339.             }
  4340.             has_channel = 1;
  4341.         }
  4342.         /* tld::shortmotd */
  4343.         else if (!strcmp(cep->ce_varname, "shortmotd"))
  4344.         {
  4345.             if (has_shortmotd)
  4346.             {
  4347.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4348.                     cep->ce_varlinenum, "tld::shortmotd");
  4349.                 continue;
  4350.             }
  4351.             has_shortmotd = 1;
  4352.             convert_to_absolute_path(&cep->ce_vardata, CONFDIR);
  4353.             if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
  4354.             {
  4355.                 config_error("%s:%i: tld::shortmotd: %s: %s",
  4356.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4357.                     cep->ce_vardata, strerror(errno));
  4358.                 errors++;
  4359.             }
  4360.             else
  4361.                 close(fd);
  4362.         }
  4363.         /* tld::opermotd */
  4364.         else if (!strcmp(cep->ce_varname, "opermotd"))
  4365.         {
  4366.             if (has_opermotd)
  4367.             {
  4368.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4369.                     cep->ce_varlinenum, "tld::opermotd");
  4370.                 continue;
  4371.             }
  4372.             has_opermotd = 1;
  4373.             convert_to_absolute_path(&cep->ce_vardata, CONFDIR);
  4374.             if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
  4375.             {
  4376.                 config_error("%s:%i: tld::opermotd: %s: %s",
  4377.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4378.                     cep->ce_vardata, strerror(errno));
  4379.                 errors++;
  4380.             }
  4381.             else
  4382.                 close(fd);
  4383.         }
  4384.         /* tld::botmotd */
  4385.         else if (!strcmp(cep->ce_varname, "botmotd"))
  4386.         {
  4387.             if (has_botmotd)
  4388.             {
  4389.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4390.                     cep->ce_varlinenum, "tld::botmotd");
  4391.                 continue;
  4392.             }
  4393.             has_botmotd = 1;
  4394.             convert_to_absolute_path(&cep->ce_vardata, CONFDIR);
  4395.             if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
  4396.             {
  4397.                 config_error("%s:%i: tld::botmotd: %s: %s",
  4398.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4399.                     cep->ce_vardata, strerror(errno));
  4400.                 errors++;
  4401.             }
  4402.             else
  4403.                 close(fd);
  4404.         }
  4405.         /* tld::options */
  4406.         else if (!strcmp(cep->ce_varname, "options")) {
  4407.             ConfigEntry *cep2;
  4408.  
  4409.             if (has_options)
  4410.             {
  4411.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4412.                     cep->ce_varlinenum, "tld::options");
  4413.                 continue;
  4414.             }
  4415.             has_options = 1;
  4416.  
  4417.             for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
  4418.             {
  4419.                 if (!cep2->ce_varname)
  4420.                 {
  4421.                     config_error_blank(cep2->ce_fileptr->cf_filename,
  4422.                         cep2->ce_varlinenum, "tld::options");
  4423.                     continue;
  4424.                 }
  4425.                 if (strcmp(cep2->ce_varname, "ssl") &&
  4426.                     strcmp(cep2->ce_varname, "remote"))
  4427.                 {
  4428.                     config_error_unknownopt(cep2->ce_fileptr->cf_filename,
  4429.                         cep2->ce_varlinenum, "tld", cep2->ce_varname);
  4430.                     errors++;
  4431.                 }
  4432.             }
  4433.         }
  4434.         else
  4435.         {
  4436.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4437.                 "tld", cep->ce_varname);
  4438.             errors++;
  4439.             continue;
  4440.         }
  4441.     }
  4442.     if (!has_mask)
  4443.     {
  4444.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4445.             "tld::mask");
  4446.         errors++;
  4447.     }
  4448.     if (!has_motd)
  4449.     {
  4450.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4451.             "tld::motd");
  4452.         errors++;
  4453.     }
  4454.     if (!has_rules)
  4455.     {
  4456.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  4457.             "tld::rules");
  4458.         errors++;
  4459.     }
  4460.     return errors;
  4461. }
  4462.  
  4463. int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
  4464. {
  4465.     ConfigEntry *cep;
  4466.     ConfigEntry *cepp;
  4467.     ConfigItem_listen *listen = NULL;
  4468.     char *ip;
  4469.     int start=0, end=0, port, isnew;
  4470.     int tmpflags =0;
  4471.  
  4472.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4473.     {
  4474.         if (!strcmp(cep->ce_varname, "ip"))
  4475.         {
  4476.             ip = cep->ce_vardata;
  4477.         } else
  4478.         if (!strcmp(cep->ce_varname, "port"))
  4479.         {
  4480.             port_range(cep->ce_vardata, &start, &end);
  4481.             if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
  4482.                 return -1; /* this is already validated in _test_listen, but okay.. */
  4483.         } else
  4484.         if (!strcmp(cep->ce_varname, "options"))
  4485.         {
  4486.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  4487.             {
  4488.                 NameValue *ofp;
  4489.                 if ((ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
  4490.                     tmpflags |= ofp->flag;
  4491.             }
  4492.         }
  4493.     }
  4494.     for (port = start; port <= end; port++)
  4495.     {
  4496.         /* First deal with IPv4 */
  4497.         if (!strchr(ip, ':'))
  4498.         {
  4499.             if (!(listen = Find_listen(ip, port, 0)))
  4500.             {
  4501.                 listen = MyMallocEx(sizeof(ConfigItem_listen));
  4502.                 listen->ip = strdup(ip);
  4503.                 listen->port = port;
  4504.                 listen->fd = -1;
  4505.                 listen->ipv6 = 0;
  4506.                 isnew = 1;
  4507.             } else
  4508.                 isnew = 0;
  4509.  
  4510.             if (listen->options & LISTENER_BOUND)
  4511.                 tmpflags |= LISTENER_BOUND;
  4512.  
  4513.             listen->options = tmpflags;
  4514.             if (isnew)
  4515.                 AddListItem(listen, conf_listen);
  4516.             listen->flag.temporary = 0;
  4517.         }
  4518.  
  4519.         /* Then deal with IPv6 (if available/enabled) */
  4520.         if (!DISABLE_IPV6)
  4521.         {
  4522.             if (strchr(ip, ':') || (*ip == '*'))
  4523.             {
  4524.                 if (!(listen = Find_listen(ip, port, 1)))
  4525.                 {
  4526.                     listen = MyMallocEx(sizeof(ConfigItem_listen));
  4527.                     listen->ip = strdup(ip);
  4528.                     listen->port = port;
  4529.                     listen->fd = -1;
  4530.                     listen->ipv6 = 1;
  4531.                     isnew = 1;
  4532.                 } else
  4533.                     isnew = 0;
  4534.  
  4535.                 if (listen->options & LISTENER_BOUND)
  4536.                     tmpflags |= LISTENER_BOUND;
  4537.  
  4538.                 listen->options = tmpflags;
  4539.                 if (isnew)
  4540.                     AddListItem(listen, conf_listen);
  4541.                 listen->flag.temporary = 0;
  4542.             }
  4543.         }
  4544.     }
  4545.     return 1;
  4546. }
  4547.  
  4548. int _test_listen(ConfigFile *conf, ConfigEntry *ce)
  4549. {
  4550.     ConfigEntry *cep;
  4551.     ConfigEntry *cepp;
  4552.     int errors = 0;
  4553.     char has_ip = 0, has_port = 0, has_options = 0;
  4554.  
  4555.     if (ce->ce_vardata)
  4556.     {
  4557.         config_error("%s:%i: listen block has a new syntax, see https://www.unrealircd.org/docs/Listen_block",
  4558.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4559.            
  4560.         need_34_upgrade = 1;
  4561.         return 1;
  4562.     }
  4563.  
  4564.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4565.     {
  4566.         if (!cep->ce_varname)
  4567.         {
  4568.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4569.                 "listen");
  4570.             errors++;
  4571.             continue;
  4572.         }
  4573.         if (!strcmp(cep->ce_varname, "options"))
  4574.         {
  4575.             if (has_options)
  4576.             {
  4577.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4578.                     cep->ce_varlinenum, "listen::options");
  4579.                 continue;
  4580.             }
  4581.             has_options = 1;
  4582.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  4583.             {
  4584.                 NameValue *ofp;
  4585.                 if (!cepp->ce_varname)
  4586.                 {
  4587.                     config_error_blank(cepp->ce_fileptr->cf_filename,
  4588.                         cepp->ce_varlinenum, "listen::options");
  4589.                     errors++;
  4590.                     continue;
  4591.                 }
  4592.                 if (!(ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
  4593.                 {
  4594.                     config_error_unknownopt(cepp->ce_fileptr->cf_filename,
  4595.                         cepp->ce_varlinenum, "listen::options", cepp->ce_varname);
  4596.                     errors++;
  4597.                     continue;
  4598.                 }
  4599.             }
  4600.         }
  4601.         else
  4602.         if (!cep->ce_vardata)
  4603.         {
  4604.             config_error_empty(cep->ce_fileptr->cf_filename,
  4605.                 cep->ce_varlinenum, "listen", cep->ce_varname);
  4606.             errors++;
  4607.             continue;
  4608.         } else
  4609.         if (!strcmp(cep->ce_varname, "ip"))
  4610.         {
  4611.             has_ip = 1;
  4612.            
  4613.             if (strcmp(cep->ce_vardata, "*") && !is_valid_ip(cep->ce_vardata))
  4614.             {
  4615.                 config_error("%s:%i: listen: illegal listen::ip (%s). Must be either '*' or contain a valid IP.",
  4616.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
  4617.                 return 1;
  4618.             }
  4619.         } else
  4620.         if (!strcmp(cep->ce_varname, "host"))
  4621.         {
  4622.             config_error("%s:%i: listen: unknown option listen::host, did you mean listen::ip?",
  4623.                 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4624.             errors++;
  4625.         } else
  4626.         if (!strcmp(cep->ce_varname, "port"))
  4627.         {
  4628.             int start = 0, end = 0;
  4629.  
  4630.             has_port = 1;
  4631.  
  4632.             port_range(cep->ce_vardata, &start, &end);
  4633.             if (start == end)
  4634.             {
  4635.                 if ((start < 0) || (start > 65535))
  4636.                 {
  4637.                     config_error("%s:%i: listen: illegal port (must be 0..65535)",
  4638.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4639.                     return 1;
  4640.                 }
  4641.             }
  4642.             else
  4643.             {
  4644.                 if (end < start)
  4645.                 {
  4646.                     config_error("%s:%i: listen: illegal port range end value is less than starting value",
  4647.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4648.                     return 1;
  4649.                 }
  4650.                 if (end - start >= 100)
  4651.                 {
  4652.                     config_error("%s:%i: listen: you requested port %d-%d, that's %d ports "
  4653.                         "(and thus consumes %d sockets) this is probably not what you want.",
  4654.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, start, end,
  4655.                         end - start + 1, end - start + 1);
  4656.                     return 1;
  4657.                 }
  4658.                 if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
  4659.                 {
  4660.                     config_error("%s:%i: listen: illegal port range values must be between 0 and 65535",
  4661.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4662.                     return 1;
  4663.                 }
  4664.             }
  4665.         } else
  4666.         {
  4667.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4668.                 "listen", cep->ce_varname);
  4669.             errors++;
  4670.             continue;
  4671.         }
  4672.     }
  4673.    
  4674.     if (!has_ip)
  4675.     {
  4676.         config_error("%s:%d: listen block requires an listen::ip",
  4677.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4678.         errors++;
  4679.     }
  4680.  
  4681.     if (!has_port)
  4682.     {
  4683.         config_error("%s:%d: listen block requires an listen::port",
  4684.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4685.         errors++;
  4686.     }
  4687.  
  4688.     requiredstuff.conf_listen = 1;
  4689.     return errors;
  4690. }
  4691.  
  4692.  
  4693. int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
  4694. {
  4695.     ConfigEntry *cep, *cepp;
  4696.     ConfigItem_allow *allow;
  4697.     Hook *h;
  4698.  
  4699.     if (ce->ce_vardata)
  4700.     {
  4701.         if (!strcmp(ce->ce_vardata, "channel"))
  4702.             return (_conf_allow_channel(conf, ce));
  4703.         else if (!strcmp(ce->ce_vardata, "dcc"))
  4704.             return (_conf_allow_dcc(conf, ce));
  4705.         else
  4706.         {
  4707.             int value;
  4708.             for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  4709.             {
  4710.                 value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW);
  4711.                 if (value == 1)
  4712.                     break;
  4713.             }
  4714.             return 0;
  4715.         }
  4716.     }
  4717.     allow = MyMallocEx(sizeof(ConfigItem_allow));
  4718.  
  4719.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4720.     {
  4721.         if (!strcmp(cep->ce_varname, "ip"))
  4722.         {
  4723.             allow->ip = strdup(cep->ce_vardata);
  4724.         }
  4725.         else if (!strcmp(cep->ce_varname, "hostname"))
  4726.             allow->hostname = strdup(cep->ce_vardata);
  4727.         else if (!strcmp(cep->ce_varname, "password"))
  4728.             allow->auth = Auth_ConvertConf2AuthStruct(cep);
  4729.         else if (!strcmp(cep->ce_varname, "class"))
  4730.         {
  4731.             allow->class = Find_class(cep->ce_vardata);
  4732.             if (!allow->class || (allow->class->flag.temporary == 1))
  4733.             {
  4734.                 config_status("%s:%i: illegal allow::class, unknown class '%s' using default of class 'default'",
  4735.                     cep->ce_fileptr->cf_filename,
  4736.                     cep->ce_varlinenum,
  4737.                     cep->ce_vardata);
  4738.                     allow->class = default_class;
  4739.             }
  4740.         }
  4741.         else if (!strcmp(cep->ce_varname, "maxperip"))
  4742.             allow->maxperip = atoi(cep->ce_vardata);
  4743.         else if (!strcmp(cep->ce_varname, "redirect-server"))
  4744.             allow->server = strdup(cep->ce_vardata);
  4745.         else if (!strcmp(cep->ce_varname, "redirect-port"))
  4746.             allow->port = atoi(cep->ce_vardata);
  4747.         else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
  4748.         {
  4749.             /*
  4750.              * If this item isn't set explicitly by the
  4751.              * user, the value will temporarily be
  4752.              * zero. Defaults are applied in config_run().
  4753.              */
  4754.             allow->ipv6_clone_mask = atoi(cep->ce_vardata);
  4755.         }
  4756.         else if (!strcmp(cep->ce_varname, "options"))
  4757.         {
  4758.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  4759.             {
  4760.                 if (!strcmp(cepp->ce_varname, "noident"))
  4761.                     allow->flags.noident = 1;
  4762.                 else if (!strcmp(cepp->ce_varname, "useip"))
  4763.                     allow->flags.useip = 1;
  4764.                 else if (!strcmp(cepp->ce_varname, "ssl"))
  4765.                     allow->flags.ssl = 1;
  4766.                 else if (!strcmp(cepp->ce_varname, "nopasscont"))
  4767.                     allow->flags.nopasscont = 1;
  4768.             }
  4769.         }
  4770.     }
  4771.  
  4772.     if (!allow->hostname)
  4773.         allow->hostname = strdup("*@NOMATCH");
  4774.  
  4775.     if (!allow->ip)
  4776.         allow->ip = strdup("*@NOMATCH");
  4777.  
  4778.     AddListItem(allow, conf_allow);
  4779.     return 1;
  4780. }
  4781.  
  4782. int _test_allow(ConfigFile *conf, ConfigEntry *ce)
  4783. {
  4784.     ConfigEntry *cep, *cepp;
  4785.     int     errors = 0;
  4786.     Hook *h;
  4787.     char has_ip = 0, has_hostname = 0, has_maxperip = 0, has_password = 0, has_class = 0;
  4788.     char has_redirectserver = 0, has_redirectport = 0, has_options = 0;
  4789.     int hostname_possible_silliness = 0;
  4790.  
  4791.     if (ce->ce_vardata)
  4792.     {
  4793.         if (!strcmp(ce->ce_vardata, "channel"))
  4794.             return (_test_allow_channel(conf, ce));
  4795.         else if (!strcmp(ce->ce_vardata, "dcc"))
  4796.             return (_test_allow_dcc(conf, ce));
  4797.         else
  4798.         {
  4799.             int used = 0;
  4800.             for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  4801.             {
  4802.                 int value, errs = 0;
  4803.                 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  4804.                     && !(h->owner->options & MOD_OPT_PERM))
  4805.                     continue;
  4806.                 value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW,&errs);
  4807.                 if (value == 2)
  4808.                     used = 1;
  4809.                 if (value == 1)
  4810.                 {
  4811.                     used = 1;
  4812.                     break;
  4813.                 }
  4814.                 if (value == -1)
  4815.                 {
  4816.                     used = 1;
  4817.                     errors += errs;
  4818.                     break;
  4819.                 }
  4820.                 if (value == -2)
  4821.                 {
  4822.                     used = 1;
  4823.                     errors += errs;
  4824.                 }
  4825.             }
  4826.             if (!used) {
  4827.                 config_error("%s:%i: allow item with unknown type",
  4828.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4829.                 return 1;
  4830.             }
  4831.             return errors;
  4832.         }
  4833.     }
  4834.  
  4835.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  4836.     {
  4837.         if (strcmp(cep->ce_varname, "options") && config_is_blankorempty(cep, "allow"))
  4838.         {
  4839.             errors++;
  4840.             continue;
  4841.         }
  4842.         if (!strcmp(cep->ce_varname, "ip"))
  4843.         {
  4844.             if (has_ip)
  4845.             {
  4846.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4847.                     cep->ce_varlinenum, "allow::ip");
  4848.                 continue;
  4849.             }
  4850.             has_ip = 1;
  4851.         }
  4852.         else if (!strcmp(cep->ce_varname, "maxperip"))
  4853.         {
  4854.             int v = atoi(cep->ce_vardata);
  4855.             if (has_maxperip)
  4856.             {
  4857.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4858.                     cep->ce_varlinenum, "allow::maxperip");
  4859.                 continue;
  4860.             }
  4861.             has_maxperip = 1;
  4862.             if ((v <= 0) || (v > 65535))
  4863.             {
  4864.                 config_error("%s:%i: allow::maxperip with illegal value (must be 1-65535)",
  4865.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4866.                 errors++;
  4867.             }
  4868.         }
  4869.         else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
  4870.         {
  4871.             /* keep this in sync with _test_set() */
  4872.             int ipv6mask;
  4873.             ipv6mask = atoi(cep->ce_vardata);
  4874.             if (ipv6mask == 0)
  4875.             {
  4876.                 config_error("%s:%d: allow::ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
  4877.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4878.                 errors++;
  4879.             }
  4880.             if (ipv6mask > 128)
  4881.             {
  4882.                 config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
  4883.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4884.                          ipv6mask);
  4885.                 errors++;
  4886.             }
  4887.             if (ipv6mask <= 32)
  4888.             {
  4889.                 config_warn("%s:%d: allow::ipv6-clone-mask was given a very small value.",
  4890.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  4891.             }
  4892.         }
  4893.         else if (!strcmp(cep->ce_varname, "hostname"))
  4894.         {
  4895.             if (has_hostname)
  4896.             {
  4897.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4898.                     cep->ce_varlinenum, "allow::hostname");
  4899.                 continue;
  4900.             }
  4901.             has_hostname = 1;
  4902.             if (!strcmp(cep->ce_vardata, "*@*") || !strcmp(cep->ce_vardata, "*"))
  4903.                 hostname_possible_silliness = 1;
  4904.         }
  4905.         else if (!strcmp(cep->ce_varname, "password"))
  4906.         {
  4907.             if (has_password)
  4908.             {
  4909.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4910.                     cep->ce_varlinenum, "allow::password");
  4911.                 continue;
  4912.             }
  4913.             has_password = 1;
  4914.             /* some auth check stuff? */
  4915.             if (Auth_CheckError(cep) < 0)
  4916.                 errors++;
  4917.         }
  4918.         else if (!strcmp(cep->ce_varname, "class"))
  4919.         {
  4920.             if (has_class)
  4921.             {
  4922.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4923.                     cep->ce_varlinenum, "allow::class");
  4924.                 continue;
  4925.             }
  4926.             has_class = 1;
  4927.         }
  4928.         else if (!strcmp(cep->ce_varname, "redirect-server"))
  4929.         {
  4930.             if (has_redirectserver)
  4931.             {
  4932.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4933.                     cep->ce_varlinenum, "allow::redirect-server");
  4934.                 continue;
  4935.             }
  4936.             has_redirectserver = 1;
  4937.         }
  4938.         else if (!strcmp(cep->ce_varname, "redirect-port"))
  4939.         {
  4940.             if (has_redirectport)
  4941.             {
  4942.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4943.                     cep->ce_varlinenum, "allow::redirect-port");
  4944.                 continue;
  4945.             }
  4946.             has_redirectport = 1;
  4947.         }
  4948.         else if (!strcmp(cep->ce_varname, "options"))
  4949.         {
  4950.             if (has_options)
  4951.             {
  4952.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  4953.                     cep->ce_varlinenum, "allow::options");
  4954.                 continue;
  4955.             }
  4956.             has_options = 1;
  4957.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  4958.             {
  4959.                 if (!strcmp(cepp->ce_varname, "noident"))
  4960.                 {}
  4961.                 else if (!strcmp(cepp->ce_varname, "useip"))
  4962.                 {}
  4963.                 else if (!strcmp(cepp->ce_varname, "ssl"))
  4964.                 {}
  4965.                 else if (!strcmp(cepp->ce_varname, "nopasscont"))
  4966.                 {}
  4967.                 else
  4968.                 {
  4969.                     config_error_unknownopt(cepp->ce_fileptr->cf_filename,
  4970.                         cepp->ce_varlinenum, "allow", cepp->ce_varname);
  4971.                     errors++;
  4972.                 }
  4973.             }
  4974.         }
  4975.         else
  4976.         {
  4977.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  4978.                 "allow", cep->ce_varname);
  4979.             errors++;
  4980.             continue;
  4981.         }
  4982.     }
  4983.  
  4984.     if (!has_ip && !has_hostname)
  4985.     {
  4986.         config_error("%s:%d: allow block needs an allow::ip or allow::hostname",
  4987.                  ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4988.         errors++;
  4989.     }
  4990.  
  4991.     if (has_ip && has_hostname)
  4992.     {
  4993.         config_warn("%s:%d: allow block has both allow::ip and allow::hostname which is no longer permitted.",
  4994.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  4995.         need_34_upgrade = 1;
  4996.     } else
  4997.     if (hostname_possible_silliness)
  4998.     {
  4999.         config_warn("%s:%d: allow block contains 'hostname *;'. This means means that users "
  5000.                     "without a valid hostname (unresolved IP's) will be unable to connect. "
  5001.                     "You most likely want to use 'ip *;' instead.",
  5002.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  5003.     }
  5004.  
  5005.     if (!has_class)
  5006.     {
  5007.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5008.             "allow::class");
  5009.         errors++;
  5010.     }
  5011.  
  5012.     if (!has_maxperip)
  5013.     {
  5014.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5015.             "allow::maxperip");
  5016.         errors++;
  5017.     }
  5018.     return errors;
  5019. }
  5020.  
  5021. int _conf_allow_channel(ConfigFile *conf, ConfigEntry *ce)
  5022. {
  5023.     ConfigItem_allow_channel    *allow = NULL;
  5024.     ConfigEntry             *cep;
  5025.     char *class = NULL;
  5026.  
  5027.     /* First, search for ::class, if any */
  5028.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5029.     {
  5030.         if (!strcmp(cep->ce_varname, "class"))
  5031.             class = cep->ce_vardata;
  5032.     }
  5033.  
  5034.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5035.     {
  5036.         if (!strcmp(cep->ce_varname, "channel"))
  5037.         {
  5038.             /* This way, we permit multiple ::channel items in one allow block */
  5039.             allow = MyMallocEx(sizeof(ConfigItem_allow_channel));
  5040.             safestrdup(allow->channel, cep->ce_vardata);
  5041.             if (class)
  5042.                 safestrdup(allow->class, class);
  5043.             AddListItem(allow, conf_allow_channel);
  5044.         }
  5045.     }
  5046.     return 1;
  5047. }
  5048.  
  5049. int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
  5050. {
  5051.     ConfigEntry     *cep;
  5052.     int         errors = 0;
  5053.     char            has_channel = 0, has_class = 0;
  5054.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5055.     {
  5056.         if (config_is_blankorempty(cep, "allow channel"))
  5057.         {
  5058.             errors++;
  5059.             continue;
  5060.         }
  5061.  
  5062.         if (!strcmp(cep->ce_varname, "channel"))
  5063.         {
  5064.             has_channel = 1;
  5065.         }
  5066.         else if (!strcmp(cep->ce_varname, "class"))
  5067.         {
  5068.  
  5069.             if (has_class)
  5070.             {
  5071.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5072.                     cep->ce_varlinenum, "allow channel::class");
  5073.                 continue;
  5074.             }
  5075.             has_class = 1;
  5076.         }
  5077.         else
  5078.         {
  5079.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5080.                 "allow channel", cep->ce_varname);
  5081.             errors++;
  5082.         }
  5083.     }
  5084.     if (!has_channel)
  5085.     {
  5086.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5087.             "allow channel::channel");
  5088.         errors++;
  5089.     }
  5090.     return errors;
  5091. }
  5092.  
  5093. int _conf_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
  5094. {
  5095.     ConfigItem_allow_dcc *allow = NULL;
  5096.     ConfigEntry *cep;
  5097.  
  5098.     allow = MyMallocEx(sizeof(ConfigItem_allow_dcc));
  5099.  
  5100.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5101.     {
  5102.         if (!strcmp(cep->ce_varname, "filename"))
  5103.             safestrdup(allow->filename, cep->ce_vardata);
  5104.         else if (!strcmp(cep->ce_varname, "soft"))
  5105.         {
  5106.             int x = config_checkval(cep->ce_vardata,CFG_YESNO);
  5107.             if (x)
  5108.                 allow->flag.type = DCCDENY_SOFT;
  5109.         }
  5110.     }
  5111.     AddListItem(allow, conf_allow_dcc);
  5112.     return 1;
  5113. }
  5114.  
  5115. int _test_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
  5116. {
  5117.     ConfigEntry *cep;
  5118.     int errors = 0, has_filename = 0, has_soft = 0;
  5119.  
  5120.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5121.     {
  5122.         if (config_is_blankorempty(cep, "allow dcc"))
  5123.         {
  5124.             errors++;
  5125.             continue;
  5126.         }
  5127.         if (!strcmp(cep->ce_varname, "filename"))
  5128.         {
  5129.             if (has_filename)
  5130.             {
  5131.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5132.                     cep->ce_varlinenum, "allow dcc::filename");
  5133.                 continue;
  5134.             }
  5135.             has_filename = 1;
  5136.         }
  5137.         else if (!strcmp(cep->ce_varname, "soft"))
  5138.         {
  5139.             if (has_soft)
  5140.             {
  5141.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5142.                     cep->ce_varlinenum, "allow dcc::soft");
  5143.                 continue;
  5144.             }
  5145.             has_soft = 1;
  5146.         }
  5147.         else
  5148.         {
  5149.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5150.                 "allow dcc", cep->ce_varname);
  5151.             errors++;
  5152.         }
  5153.     }
  5154.     if (!has_filename)
  5155.     {
  5156.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5157.             "allow dcc::filename");
  5158.         errors++;
  5159.     }
  5160.     return errors;
  5161. }
  5162.  
  5163. void create_tkl_except_ii(char *mask, char *type)
  5164. {
  5165.     ConfigItem_except *ca;
  5166.     NameValue *opf;
  5167.     ca = MyMallocEx(sizeof(ConfigItem_except));
  5168.     ca->mask = strdup(mask);
  5169.  
  5170.     opf = config_binary_flags_search(ExceptTklFlags, type, ARRAY_SIZEOF(ExceptTklFlags));
  5171.     ca->type = opf->flag;
  5172.     ca->flag.type = CONF_EXCEPT_TKL;
  5173.     AddListItem(ca, conf_except);
  5174. }
  5175.  
  5176. void create_tkl_except(char *mask, char *type)
  5177. {
  5178.     if (!strcmp(type, "all"))
  5179.     {
  5180.         /* Special treatment */
  5181.         int i;
  5182.         for (i = 0; i < ARRAY_SIZEOF(ExceptTklFlags); i++)
  5183.             if (ExceptTklFlags[i].flag)
  5184.                 create_tkl_except_ii(mask, ExceptTklFlags[i].name);
  5185.     }
  5186.     else
  5187.         create_tkl_except_ii(mask, type);
  5188. }
  5189.  
  5190. int     _conf_except(ConfigFile *conf, ConfigEntry *ce)
  5191. {
  5192.  
  5193.     ConfigEntry *cep;
  5194.     ConfigItem_except *ca;
  5195.     Hook *h;
  5196.  
  5197.     if (!strcmp(ce->ce_vardata, "ban")) {
  5198.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5199.         {
  5200.             if (!strcmp(cep->ce_varname, "mask")) {
  5201.                 ca = MyMallocEx(sizeof(ConfigItem_except));
  5202.                 ca->mask = strdup(cep->ce_vardata);
  5203.                 ca->flag.type = CONF_EXCEPT_BAN;
  5204.                 AddListItem(ca, conf_except);
  5205.             }
  5206.             else {
  5207.             }
  5208.         }
  5209.     }
  5210.     else if (!strcmp(ce->ce_vardata, "throttle")) {
  5211.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5212.         {
  5213.             if (!strcmp(cep->ce_varname, "mask")) {
  5214.                 ca = MyMallocEx(sizeof(ConfigItem_except));
  5215.                 ca->mask = strdup(cep->ce_vardata);
  5216.                 ca->flag.type = CONF_EXCEPT_THROTTLE;
  5217.                 AddListItem(ca, conf_except);
  5218.             }
  5219.             else {
  5220.             }
  5221.         }
  5222.  
  5223.     }
  5224.     else if (!strcmp(ce->ce_vardata, "tkl")) {
  5225.         ConfigEntry *mask = NULL, *type = NULL;
  5226.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5227.         {
  5228.             if (!strcmp(cep->ce_varname, "mask"))
  5229.                 mask = cep;
  5230.             else if (!strcmp(cep->ce_varname, "type"))
  5231.                 type = cep;
  5232.         }
  5233.         if (type->ce_vardata)
  5234.             create_tkl_except(mask->ce_vardata, type->ce_vardata);
  5235.         else
  5236.         {
  5237.             ConfigEntry *cepp;
  5238.             for (cepp = type->ce_entries; cepp; cepp = cepp->ce_next)
  5239.                 create_tkl_except(mask->ce_vardata, cepp->ce_varname);
  5240.         }
  5241.     }
  5242.     else {
  5243.         int value;
  5244.         for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  5245.         {
  5246.             value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT);
  5247.             if (value == 1)
  5248.                 break;
  5249.         }
  5250.     }
  5251.     return 1;
  5252. }
  5253.  
  5254. int     _test_except(ConfigFile *conf, ConfigEntry *ce)
  5255. {
  5256.     ConfigEntry *cep;
  5257.     int     errors = 0;
  5258.     Hook *h;
  5259.     char has_mask = 0;
  5260.  
  5261.     if (!ce->ce_vardata)
  5262.     {
  5263.         config_error("%s:%i: except without type",
  5264.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  5265.         return 1;
  5266.     }
  5267.  
  5268.     if (!strcmp(ce->ce_vardata, "ban"))
  5269.     {
  5270.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5271.         {
  5272.             if (config_is_blankorempty(cep, "except ban"))
  5273.             {
  5274.                 errors++;
  5275.                 continue;
  5276.             }
  5277.             if (!strcmp(cep->ce_varname, "mask"))
  5278.             {
  5279.                 if (has_mask)
  5280.                 {
  5281.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5282.                         cep->ce_varlinenum, "except ban::mask");
  5283.                     continue;
  5284.                 }
  5285.                 has_mask = 1;
  5286.             }
  5287.             else
  5288.             {
  5289.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  5290.                     cep->ce_varlinenum, "except ban", cep->ce_varname);
  5291.                 errors++;
  5292.                 continue;
  5293.             }
  5294.         }
  5295.         if (!has_mask)
  5296.         {
  5297.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5298.                 "except ban::mask");
  5299.             errors++;
  5300.         }
  5301.         return errors;
  5302.     }
  5303.     else if (!strcmp(ce->ce_vardata, "throttle")) {
  5304.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5305.         {
  5306.             if (config_is_blankorempty(cep, "except throttle"))
  5307.             {
  5308.                 errors++;
  5309.                 continue;
  5310.             }
  5311.             if (!strcmp(cep->ce_varname, "mask"))
  5312.             {
  5313.                 has_mask = 1;
  5314.             }
  5315.             else
  5316.             {
  5317.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  5318.                     cep->ce_varlinenum, "except throttle", cep->ce_varname);
  5319.                 errors++;
  5320.                 continue;
  5321.             }
  5322.         }
  5323.         if (!has_mask)
  5324.         {
  5325.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5326.                 "except throttle::mask");
  5327.             errors++;
  5328.         }
  5329.         return errors;
  5330.     }
  5331.     else if (!strcmp(ce->ce_vardata, "tkl")) {
  5332.         char has_type = 0;
  5333.  
  5334.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5335.         {
  5336.             if (!cep->ce_varname)
  5337.             {
  5338.                 config_error_blank(cep->ce_fileptr->cf_filename,
  5339.                     cep->ce_varlinenum, "except tkl");
  5340.                 errors++;
  5341.                 continue;
  5342.             }
  5343.             if (!strcmp(cep->ce_varname, "mask"))
  5344.             {
  5345.                 if (!cep->ce_vardata)
  5346.                 {
  5347.                     config_error_empty(cep->ce_fileptr->cf_filename,
  5348.                         cep->ce_varlinenum, "except tkl", "mask");
  5349.                     errors++;
  5350.                     continue;
  5351.                 }
  5352.                 if (has_mask)
  5353.                 {
  5354.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5355.                         cep->ce_varlinenum, "except tkl::mask");
  5356.                     continue;
  5357.                 }
  5358.                 has_mask = 1;
  5359.             }
  5360.             else if (!strcmp(cep->ce_varname, "type"))
  5361.             {
  5362.                 if (has_type)
  5363.                 {
  5364.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5365.                         cep->ce_varlinenum, "except tkl::type");
  5366.                     continue;
  5367.                 }
  5368.                 if (cep->ce_vardata)
  5369.                 {
  5370.                     if (!strcmp(cep->ce_vardata, "tkline") ||
  5371.                         !strcmp(cep->ce_vardata, "tzline"))
  5372.                     {
  5373.                         config_error("%s:%i: except tkl of type %s is"
  5374.                                  " deprecated. Use except ban {}"
  5375.                                  " instead",
  5376.                                  cep->ce_fileptr->cf_filename,
  5377.                                  cep->ce_varlinenum,
  5378.                                  cep->ce_vardata);
  5379.                         errors++;
  5380.                     }
  5381.                     if (!config_binary_flags_search(ExceptTklFlags,
  5382.                          cep->ce_vardata, ARRAY_SIZEOF(ExceptTklFlags)))
  5383.                     {
  5384.                         config_error("%s:%i: unknown except tkl type %s",
  5385.                                  cep->ce_fileptr->cf_filename,
  5386.                                  cep->ce_varlinenum,
  5387.                                  cep->ce_vardata);
  5388.                         return 1;
  5389.                     }
  5390.                 }
  5391.                 else if (cep->ce_entries)
  5392.                 {
  5393.                     ConfigEntry *cepp;
  5394.                     for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  5395.                     {
  5396.                         if (!strcmp(cepp->ce_varname, "tkline") ||
  5397.                             !strcmp(cepp->ce_varname, "tzline"))
  5398.                         {
  5399.                             config_error("%s:%i: except tkl of type %s is"
  5400.                                      " deprecated. Use except ban {}"
  5401.                                      " instead",
  5402.                                      cepp->ce_fileptr->cf_filename,
  5403.                                      cepp->ce_varlinenum,
  5404.                                      cepp->ce_varname);
  5405.                             errors++;
  5406.                         }
  5407.                         if (!config_binary_flags_search(ExceptTklFlags,
  5408.                              cepp->ce_varname, ARRAY_SIZEOF(ExceptTklFlags)))
  5409.                         {
  5410.                             config_error("%s:%i: unknown except tkl type %s",
  5411.                                      cepp->ce_fileptr->cf_filename,
  5412.                                      cepp->ce_varlinenum,
  5413.                                      cepp->ce_varname);
  5414.                             return 1;
  5415.                         }
  5416.                     }
  5417.                 }
  5418.                 else
  5419.                 {
  5420.                     config_error_empty(cep->ce_fileptr->cf_filename,
  5421.                         cep->ce_varlinenum, "except tkl", "type");
  5422.                     errors++;
  5423.                     continue;
  5424.                 }
  5425.                 has_type = 1;
  5426.             }
  5427.             else
  5428.             {
  5429.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  5430.                     cep->ce_varlinenum, "except tkl", cep->ce_varname);
  5431.                 errors++;
  5432.                 continue;
  5433.             }
  5434.         }
  5435.         if (!has_mask)
  5436.         {
  5437.             config_error("%s:%i: except tkl without mask item",
  5438.                 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  5439.             return 1;
  5440.         }
  5441.         if (!has_type)
  5442.         {
  5443.             config_error("%s:%i: except tkl without type item",
  5444.                 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  5445.             return 1;
  5446.         }
  5447.         return errors;
  5448.     }
  5449.     else {
  5450.         int used = 0;
  5451.         for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  5452.         {
  5453.             int value, errs = 0;
  5454.             if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  5455.                 && !(h->owner->options & MOD_OPT_PERM))
  5456.                 continue;
  5457.             value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT,&errs);
  5458.             if (value == 2)
  5459.                 used = 1;
  5460.             if (value == 1)
  5461.             {
  5462.                 used = 1;
  5463.                 break;
  5464.             }
  5465.             if (value == -1)
  5466.             {
  5467.                 used = 1;
  5468.                 errors += errs;
  5469.                 break;
  5470.             }
  5471.             if (value == -2)
  5472.             {
  5473.                 used = 1;
  5474.                 errors += errs;
  5475.             }
  5476.         }
  5477.         if (!used) {
  5478.             config_error("%s:%i: unknown except type %s",
  5479.                 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5480.                 ce->ce_vardata);
  5481.             return 1;
  5482.         }
  5483.     }
  5484.     return errors;
  5485. }
  5486.  
  5487. /*
  5488.  * vhost {} block parser
  5489. */
  5490. int _conf_vhost(ConfigFile *conf, ConfigEntry *ce)
  5491. {
  5492.     ConfigItem_vhost *vhost;
  5493.     ConfigItem_mask *mask;
  5494.     ConfigEntry *cep, *cepp;
  5495.     vhost = MyMallocEx(sizeof(ConfigItem_vhost));
  5496.  
  5497.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5498.     {
  5499.         if (!strcmp(cep->ce_varname, "vhost"))
  5500.         {
  5501.             char *user, *host;
  5502.             user = strtok(cep->ce_vardata, "@");
  5503.             host = strtok(NULL, "");
  5504.             if (!host)
  5505.                 vhost->virthost = strdup(user);
  5506.             else
  5507.             {
  5508.                 vhost->virtuser = strdup(user);
  5509.                 vhost->virthost = strdup(host);
  5510.             }
  5511.         }
  5512.         else if (!strcmp(cep->ce_varname, "login"))
  5513.             vhost->login = strdup(cep->ce_vardata);
  5514.         else if (!strcmp(cep->ce_varname, "password"))
  5515.             vhost->auth = Auth_ConvertConf2AuthStruct(cep);
  5516.         else if (!strcmp(cep->ce_varname, "mask"))
  5517.         {
  5518.             unreal_add_masks(&vhost->mask, cep);
  5519.         }
  5520.         else if (!strcmp(cep->ce_varname, "swhois"))
  5521.         {
  5522.             SWhois *s;
  5523.             if (cep->ce_entries)
  5524.             {
  5525.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  5526.                 {
  5527.                     s = MyMallocEx(sizeof(SWhois));
  5528.                     s->line = strdup(cepp->ce_varname);
  5529.                     s->setby = strdup("vhost");
  5530.                     AddListItem(s, vhost->swhois);
  5531.                 }
  5532.             } else
  5533.             if (cep->ce_vardata)
  5534.             {
  5535.                 s = MyMallocEx(sizeof(SWhois));
  5536.                 s->line = strdup(cep->ce_vardata);
  5537.                 s->setby = strdup("vhost");
  5538.                 AddListItem(s, vhost->swhois);
  5539.             }
  5540.         }
  5541.     }
  5542.     AddListItem(vhost, conf_vhost);
  5543.     return 1;
  5544. }
  5545.  
  5546. int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
  5547. {
  5548.     int errors = 0;
  5549.     ConfigEntry *cep;
  5550.     char has_vhost = 0, has_login = 0, has_password = 0, has_swhois = 0, has_mask = 0;
  5551.  
  5552.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5553.     {
  5554.         if (!cep->ce_varname)
  5555.         {
  5556.             config_error_blank(cep->ce_fileptr->cf_filename,
  5557.                 cep->ce_varlinenum, "vhost");
  5558.             errors++;
  5559.             continue;
  5560.         }
  5561.         if (!strcmp(cep->ce_varname, "vhost"))
  5562.         {
  5563.             char *at, *tmp, *host;
  5564.             if (has_vhost)
  5565.             {
  5566.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5567.                     cep->ce_varlinenum, "vhost::vhost");
  5568.                 continue;
  5569.             }
  5570.             has_vhost = 1;
  5571.             if (!cep->ce_vardata)
  5572.             {
  5573.                 config_error_empty(cep->ce_fileptr->cf_filename,
  5574.                     cep->ce_varlinenum, "vhost", "vhost");
  5575.                 errors++;
  5576.                 continue;
  5577.             }
  5578.             if ((at = strchr(cep->ce_vardata, '@')))
  5579.             {
  5580.                 for (tmp = cep->ce_vardata; tmp != at; tmp++)
  5581.                 {
  5582.                     if (*tmp == '~' && tmp == cep->ce_vardata)
  5583.                         continue;
  5584.                     if (!isallowed(*tmp))
  5585.                         break;
  5586.                 }
  5587.                 if (tmp != at)
  5588.                 {
  5589.                     config_error("%s:%i: vhost::vhost contains an invalid ident",
  5590.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  5591.                     errors++;
  5592.                 }
  5593.                 host = at+1;
  5594.             }
  5595.             else
  5596.                 host = cep->ce_vardata;
  5597.             if (!*host)
  5598.             {
  5599.                 config_error("%s:%i: vhost::vhost does not have a host set",
  5600.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  5601.                 errors++;
  5602.             }
  5603.             else
  5604.             {
  5605.                 if (!valid_host(host))
  5606.                 {
  5607.                     config_error("%s:%i: vhost::vhost contains an invalid host",
  5608.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  5609.                     errors++;
  5610.                 }
  5611.             }
  5612.         }
  5613.         else if (!strcmp(cep->ce_varname, "login"))
  5614.         {
  5615.             if (has_login)
  5616.             {
  5617.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5618.                     cep->ce_varlinenum, "vhost::login");
  5619.             }
  5620.             has_login = 1;
  5621.             if (!cep->ce_vardata)
  5622.             {
  5623.                 config_error_empty(cep->ce_fileptr->cf_filename,
  5624.                     cep->ce_varlinenum, "vhost", "login");
  5625.                 errors++;
  5626.                 continue;
  5627.             }
  5628.         }
  5629.         else if (!strcmp(cep->ce_varname, "password"))
  5630.         {
  5631.             if (has_password)
  5632.             {
  5633.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5634.                     cep->ce_varlinenum, "vhost::password");
  5635.             }
  5636.             has_password = 1;
  5637.             if (!cep->ce_vardata)
  5638.             {
  5639.                 config_error_empty(cep->ce_fileptr->cf_filename,
  5640.                     cep->ce_varlinenum, "vhost", "password");
  5641.                 errors++;
  5642.                 continue;
  5643.             }
  5644.             if (Auth_CheckError(cep) < 0)
  5645.                 errors++;
  5646.         }
  5647.         else if (!strcmp(cep->ce_varname, "from"))
  5648.         {
  5649.             ConfigEntry *cepp;
  5650.  
  5651.             config_error("%s:%i: vhost::from::userhost is now called oper::mask",
  5652.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  5653.             errors++;
  5654.             need_34_upgrade = 1;
  5655.             continue;
  5656.         }
  5657.         else if (!strcmp(cep->ce_varname, "mask"))
  5658.         {
  5659.             has_mask = 1;
  5660.         }
  5661.         else if (!strcmp(cep->ce_varname, "swhois"))
  5662.         {
  5663.             /* multiple is ok */
  5664.         }
  5665.         else
  5666.         {
  5667.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5668.                 "vhost", cep->ce_varname);
  5669.             errors++;
  5670.         }
  5671.     }
  5672.     if (!has_vhost)
  5673.     {
  5674.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5675.             "vhost::vhost");
  5676.         errors++;
  5677.     }
  5678.     if (!has_login)
  5679.     {
  5680.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5681.             "vhost::login");
  5682.         errors++;
  5683.  
  5684.     }
  5685.     if (!has_password)
  5686.     {
  5687.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5688.             "vhost::password");
  5689.         errors++;
  5690.     }
  5691.     if (!has_mask)
  5692.     {
  5693.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5694.             "vhost::mask");
  5695.         errors++;
  5696.     }
  5697.     // TODO: 3.2.x -> 4.x upgrading hints
  5698.     return errors;
  5699. }
  5700.  
  5701. int _conf_spamfilter(ConfigFile *conf, ConfigEntry *ce)
  5702. {
  5703.     ConfigEntry *cep;
  5704.     ConfigEntry *cepp;
  5705.     aTKline *nl = MyMallocEx(sizeof(aTKline));
  5706.     char *word = NULL, *reason = NULL, *bantime = NULL;
  5707.     int action = 0, target = 0;
  5708.     char has_reason = 0, has_bantime = 0;
  5709.     int match_type = 0;
  5710.  
  5711.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5712.     {
  5713.         if (!strcmp(cep->ce_varname, "match"))
  5714.         {
  5715.             nl->reason = strdup(cep->ce_vardata);
  5716.  
  5717.             word = cep->ce_vardata;
  5718.         }
  5719.         else if (!strcmp(cep->ce_varname, "target"))
  5720.         {
  5721.             if (cep->ce_vardata)
  5722.                 target = spamfilter_getconftargets(cep->ce_vardata);
  5723.             else
  5724.             {
  5725.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  5726.                     target |= spamfilter_getconftargets(cepp->ce_varname);
  5727.             }
  5728.         }
  5729.         else if (!strcmp(cep->ce_varname, "action"))
  5730.         {
  5731.             action = banact_stringtoval(cep->ce_vardata);
  5732.             nl->hostmask = strdup(cep->ce_vardata);
  5733.         }
  5734.         else if (!strcmp(cep->ce_varname, "reason"))
  5735.         {
  5736.             has_reason = 1;
  5737.             reason = cep->ce_vardata;
  5738.         }
  5739.         else if (!strcmp(cep->ce_varname, "ban-time"))
  5740.         {
  5741.             has_bantime = 1;
  5742.             bantime = cep->ce_vardata;
  5743.         }
  5744.         else if (!strcmp(cep->ce_varname, "match-type"))
  5745.         {
  5746.             match_type = unreal_match_method_strtoval(cep->ce_vardata);
  5747.         }
  5748.     }
  5749.     nl->type = TKL_SPAMF;
  5750.     nl->expire_at = 0;
  5751.     nl->set_at = TStime();
  5752.  
  5753.     strlcpy(nl->usermask, spamfilter_target_inttostring(target), sizeof(nl->usermask));
  5754.     nl->subtype = target;
  5755.  
  5756.     nl->setby = BadPtr(me.name) ? NULL : strdup(me.name); /* Hmm! */
  5757.     nl->ptr.spamf = MyMallocEx(sizeof(Spamfilter));
  5758.     nl->ptr.spamf->expr = unreal_create_match(match_type, word, NULL);
  5759.     nl->ptr.spamf->action = action;
  5760.  
  5761.     if (has_reason && reason)
  5762.         nl->ptr.spamf->tkl_reason = strdup(unreal_encodespace(reason));
  5763.     else
  5764.         nl->ptr.spamf->tkl_reason = strdup("<internally added by ircd>");
  5765.  
  5766.     if (has_bantime)
  5767.         nl->ptr.spamf->tkl_duration = config_checkval(bantime, CFG_TIME);
  5768.     else
  5769.         nl->ptr.spamf->tkl_duration = (SPAMFILTER_BAN_TIME ? SPAMFILTER_BAN_TIME : 86400);
  5770.  
  5771.     AddListItem(nl, tklines[tkl_hash('f')]);
  5772.     return 1;
  5773. }
  5774.  
  5775. int _test_spamfilter(ConfigFile *conf, ConfigEntry *ce)
  5776. {
  5777.     ConfigEntry *cep, *cepp;
  5778.     int errors = 0;
  5779.     char *match = NULL, *reason = NULL;
  5780.     char has_target = 0, has_match = 0, has_action = 0, has_reason = 0, has_bantime = 0, has_match_type = 0;
  5781.     int match_type = 0;
  5782.  
  5783.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5784.     {
  5785.         if (!cep->ce_varname)
  5786.         {
  5787.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5788.                 "spamfilter");
  5789.             errors++;
  5790.             continue;
  5791.         }
  5792.         if (!strcmp(cep->ce_varname, "target"))
  5793.         {
  5794.             if (has_target)
  5795.             {
  5796.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5797.                     cep->ce_varlinenum, "spamfilter::target");
  5798.                 continue;
  5799.             }
  5800.             has_target = 1;
  5801.             if (cep->ce_vardata)
  5802.             {
  5803.                 if (!spamfilter_getconftargets(cep->ce_vardata))
  5804.                 {
  5805.                     config_error("%s:%i: unknown spamfiler target type '%s'",
  5806.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
  5807.                     errors++;
  5808.                 }
  5809.             }
  5810.             else if (cep->ce_entries)
  5811.             {
  5812.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  5813.                 {
  5814.                     if (!cepp->ce_varname)
  5815.                     {
  5816.                         config_error_blank(cepp->ce_fileptr->cf_filename,
  5817.                             cepp->ce_varlinenum,
  5818.                             "spamfilter::target");
  5819.                         errors++;
  5820.                         continue;
  5821.                     }
  5822.                     if (!spamfilter_getconftargets(cepp->ce_varname))
  5823.                     {
  5824.                         config_error("%s:%i: unknown spamfiler target type '%s'",
  5825.                             cepp->ce_fileptr->cf_filename,
  5826.                             cepp->ce_varlinenum, cepp->ce_varname);
  5827.                         errors++;
  5828.                     }
  5829.                 }
  5830.             }
  5831.             else
  5832.             {
  5833.                 config_error_empty(cep->ce_fileptr->cf_filename,
  5834.                     cep->ce_varlinenum, "spamfilter", cep->ce_varname);
  5835.                 errors++;
  5836.             }
  5837.             continue;
  5838.         }
  5839.         if (!cep->ce_vardata)
  5840.         {
  5841.             config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5842.                 "spamfilter", cep->ce_varname);
  5843.             errors++;
  5844.             continue;
  5845.         }
  5846.         if (!strcmp(cep->ce_varname, "reason"))
  5847.         {
  5848.             if (has_reason)
  5849.             {
  5850.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5851.                     cep->ce_varlinenum, "spamfilter::reason");
  5852.                 continue;
  5853.             }
  5854.             has_reason = 1;
  5855.             reason = cep->ce_vardata;
  5856.         }
  5857.         else if (!strcmp(cep->ce_varname, "match"))
  5858.         {
  5859.             if (has_match)
  5860.             {
  5861.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5862.                     cep->ce_varlinenum, "spamfilter::match");
  5863.                 continue;
  5864.             }
  5865.             has_match = 1;
  5866.             match = cep->ce_vardata;
  5867.         }
  5868.         else if (!strcmp(cep->ce_varname, "action"))
  5869.         {
  5870.             if (has_action)
  5871.             {
  5872.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5873.                     cep->ce_varlinenum, "spamfilter::action");
  5874.                 continue;
  5875.             }
  5876.             has_action = 1;
  5877.             if (!banact_stringtoval(cep->ce_vardata))
  5878.             {
  5879.                 config_error("%s:%i: spamfilter::action has unknown action type '%s'",
  5880.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
  5881.                 errors++;
  5882.             }
  5883.         }
  5884.         else if (!strcmp(cep->ce_varname, "ban-time"))
  5885.         {
  5886.             if (has_bantime)
  5887.             {
  5888.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5889.                     cep->ce_varlinenum, "spamfilter::ban-time");
  5890.                 continue;
  5891.             }
  5892.             has_bantime = 1;
  5893.         }
  5894.         else if (!strcmp(cep->ce_varname, "match-type"))
  5895.         {
  5896.             if (has_match_type)
  5897.             {
  5898.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  5899.                     cep->ce_varlinenum, "spamfilter::match-type");
  5900.                 continue;
  5901.             }
  5902.             match_type = unreal_match_method_strtoval(cep->ce_vardata);
  5903.             if (match_type == 0)
  5904.             {
  5905.                 config_error("%s:%i: spamfilter::match-type: unknown match type '%s', "
  5906.                              "should be one of: 'simple', 'regex' or 'posix'",
  5907.                              cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5908.                              cep->ce_vardata);
  5909.                 errors++;
  5910.                 continue;
  5911.             }
  5912.             has_match_type = 1;
  5913.         }
  5914.         else
  5915.         {
  5916.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  5917.                 "spamfilter", cep->ce_varname);
  5918.             errors++;
  5919.             continue;
  5920.         }
  5921.     }
  5922.  
  5923.     if (match && match_type)
  5924.     {
  5925.         aMatch *m;
  5926.         char *err;
  5927.  
  5928.         m = unreal_create_match(match_type, match, &err);
  5929.         if (!m)
  5930.         {
  5931.             config_error("%s:%i: spamfilter::match contains an invalid regex: %s",
  5932.                 ce->ce_fileptr->cf_filename,
  5933.                 ce->ce_varlinenum,
  5934.                 err);
  5935.             errors++;
  5936.         } else
  5937.         {
  5938.             unreal_delete_match(m);
  5939.         }
  5940.     }
  5941.  
  5942.     if (!has_match)
  5943.     {
  5944.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5945.             "spamfilter::match");
  5946.         errors++;
  5947.     }
  5948.     if (!has_target)
  5949.     {
  5950.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5951.             "spamfilter::target");
  5952.         errors++;
  5953.     }
  5954.     if (!has_action)
  5955.     {
  5956.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5957.             "spamfilter::action");
  5958.         errors++;
  5959.     }
  5960.     if (match && reason && (strlen(match) + strlen(reason) > 505))
  5961.     {
  5962.         config_error("%s:%i: spamfilter block problem: match + reason field are together over 505 bytes, "
  5963.                      "please choose a shorter regex or reason",
  5964.                      ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  5965.         errors++;
  5966.     }
  5967.     if (!has_match_type)
  5968.     {
  5969.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  5970.             "spamfilter::match-type");
  5971.         errors++;
  5972.     }
  5973.  
  5974.     if (!has_match_type && !has_match && has_action && has_target)
  5975.     {
  5976.         need_34_upgrade = 1;
  5977.     }
  5978.  
  5979.     return errors;
  5980. }
  5981.  
  5982. int     _conf_help(ConfigFile *conf, ConfigEntry *ce)
  5983. {
  5984.     ConfigEntry *cep;
  5985.     ConfigItem_help *ca;
  5986.     aMotdLine *last = NULL, *temp;
  5987.     ca = MyMallocEx(sizeof(ConfigItem_help));
  5988.  
  5989.     if (!ce->ce_vardata)
  5990.         ca->command = NULL;
  5991.     else
  5992.         ca->command = strdup(ce->ce_vardata);
  5993.  
  5994.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  5995.     {
  5996.         temp = MyMallocEx(sizeof(aMotdLine));
  5997.         temp->line = strdup(cep->ce_varname);
  5998.         temp->next = NULL;
  5999.         if (!last)
  6000.             ca->text = temp;
  6001.         else
  6002.             last->next = temp;
  6003.         last = temp;
  6004.     }
  6005.     AddListItem(ca, conf_help);
  6006.     return 1;
  6007.  
  6008. }
  6009.  
  6010. int _test_help(ConfigFile *conf, ConfigEntry *ce) {
  6011.     int errors = 0;
  6012.     ConfigEntry *cep;
  6013.     if (!ce->ce_entries)
  6014.     {
  6015.         config_error("%s:%i: empty help block",
  6016.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6017.         return 1;
  6018.     }
  6019.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6020.     {
  6021.         if (!cep->ce_varname)
  6022.         {
  6023.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  6024.                 "help");
  6025.             errors++;
  6026.             continue;
  6027.         }
  6028.     }
  6029.     return errors;
  6030. }
  6031.  
  6032. int     _conf_log(ConfigFile *conf, ConfigEntry *ce)
  6033. {
  6034.     ConfigEntry *cep, *cepp;
  6035.     ConfigItem_log *ca;
  6036.     NameValue *ofp = NULL;
  6037.  
  6038.     ca = MyMallocEx(sizeof(ConfigItem_log));
  6039.     ca->logfd = -1;
  6040.     safestrdup(ca->file, ce->ce_vardata);
  6041.  
  6042.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6043.     {
  6044.         if (!strcmp(cep->ce_varname, "maxsize"))
  6045.         {
  6046.             ca->maxsize = config_checkval(cep->ce_vardata,CFG_SIZE);
  6047.         }
  6048.         else if (!strcmp(cep->ce_varname, "flags"))
  6049.         {
  6050.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6051.             {
  6052.                 if ((ofp = config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags))))
  6053.                     ca->flags |= ofp->flag;
  6054.             }
  6055.         }
  6056.     }
  6057.     AddListItem(ca, conf_log);
  6058.     return 1;
  6059.  
  6060. }
  6061.  
  6062. int _test_log(ConfigFile *conf, ConfigEntry *ce) {
  6063.     int fd, errors = 0;
  6064.     ConfigEntry *cep, *cepp;
  6065.     char has_flags = 0, has_maxsize = 0;
  6066.  
  6067.     if (!ce->ce_vardata)
  6068.     {
  6069.         config_error("%s:%i: log block without filename",
  6070.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6071.         return 1;
  6072.     }
  6073.     if (!ce->ce_entries)
  6074.     {
  6075.         config_error("%s:%i: empty log block",
  6076.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6077.         return 1;
  6078.     }
  6079.  
  6080.     /* Convert to absolute path (if needed) unless it's "syslog" */
  6081.     if (strcmp(ce->ce_vardata, "syslog"))
  6082.         convert_to_absolute_path(&ce->ce_vardata, LOGDIR);
  6083.  
  6084.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6085.     {
  6086.         if (!cep->ce_varname)
  6087.         {
  6088.             config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  6089.                 "log");
  6090.             errors++;
  6091.             continue;
  6092.         }
  6093.         if (!strcmp(cep->ce_varname, "flags"))
  6094.         {
  6095.             if (has_flags)
  6096.             {
  6097.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  6098.                     cep->ce_varlinenum, "log::flags");
  6099.                 continue;
  6100.             }
  6101.             has_flags = 1;
  6102.             if (!cep->ce_entries)
  6103.             {
  6104.                 config_error_empty(cep->ce_fileptr->cf_filename,
  6105.                     cep->ce_varlinenum, "log", cep->ce_varname);
  6106.                 errors++;
  6107.                 continue;
  6108.             }
  6109.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6110.             {
  6111.                 if (!cepp->ce_varname)
  6112.                 {
  6113.                     config_error_blank(cepp->ce_fileptr->cf_filename,
  6114.                         cepp->ce_varlinenum, "log::flags");
  6115.                     errors++;
  6116.                     continue;
  6117.                 }
  6118.                 if (!config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags)))
  6119.                 {
  6120.                     config_error_unknownflag(cepp->ce_fileptr->cf_filename,
  6121.                         cepp->ce_varlinenum, "log", cepp->ce_varname);
  6122.                     errors++;
  6123.                 }
  6124.             }
  6125.         }
  6126.         else if (!strcmp(cep->ce_varname, "maxsize"))
  6127.         {
  6128.             if (has_maxsize)
  6129.             {
  6130.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  6131.                     cep->ce_varlinenum, "log::maxsize");
  6132.                 continue;
  6133.             }
  6134.             has_maxsize = 1;
  6135.             if (!cep->ce_vardata)
  6136.             {
  6137.                 config_error_empty(cep->ce_fileptr->cf_filename,
  6138.                     cep->ce_varlinenum, "log", cep->ce_varname);
  6139.                 errors++;
  6140.             }
  6141.         }
  6142.         else
  6143.         {
  6144.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  6145.                 "log", cep->ce_varname);
  6146.             errors++;
  6147.             continue;
  6148.         }
  6149.     }
  6150.     if (!has_flags)
  6151.     {
  6152.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6153.             "log::flags");
  6154.         errors++;
  6155.     }
  6156.     if ((fd = fd_fileopen(ce->ce_vardata, O_WRONLY|O_CREAT)) == -1)
  6157.     {
  6158.         config_error("%s:%i: Couldn't open logfile (%s) for writing: %s",
  6159.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6160.             ce->ce_vardata, strerror(errno));
  6161.         errors++;
  6162.     }
  6163.     else
  6164.         fd_close(fd);
  6165.  
  6166.     return errors;
  6167. }
  6168.  
  6169. int _conf_link(ConfigFile *conf, ConfigEntry *ce)
  6170. {
  6171.     ConfigEntry *cep, *cepp, *ceppp;
  6172.     ConfigItem_link *link = NULL;
  6173.     NameValue *ofp;
  6174.  
  6175.     link = (ConfigItem_link *) MyMallocEx(sizeof(ConfigItem_link));
  6176.     link->servername = strdup(ce->ce_vardata);
  6177.  
  6178.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6179.     {
  6180.         if (!strcmp(cep->ce_varname, "incoming"))
  6181.         {
  6182.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6183.             {
  6184.                 if (!strcmp(cepp->ce_varname, "mask"))
  6185.                 {
  6186.                     unreal_add_masks(&link->incoming.mask, cepp);
  6187.                 }
  6188.             }
  6189.         }
  6190.         else if (!strcmp(cep->ce_varname, "outgoing"))
  6191.         {
  6192.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6193.             {
  6194.                 if (!strcmp(cepp->ce_varname, "bind-ip"))
  6195.                     safestrdup(link->outgoing.bind_ip, cepp->ce_vardata);
  6196.                 else if (!strcmp(cepp->ce_varname, "hostname"))
  6197.                     safestrdup(link->outgoing.hostname, cepp->ce_vardata);
  6198.                 else if (!strcmp(cepp->ce_varname, "port"))
  6199.                     link->outgoing.port = atoi(cepp->ce_vardata);
  6200.                 else if (!strcmp(cepp->ce_varname, "options"))
  6201.                 {
  6202.                     /* TODO: options still need to be split */
  6203.                     link->outgoing.options = 0;
  6204.                     for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
  6205.                     {
  6206.                         if ((ofp = config_binary_flags_search(_LinkFlags, ceppp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
  6207.                             link->outgoing.options |= ofp->flag;
  6208.                     }
  6209.                 }
  6210.             }
  6211.         }
  6212.         else if (!strcmp(cep->ce_varname, "password"))
  6213.             link->auth = Auth_ConvertConf2AuthStruct(cep);
  6214.         else if (!strcmp(cep->ce_varname, "hub"))
  6215.             safestrdup(link->hub, cep->ce_vardata);
  6216.         else if (!strcmp(cep->ce_varname, "leaf"))
  6217.             safestrdup(link->leaf, cep->ce_vardata);
  6218.         else if (!strcmp(cep->ce_varname, "leaf-depth") || !strcmp(cep->ce_varname, "leafdepth"))
  6219.             link->leaf_depth = atoi(cep->ce_vardata);
  6220.         else if (!strcmp(cep->ce_varname, "class"))
  6221.         {
  6222.             link->class = Find_class(cep->ce_vardata);
  6223.             if (!link->class || (link->class->flag.temporary == 1))
  6224.             {
  6225.                 config_status("%s:%i: illegal link::class, unknown class '%s' using default of class 'default'",
  6226.                     cep->ce_fileptr->cf_filename,
  6227.                     cep->ce_varlinenum,
  6228.                     cep->ce_vardata);
  6229.                 link->class = default_class;
  6230.             }
  6231.             link->class->xrefcount++;
  6232.         }
  6233.         else if (!strcmp(cep->ce_varname, "ciphers"))
  6234.             link->ciphers = strdup(cep->ce_vardata);
  6235.         else if (!strcmp(cep->ce_varname, "options"))
  6236.         {
  6237.             link->options = 0;
  6238.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6239.             {
  6240.                 if ((ofp = config_binary_flags_search(_LinkFlags, cepp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
  6241.                     link->options |= ofp->flag;
  6242.             }
  6243.         }
  6244.     }
  6245.  
  6246.     /* The default is 'hub *', unless you specify leaf or hub manually. */
  6247.     if (!link->hub && !link->leaf)
  6248.         link->hub = strdup("*");
  6249.  
  6250.     AddListItem(link, conf_link);
  6251.     return 0;
  6252. }
  6253.  
  6254. /** Helper function for erroring on duplicate items.
  6255.  * TODO: make even more friendy for dev's?
  6256.  */
  6257. int config_detect_duplicate(int *var, ConfigEntry *ce, int *errors)
  6258. {
  6259.     if (*var)
  6260.     {
  6261.         config_error("%s:%d: Duplicate %s directive",
  6262.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6263.             ce->ce_varname);
  6264.         (*errors)++;
  6265.         return 1;
  6266.     } else {
  6267.         *var = 1;
  6268.     }
  6269.     return 0;
  6270. }
  6271.  
  6272. int _test_link(ConfigFile *conf, ConfigEntry *ce)
  6273. {
  6274.     ConfigEntry *cep, *cepp, *ceppp;
  6275.     NameValue *ofp;
  6276.     int errors = 0;
  6277.  
  6278.     int has_incoming = 0, has_incoming_mask = 0, has_outgoing = 0;
  6279.     int has_outgoing_bind_ip = 0, has_outgoing_hostname = 0, has_outgoing_port = 0;
  6280.     int has_outgoing_options = 0, has_hub = 0, has_leaf = 0, has_leaf_depth = 0;
  6281.     int has_password = 0, has_class = 0, has_ciphers = 0, has_options = 0;
  6282.  
  6283.     if (!ce->ce_vardata)
  6284.     {
  6285.         config_error("%s:%i: link without servername. Expected: link servername { ... }",
  6286.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6287.         return 1;
  6288.  
  6289.     }
  6290.  
  6291.     if (!strchr(ce->ce_vardata, '.'))
  6292.     {
  6293.         config_error("%s:%i: link: bogus server name. Expected: link servername { ... }",
  6294.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6295.         return 1;
  6296.     }
  6297.  
  6298.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6299.     {
  6300.         if (!strcmp(cep->ce_varname, "incoming"))
  6301.         {
  6302.             config_detect_duplicate(&has_incoming, cep, &errors);
  6303.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6304.             {
  6305.                 if (!strcmp(cepp->ce_varname, "mask"))
  6306.                 {
  6307.                     if (cepp->ce_vardata || cepp->ce_entries)
  6308.                         has_incoming_mask = 1;
  6309.                 }
  6310.             }
  6311.         }
  6312.         else if (!strcmp(cep->ce_varname, "outgoing"))
  6313.         {
  6314.             config_detect_duplicate(&has_outgoing, cep, &errors);
  6315.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6316.             {
  6317.                 if (!strcmp(cepp->ce_varname, "bind-ip"))
  6318.                 {
  6319.                     config_detect_duplicate(&has_outgoing_bind_ip, cepp, &errors);
  6320.                     // todo: ipv4 vs ipv6
  6321.                 }
  6322.                 else if (!strcmp(cepp->ce_varname, "hostname"))
  6323.                 {
  6324.                     config_detect_duplicate(&has_outgoing_hostname, cepp, &errors);
  6325.                     if (strchr(cepp->ce_vardata, '*') || strchr(cepp->ce_vardata, '?'))
  6326.                     {
  6327.                         config_error("%s:%i: hostname in link::outgoing(!) cannot contain wildcards",
  6328.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  6329.                         errors++;
  6330.                     }
  6331.                 }
  6332.                 else if (!strcmp(cepp->ce_varname, "port"))
  6333.                 {
  6334.                     config_detect_duplicate(&has_outgoing_port, cepp, &errors);
  6335.                 }
  6336.                 else if (!strcmp(cepp->ce_varname, "options"))
  6337.                 {
  6338.                     config_detect_duplicate(&has_outgoing_options, cepp, &errors);
  6339.                     for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
  6340.                     {
  6341.                         if (!strcmp(ceppp->ce_varname, "autoconnect"))
  6342.                             ;
  6343.                         else if (!strcmp(ceppp->ce_varname, "ssl"))
  6344.                             ;
  6345.                         else if (!strcmp(ceppp->ce_varname, "insecure"))
  6346.                             ;
  6347.                         else
  6348.                         {
  6349.                             config_error_unknownopt(ceppp->ce_fileptr->cf_filename,
  6350.                                 ceppp->ce_varlinenum, "link::outgoing", ceppp->ce_varname);
  6351.                             errors++;
  6352.                         }
  6353.                         // TODO: validate more options (?) and use list rather than code here...
  6354.                     }
  6355.                 }
  6356.             }
  6357.         }
  6358.         else if (!strcmp(cep->ce_varname, "password"))
  6359.         {
  6360.             config_detect_duplicate(&has_password, cep, &errors);
  6361.             if (Auth_CheckError(cep) < 0)
  6362.             {
  6363.                 errors++;
  6364.             } else {
  6365.                 anAuthStruct *auth = Auth_ConvertConf2AuthStruct(cep);
  6366.                 /* hm. would be nicer if handled @auth-system I think. ah well.. */
  6367.                 if ((auth->type != AUTHTYPE_PLAINTEXT) && (auth->type != AUTHTYPE_SSL_CLIENTCERT) &&
  6368.                     (auth->type != AUTHTYPE_SSL_CLIENTCERTFP))
  6369.                 {
  6370.                     config_error("%s:%i: password in link block should be plaintext OR should be the "
  6371.                                  "SSL fingerprint of the remote link (=better)",
  6372.                                  /* TODO: mention some faq or wiki item for more information */
  6373.                                  cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  6374.                     errors++;
  6375.                 }
  6376.                 Auth_DeleteAuthStruct(auth);
  6377.             }
  6378.         }
  6379.         else if (!strcmp(cep->ce_varname, "hub"))
  6380.         {
  6381.             config_detect_duplicate(&has_hub, cep, &errors);
  6382.         }
  6383.         else if (!strcmp(cep->ce_varname, "leaf"))
  6384.         {
  6385.             config_detect_duplicate(&has_leaf, cep, &errors);
  6386.         }
  6387.         else if (!strcmp(cep->ce_varname, "leaf-depth") || !strcmp(cep->ce_varname, "leafdepth"))
  6388.         {
  6389.             config_detect_duplicate(&has_leaf_depth, cep, &errors);
  6390.         }
  6391.         else if (!strcmp(cep->ce_varname, "class"))
  6392.         {
  6393.             config_detect_duplicate(&has_class, cep, &errors);
  6394.         }
  6395.         else if (!strcmp(cep->ce_varname, "ciphers"))
  6396.         {
  6397.             config_detect_duplicate(&has_ciphers, cep, &errors);
  6398.         }
  6399.         else if (!strcmp(cep->ce_varname, "options"))
  6400.         {
  6401.             config_detect_duplicate(&has_options, cep, &errors);
  6402.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6403.             {
  6404.                 if (!strcmp(cepp->ce_varname, "quarantine"))
  6405.                     ;
  6406.                 else
  6407.                 {
  6408.                     config_error("%s:%d: link::options only has one possible option ('quarantine', rarely used). "
  6409.                                  "Option '%s' is unrecognized. "
  6410.                                  "Perhaps you meant to set an outgoing option in link::outgoing::options instead?",
  6411.                                  cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
  6412.                     errors++;
  6413.                 }
  6414.             }
  6415.         }
  6416.     }
  6417.  
  6418.     if (!has_incoming && !has_outgoing)
  6419.     {
  6420.         config_error("%s:%d: link block needs at least an incoming or outgoing section.",
  6421.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6422.         errors++;
  6423.         need_34_upgrade = 1;
  6424.     }
  6425.  
  6426.     if (has_incoming)
  6427.     {
  6428.         /* If we have an incoming sub-block then we need at least 'mask' and 'password' */
  6429.         if (!has_incoming_mask)
  6430.         {
  6431.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "link::incoming::mask");
  6432.             errors++;
  6433.         }
  6434.     }
  6435.  
  6436.     if (has_outgoing)
  6437.     {
  6438.         /* If we have an outgoing sub-block then we need at least a hostname and port */
  6439.         if (!has_outgoing_hostname)
  6440.         {
  6441.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "link::outgoing::hostname");
  6442.             errors++;
  6443.         }
  6444.         if (!has_outgoing_port)
  6445.         {
  6446.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "link::outgoing::port");
  6447.             errors++;
  6448.         }
  6449.     }
  6450.  
  6451.     /* The only other generic options that are required are 'class' and 'password' */
  6452.     if (!has_password)
  6453.     {
  6454.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "link::password");
  6455.         errors++;
  6456.     }
  6457.     if (!has_class)
  6458.     {
  6459.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6460.             "link::class");
  6461.         errors++;
  6462.     }
  6463.  
  6464.     return errors;
  6465. }
  6466.  
  6467. int     _conf_ban(ConfigFile *conf, ConfigEntry *ce)
  6468. {
  6469.  
  6470.     ConfigEntry *cep;
  6471.     ConfigItem_ban *ca;
  6472.     Hook *h;
  6473.  
  6474.     ca = MyMallocEx(sizeof(ConfigItem_ban));
  6475.     if (!strcmp(ce->ce_vardata, "nick"))
  6476.     {
  6477.         aTKline *nl = MyMallocEx(sizeof(aTKline));
  6478.         nl->type = TKL_NICK;
  6479.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6480.         {
  6481.             if (!strcmp(cep->ce_varname, "mask"))
  6482.                 nl->hostmask = strdup(cep->ce_vardata);
  6483.             else if (!strcmp(cep->ce_varname, "reason"))
  6484.                 nl->reason = strdup(cep->ce_vardata);
  6485.         }
  6486.         strcpy(nl->usermask, "*");
  6487.         AddListItem(nl, tklines[tkl_hash('q')]);
  6488.         free(ca);
  6489.         return 0;
  6490.     }
  6491.     else if (!strcmp(ce->ce_vardata, "ip"))
  6492.         ca->flag.type = CONF_BAN_IP;
  6493.     else if (!strcmp(ce->ce_vardata, "server"))
  6494.         ca->flag.type = CONF_BAN_SERVER;
  6495.     else if (!strcmp(ce->ce_vardata, "user"))
  6496.         ca->flag.type = CONF_BAN_USER;
  6497.     else if (!strcmp(ce->ce_vardata, "realname"))
  6498.         ca->flag.type = CONF_BAN_REALNAME;
  6499.     else if (!strcmp(ce->ce_vardata, "version"))
  6500.     {
  6501.         ca->flag.type = CONF_BAN_VERSION;
  6502.         tempiConf.use_ban_version = 1;
  6503.     }
  6504.     else {
  6505.         int value;
  6506.         free(ca); /* ca isn't used, modules have their own list. */
  6507.         for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  6508.         {
  6509.             value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN);
  6510.             if (value == 1)
  6511.                 break;
  6512.         }
  6513.         return 0;
  6514.     }
  6515.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6516.     {
  6517.         if (!strcmp(cep->ce_varname, "mask"))
  6518.         {
  6519.             ca->mask = strdup(cep->ce_vardata);
  6520.         }
  6521.         else if (!strcmp(cep->ce_varname, "reason"))
  6522.             ca->reason = strdup(cep->ce_vardata);
  6523.         else if (!strcmp(cep->ce_varname, "action"))
  6524.             ca ->action = banact_stringtoval(cep->ce_vardata);
  6525.     }
  6526.     AddListItem(ca, conf_ban);
  6527.     return 0;
  6528. }
  6529.  
  6530. int     _test_ban(ConfigFile *conf, ConfigEntry *ce)
  6531. {
  6532.     ConfigEntry *cep;
  6533.     int     errors = 0;
  6534.     Hook *h;
  6535.     char type = 0;
  6536.     char has_mask = 0, has_action = 0, has_reason = 0;
  6537.  
  6538.     if (!ce->ce_vardata)
  6539.     {
  6540.         config_error("%s:%i: ban without type",
  6541.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6542.         return 1;
  6543.     }
  6544.     if (!strcmp(ce->ce_vardata, "nick"))
  6545.     {}
  6546.     else if (!strcmp(ce->ce_vardata, "ip"))
  6547.     {}
  6548.     else if (!strcmp(ce->ce_vardata, "server"))
  6549.     {}
  6550.     else if (!strcmp(ce->ce_vardata, "user"))
  6551.     {}
  6552.     else if (!strcmp(ce->ce_vardata, "realname"))
  6553.     {}
  6554.     else if (!strcmp(ce->ce_vardata, "version"))
  6555.         type = 'v';
  6556.     else
  6557.     {
  6558.         int used = 0;
  6559.         for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  6560.         {
  6561.             int value, errs = 0;
  6562.             if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  6563.                 && !(h->owner->options & MOD_OPT_PERM))
  6564.                 continue;
  6565.             value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN, &errs);
  6566.             if (value == 2)
  6567.                 used = 1;
  6568.             if (value == 1)
  6569.             {
  6570.                 used = 1;
  6571.                 break;
  6572.             }
  6573.             if (value == -1)
  6574.             {
  6575.                 used = 1;
  6576.                 errors += errs;
  6577.                 break;
  6578.             }
  6579.             if (value == -2)
  6580.             {
  6581.                 used = 1;
  6582.                 errors += errs;
  6583.             }
  6584.         }
  6585.         if (!used) {
  6586.             config_error("%s:%i: unknown ban type %s",
  6587.                 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6588.                 ce->ce_vardata);
  6589.             return 1;
  6590.         }
  6591.         return errors;
  6592.     }
  6593.  
  6594.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6595.     {
  6596.         if (config_is_blankorempty(cep, "ban"))
  6597.         {
  6598.             errors++;
  6599.             continue;
  6600.         }
  6601.         if (!strcmp(cep->ce_varname, "mask"))
  6602.         {
  6603.             if (has_mask)
  6604.             {
  6605.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  6606.                     cep->ce_varlinenum, "ban::mask");
  6607.                 continue;
  6608.             }
  6609.             has_mask = 1;
  6610.         }
  6611.         else if (!strcmp(cep->ce_varname, "reason"))
  6612.         {
  6613.             if (has_reason)
  6614.             {
  6615.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  6616.                     cep->ce_varlinenum, "ban::reason");
  6617.                 continue;
  6618.             }
  6619.             has_reason = 1;
  6620.         }
  6621.         else if (!strcmp(cep->ce_varname, "action"))
  6622.         {
  6623.             if (has_action)
  6624.             {
  6625.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  6626.                     cep->ce_varlinenum, "ban::action");
  6627.             }
  6628.             has_action = 1;
  6629.             if (!banact_stringtoval(cep->ce_vardata))
  6630.             {
  6631.                 config_error("%s:%i: ban::action has unknown action type '%s'",
  6632.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  6633.                     cep->ce_vardata);
  6634.                 errors++;
  6635.             }
  6636.         }
  6637.     }
  6638.  
  6639.     if (!has_mask)
  6640.     {
  6641.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6642.             "ban::mask");
  6643.         errors++;
  6644.     }
  6645.     if (!has_reason)
  6646.     {
  6647.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  6648.             "ban::reason");
  6649.         errors++;
  6650.     }
  6651.     if (has_action && type != 'v')
  6652.     {
  6653.         config_error("%s:%d: ban::action specified even though type is not 'version'",
  6654.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  6655.         errors++;
  6656.     }
  6657.     return errors;
  6658. }
  6659.  
  6660. int _conf_set(ConfigFile *conf, ConfigEntry *ce)
  6661. {
  6662.     ConfigEntry *cep, *cepp, *ceppp;
  6663.     NameValue   *ofl = NULL;
  6664.     Hook *h;
  6665.  
  6666.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  6667.     {
  6668.         if (!strcmp(cep->ce_varname, "kline-address")) {
  6669.             safestrdup(tempiConf.kline_address, cep->ce_vardata);
  6670.         }
  6671.         if (!strcmp(cep->ce_varname, "gline-address")) {
  6672.             safestrdup(tempiConf.gline_address, cep->ce_vardata);
  6673.         }
  6674.         else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
  6675.             tempiConf.conn_modes = (long) set_usermode(cep->ce_vardata);
  6676.         }
  6677.         else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
  6678.             tempiConf.oper_modes = (long) set_usermode(cep->ce_vardata);
  6679.         }
  6680.         else if (!strcmp(cep->ce_varname, "modes-on-join")) {
  6681.             set_channelmodes(cep->ce_vardata, &tempiConf.modes_on_join, 0);
  6682.         }
  6683.         else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
  6684.             safestrdup(tempiConf.oper_snomask, cep->ce_vardata);
  6685.         }
  6686.         else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
  6687.             safestrdup(tempiConf.user_snomask, cep->ce_vardata);
  6688.         }
  6689.         else if (!strcmp(cep->ce_varname, "level-on-join")) {
  6690.             tempiConf.level_on_join = channellevel_to_int(cep->ce_vardata);
  6691.         }
  6692.         else if (!strcmp(cep->ce_varname, "static-quit")) {
  6693.             safestrdup(tempiConf.static_quit, cep->ce_vardata);
  6694.         }
  6695.         else if (!strcmp(cep->ce_varname, "static-part")) {
  6696.             safestrdup(tempiConf.static_part, cep->ce_vardata);
  6697.         }
  6698.         else if (!strcmp(cep->ce_varname, "who-limit")) {
  6699.             tempiConf.who_limit = atol(cep->ce_vardata);
  6700.         }
  6701.         else if (!strcmp(cep->ce_varname, "maxbans")) {
  6702.             tempiConf.maxbans = atol(cep->ce_vardata);
  6703.         }
  6704.         else if (!strcmp(cep->ce_varname, "maxbanlength")) {
  6705.             tempiConf.maxbanlength = atol(cep->ce_vardata);
  6706.         }
  6707.         else if (!strcmp(cep->ce_varname, "silence-limit")) {
  6708.             tempiConf.silence_limit = atol(cep->ce_vardata);
  6709.             if (loop.ircd_booted)
  6710.                 IsupportSetValue(IsupportFind("SILENCE"), cep->ce_vardata);
  6711.         }
  6712.         else if (!strcmp(cep->ce_varname, "auto-join")) {
  6713.             safestrdup(tempiConf.auto_join_chans, cep->ce_vardata);
  6714.         }
  6715.         else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
  6716.             safestrdup(tempiConf.oper_auto_join_chans, cep->ce_vardata);
  6717.         }
  6718.         else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
  6719.             tempiConf.check_target_nick_bans = config_checkval(cep->ce_vardata, CFG_YESNO);
  6720.         }
  6721.         else if (!strcmp(cep->ce_varname, "ping-cookie")) {
  6722.             tempiConf.ping_cookie = config_checkval(cep->ce_vardata, CFG_YESNO);
  6723.         }
  6724.         else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
  6725.             tempiConf.watch_away_notification = config_checkval(cep->ce_vardata, CFG_YESNO);
  6726.         }
  6727.         else if (!strcmp(cep->ce_varname, "uhnames")) {
  6728.             tempiConf.uhnames = config_checkval(cep->ce_vardata, CFG_YESNO);
  6729.         }
  6730.         else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
  6731.             if (!stricmp(cep->ce_vardata, "always"))
  6732.                 tempiConf.userhost_allowed = UHALLOW_ALWAYS;
  6733.             else if (!stricmp(cep->ce_vardata, "never"))
  6734.                 tempiConf.userhost_allowed = UHALLOW_NEVER;
  6735.             else if (!stricmp(cep->ce_vardata, "not-on-channels"))
  6736.                 tempiConf.userhost_allowed = UHALLOW_NOCHANS;
  6737.             else
  6738.                 tempiConf.userhost_allowed = UHALLOW_REJOIN;
  6739.         }
  6740.         else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
  6741.             for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
  6742.                 charsys_add_language(cepp->ce_varname);
  6743.         }
  6744.         else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
  6745.             safestrdup(tempiConf.channel_command_prefix, cep->ce_vardata);
  6746.         }
  6747.         else if (!strcmp(cep->ce_varname, "restrict-usermodes")) {
  6748.             int i;
  6749.             char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
  6750.             /* The data should be something like 'Gw' or something,
  6751.              * but just in case users use '+Gw' then ignore the + (and -).
  6752.              */
  6753.             for (i=0; i < strlen(cep->ce_vardata); i++)
  6754.                 if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
  6755.                     *x++ = cep->ce_vardata[i];
  6756.             *x = '\0';
  6757.             tempiConf.restrict_usermodes = p;
  6758.         }
  6759.         else if (!strcmp(cep->ce_varname, "restrict-channelmodes")) {
  6760.             int i;
  6761.             char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
  6762.             /* The data should be something like 'GL' or something,
  6763.              * but just in case users use '+GL' then ignore the + (and -).
  6764.              */
  6765.             for (i=0; i < strlen(cep->ce_vardata); i++)
  6766.                 if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
  6767.                     *x++ = cep->ce_vardata[i];
  6768.             *x = '\0';
  6769.             tempiConf.restrict_channelmodes = p;
  6770.         }
  6771.         else if (!strcmp(cep->ce_varname, "restrict-extendedbans")) {
  6772.             safestrdup(tempiConf.restrict_extendedbans, cep->ce_vardata);
  6773.         }
  6774.         else if (!strcmp(cep->ce_varname, "new-linking-protocol")) {
  6775.             tempiConf.new_linking_protocol = atoi(cep->ce_vardata);
  6776.         }
  6777.         else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
  6778.             tempiConf.anti_spam_quit_message_time = config_checkval(cep->ce_vardata,CFG_TIME);
  6779.         }
  6780.         else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
  6781.             if (!cep->ce_entries)
  6782.             {
  6783.                 safestrdup(tempiConf.oper_only_stats, cep->ce_vardata);
  6784.             }
  6785.             else
  6786.             {
  6787.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6788.                 {
  6789.                     OperStat *os = MyMallocEx(sizeof(OperStat));
  6790.                     safestrdup(os->flag, cepp->ce_varname);
  6791.                     AddListItem(os, tempiConf.oper_only_stats_ext);
  6792.                 }
  6793.             }
  6794.         }
  6795.         else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
  6796.             tempiConf.maxchannelsperuser = atoi(cep->ce_vardata);
  6797.             if (loop.ircd_booted)
  6798.             {
  6799.                 char tmpbuf[512];
  6800.                 IsupportSetValue(IsupportFind("MAXCHANNELS"), cep->ce_vardata);
  6801.                 ircsnprintf(tmpbuf, sizeof(tmpbuf), "#:%s", cep->ce_vardata);
  6802.                 IsupportSetValue(IsupportFind("CHANLIMIT"), tmpbuf);
  6803.             }
  6804.         }
  6805.         else if (!strcmp(cep->ce_varname, "maxdccallow")) {
  6806.             tempiConf.maxdccallow = atoi(cep->ce_vardata);
  6807.         }
  6808.         else if (!strcmp(cep->ce_varname, "network-name")) {
  6809.             char *tmp;
  6810.             safestrdup(tempiConf.network.x_ircnetwork, cep->ce_vardata);
  6811.             for (tmp = cep->ce_vardata; *cep->ce_vardata; cep->ce_vardata++) {
  6812.                 if (*cep->ce_vardata == ' ')
  6813.                     *cep->ce_vardata='-';
  6814.             }
  6815.             safestrdup(tempiConf.network.x_ircnet005, tmp);
  6816.             if (loop.ircd_booted)
  6817.                 IsupportSetValue(IsupportFind("NETWORK"), tmp);
  6818.             cep->ce_vardata = tmp;
  6819.         }
  6820.         else if (!strcmp(cep->ce_varname, "default-server")) {
  6821.             safestrdup(tempiConf.network.x_defserv, cep->ce_vardata);
  6822.         }
  6823.         else if (!strcmp(cep->ce_varname, "services-server")) {
  6824.             safestrdup(tempiConf.network.x_services_name, cep->ce_vardata);
  6825.         }
  6826.         else if (!strcmp(cep->ce_varname, "sasl-server")) {
  6827.             safestrdup(tempiConf.network.x_sasl_server, cep->ce_vardata);
  6828.         }
  6829.         else if (!strcmp(cep->ce_varname, "stats-server")) {
  6830.             safestrdup(tempiConf.network.x_stats_server, cep->ce_vardata);
  6831.         }
  6832.         else if (!strcmp(cep->ce_varname, "help-channel")) {
  6833.             safestrdup(tempiConf.network.x_helpchan, cep->ce_vardata);
  6834.         }
  6835.         else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
  6836.             safestrdup(tempiConf.network.x_hidden_host, cep->ce_vardata);
  6837.         }
  6838.         else if (!strcmp(cep->ce_varname, "hide-ban-reason")) {
  6839.             tempiConf.hide_ban_reason = config_checkval(cep->ce_vardata, CFG_YESNO);
  6840.         }
  6841.         else if (!strcmp(cep->ce_varname, "prefix-quit")) {
  6842.             if (!strcmp(cep->ce_vardata, "0") || !strcmp(cep->ce_vardata, "no"))
  6843.                 safefree(tempiConf.network.x_prefix_quit);
  6844.             else
  6845.                 safestrdup(tempiConf.network.x_prefix_quit, cep->ce_vardata);
  6846.         }
  6847.         else if (!strcmp(cep->ce_varname, "link")) {
  6848.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  6849.                 if (!strcmp(cepp->ce_varname, "bind-ip")) {
  6850.                     safestrdup(tempiConf.link_bindip, cepp->ce_vardata);
  6851.                 }
  6852.             }
  6853.         }
  6854.         else if (!strcmp(cep->ce_varname, "dns")) {
  6855.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  6856.                 if (!strcmp(cepp->ce_varname, "bind-ip")) {
  6857.                     safestrdup(tempiConf.dns_bindip, cepp->ce_vardata);
  6858.                 }
  6859.             }
  6860.         }
  6861.         else if (!strcmp(cep->ce_varname, "anti-flood")) {
  6862.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  6863.                 if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
  6864.                     tempiConf.unknown_flood_bantime = config_checkval(cepp->ce_vardata,CFG_TIME);
  6865.                 else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
  6866.                     tempiConf.unknown_flood_amount = atol(cepp->ce_vardata);
  6867. #ifdef NO_FLOOD_AWAY
  6868.                 else if (!strcmp(cepp->ce_varname, "away-count"))
  6869.                     tempiConf.away_count = atol(cepp->ce_vardata);
  6870.                 else if (!strcmp(cepp->ce_varname, "away-period"))
  6871.                     tempiConf.away_period = config_checkval(cepp->ce_vardata, CFG_TIME);
  6872.                 else if (!strcmp(cepp->ce_varname, "away-flood"))
  6873.                 {
  6874.                     int cnt, period;
  6875.                     config_parse_flood(cepp->ce_vardata, &cnt, &period);
  6876.                     tempiConf.away_count = cnt;
  6877.                     tempiConf.away_period = period;
  6878.                 }
  6879. #endif
  6880.                 else if (!strcmp(cepp->ce_varname, "nick-flood"))
  6881.                 {
  6882.                     int cnt, period;
  6883.                     config_parse_flood(cepp->ce_vardata, &cnt, &period);
  6884.                     tempiConf.nick_count = cnt;
  6885.                     tempiConf.nick_period = period;
  6886.                 }
  6887.                 else if (!strcmp(cepp->ce_varname, "connect-flood"))
  6888.                 {
  6889.                     int cnt, period;
  6890.                     config_parse_flood(cepp->ce_vardata, &cnt, &period);
  6891.                     tempiConf.throttle_count = cnt;
  6892.                     tempiConf.throttle_period = period;
  6893.                 }
  6894.                 else
  6895.                 {
  6896.                     for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  6897.                     {
  6898.                         int value = (*(h->func.intfunc))(conf,cepp,CONFIG_SET_ANTI_FLOOD);
  6899.                         if (value == 1)
  6900.                             break;
  6901.                     }
  6902.                 }
  6903.             }
  6904.         }
  6905.         else if (!strcmp(cep->ce_varname, "options")) {
  6906.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  6907.                 if (!strcmp(cepp->ce_varname, "hide-ulines")) {
  6908.                     tempiConf.hide_ulines = 1;
  6909.                 }
  6910.                 else if (!strcmp(cepp->ce_varname, "flat-map")) {
  6911.                     tempiConf.flat_map = 1;
  6912.                 }
  6913.                 else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
  6914.                     tempiConf.som = 1;
  6915.                 }
  6916.                 else if (!strcmp(cepp->ce_varname, "identd-check")) {
  6917.                     tempiConf.ident_check = 1;
  6918.                 }
  6919.                 else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
  6920.                     tempiConf.fail_oper_warn = 1;
  6921.                 }
  6922.                 else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
  6923.                     tempiConf.show_connect_info = 1;
  6924.                 }
  6925.                 else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
  6926.                     tempiConf.dont_resolve = 1;
  6927.                 }
  6928.                 else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
  6929.                     tempiConf.mkpasswd_for_everyone = 1;
  6930.                 }
  6931.                 else if (!strcmp(cepp->ce_varname, "allow-insane-bans")) {
  6932.                     tempiConf.allow_insane_bans = 1;
  6933.                 }
  6934.                 else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
  6935.                     tempiConf.allow_part_if_shunned = 1;
  6936.                 }
  6937.                 else if (!strcmp(cepp->ce_varname, "disable-cap")) {
  6938.                     tempiConf.disable_cap = 1;
  6939.                 }
  6940.                 else if (!strcmp(cepp->ce_varname, "disable-ipv6")) {
  6941.                     /* other code handles this */
  6942.                 }
  6943.             }
  6944.         }
  6945.         else if (!strcmp(cep->ce_varname, "cloak-keys"))
  6946.         {
  6947.             for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  6948.             {
  6949.                 int value;
  6950.                 value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS);
  6951.                 if (value == 1)
  6952.                     break;
  6953.             }
  6954.         }
  6955.         else if (!strcmp(cep->ce_varname, "ident"))
  6956.         {
  6957.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6958.             {
  6959.                 if (!strcmp(cepp->ce_varname, "connect-timeout"))
  6960.                     tempiConf.ident_connect_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
  6961.                 if (!strcmp(cepp->ce_varname, "read-timeout"))
  6962.                     tempiConf.ident_read_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
  6963.             }
  6964.         }
  6965.         else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch"))
  6966.         {
  6967.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6968.             {
  6969.                 if (!strcmp(cepp->ce_varname, "enabled"))
  6970.                     tempiConf.timesynch_enabled = config_checkval(cepp->ce_vardata,CFG_YESNO);
  6971.                 else if (!strcmp(cepp->ce_varname, "timeout"))
  6972.                     tempiConf.timesynch_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
  6973.                 else if (!strcmp(cepp->ce_varname, "server"))
  6974.                     safestrdup(tempiConf.timesynch_server, cepp->ce_vardata);
  6975.             }
  6976.         }
  6977.         else if (!strcmp(cep->ce_varname, "spamfilter"))
  6978.         {
  6979.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  6980.             {
  6981.                 if (!strcmp(cepp->ce_varname, "ban-time"))
  6982.                     tempiConf.spamfilter_ban_time = config_checkval(cepp->ce_vardata,CFG_TIME);
  6983.                 else if (!strcmp(cepp->ce_varname, "ban-reason"))
  6984.                     safestrdup(tempiConf.spamfilter_ban_reason, cepp->ce_vardata);
  6985.                 else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
  6986.                     safestrdup(tempiConf.spamfilter_virus_help_channel, cepp->ce_vardata);
  6987.                 else if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
  6988.                     tempiConf.spamfilter_vchan_deny = config_checkval(cepp->ce_vardata,CFG_YESNO);
  6989.                 else if (!strcmp(cepp->ce_varname, "except"))
  6990.                 {
  6991.                     char *name, *p;
  6992.                     SpamExcept *e;
  6993.                     safestrdup(tempiConf.spamexcept_line, cepp->ce_vardata);
  6994.                     for (name = strtoken(&p, cepp->ce_vardata, ","); name; name = strtoken(&p, NULL, ","))
  6995.                     {
  6996.                         if (*name == ' ')
  6997.                             name++;
  6998.                         if (*name)
  6999.                         {
  7000.                             e = MyMallocEx(sizeof(SpamExcept) + strlen(name));
  7001.                             strcpy(e->name, name);
  7002.                             AddListItem(e, tempiConf.spamexcept);
  7003.                         }
  7004.                     }
  7005.                 }
  7006.                 else if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
  7007.                 {
  7008.                     tempiConf.spamfilter_detectslow_warn = atol(cepp->ce_vardata);
  7009.                 }
  7010.                 else if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
  7011.                 {
  7012.                     tempiConf.spamfilter_detectslow_fatal = atol(cepp->ce_vardata);
  7013.                 }
  7014.                 else if (!strcmp(cepp->ce_varname, "stop-on-first-match"))
  7015.                 {
  7016.                     tempiConf.spamfilter_stop_on_first_match = config_checkval(cepp->ce_vardata, CFG_YESNO);
  7017.                 }
  7018.             }
  7019.         }
  7020.         else if (!strcmp(cep->ce_varname, "default-bantime"))
  7021.         {
  7022.             tempiConf.default_bantime = config_checkval(cep->ce_vardata,CFG_TIME);
  7023.         }
  7024.         else if (!strcmp(cep->ce_varname, "ban-version-tkl-time"))
  7025.         {
  7026.             tempiConf.ban_version_tkl_time = config_checkval(cep->ce_vardata,CFG_TIME);
  7027.         }
  7028.         else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
  7029.             int v = atoi(cep->ce_vardata);
  7030.             tempiConf.modef_default_unsettime = (unsigned char)v;
  7031.         }
  7032.         else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
  7033.             int v = atoi(cep->ce_vardata);
  7034.             tempiConf.modef_max_unsettime = (unsigned char)v;
  7035.         }
  7036.         else if (!strcmp(cep->ce_varname, "nick-length")) {
  7037.             int v = atoi(cep->ce_vardata);
  7038.             tempiConf.nicklen = v;
  7039.             if (loop.ircd_booted)
  7040.                 IsupportSetValue(IsupportFind("NICKLEN"), cep->ce_vardata);
  7041.         }
  7042.         else if (!strcmp(cep->ce_varname, "ssl")) {
  7043.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7044.                 if (!strcmp(cepp->ce_varname, "egd")) {
  7045.                     tempiConf.use_egd = 1;
  7046.                     if (cepp->ce_vardata)
  7047.                         tempiConf.egd_path = strdup(cepp->ce_vardata);
  7048.                 }
  7049.                 else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
  7050.                 {
  7051.                     safestrdup(tempiConf.x_server_cipher_list, cepp->ce_vardata);
  7052.                 }
  7053.                 else if (!strcmp(cepp->ce_varname, "dh"))
  7054.                 {
  7055.                     safestrdup(tempiConf.x_dh_pem, cepp->ce_vardata);
  7056.                 }
  7057.                 else if (!strcmp(cepp->ce_varname, "certificate"))
  7058.                 {
  7059.                     convert_to_absolute_path(&cepp->ce_vardata, CONFDIR);
  7060.                     safestrdup(tempiConf.x_server_cert_pem, cepp->ce_vardata);
  7061.                 }
  7062.                 else if (!strcmp(cepp->ce_varname, "key"))
  7063.                 {
  7064.                     convert_to_absolute_path(&cepp->ce_vardata, CONFDIR);
  7065.                     safestrdup(tempiConf.x_server_key_pem, cepp->ce_vardata);
  7066.                 }
  7067.                 else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
  7068.                 {
  7069.                     convert_to_absolute_path(&cepp->ce_vardata, CONFDIR);
  7070.                     safestrdup(tempiConf.trusted_ca_file, cepp->ce_vardata);
  7071.                 }
  7072.                 else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
  7073.                 {
  7074.                     tempiConf.ssl_renegotiate_bytes = config_checkval(cepp->ce_vardata, CFG_SIZE);
  7075.                 }
  7076.                 else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
  7077.                 {
  7078.                     tempiConf.ssl_renegotiate_timeout = config_checkval(cepp->ce_vardata, CFG_TIME);
  7079.                 }
  7080.                 else if (!strcmp(cepp->ce_varname, "options"))
  7081.                 {
  7082.                     tempiConf.ssl_options = 0;
  7083.                     for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
  7084.                     {
  7085.                         ofl = config_binary_flags_search(_SSLFlags, ceppp->ce_varname, ARRAY_SIZEOF(_SSLFlags));
  7086.                         if (ofl) /* this should always be true */
  7087.                             tempiConf.ssl_options |= ofl->flag;
  7088.                     }
  7089.                     if (tempiConf.ssl_options & SSLFLAG_DONOTACCEPTSELFSIGNED)
  7090.                         if (!(tempiConf.ssl_options & SSLFLAG_VERIFYCERT))
  7091.                             tempiConf.ssl_options |= SSLFLAG_VERIFYCERT;
  7092.                 }
  7093.  
  7094.             }
  7095.         }
  7096.         else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
  7097.         {
  7098.             tempiConf.default_ipv6_clone_mask = atoi(cep->ce_vardata);
  7099.         }
  7100.         else
  7101.         {
  7102.             int value;
  7103.             for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  7104.             {
  7105.                 value = (*(h->func.intfunc))(conf,cep,CONFIG_SET);
  7106.                 if (value == 1)
  7107.                     break;
  7108.             }
  7109.         }
  7110.     }
  7111.     return 0;
  7112. }
  7113.  
  7114. int _test_set(ConfigFile *conf, ConfigEntry *ce)
  7115. {
  7116.     ConfigEntry *cep, *cepp, *ceppp;
  7117.     long        templong;
  7118.     int     tempi;
  7119.     int     errors = 0;
  7120.     Hook    *h;
  7121. #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; }
  7122. #define CheckNullAllowEmpty(x) if ((!(x)->ce_vardata)) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
  7123. #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
  7124.  
  7125.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  7126.     {
  7127.         if (!cep->ce_varname)
  7128.         {
  7129.             config_error_blank(cep->ce_fileptr->cf_filename,
  7130.                 cep->ce_varlinenum, "set");
  7131.             errors++;
  7132.             continue;
  7133.         }
  7134.         if (!strcmp(cep->ce_varname, "kline-address")) {
  7135.             CheckNull(cep);
  7136.             CheckDuplicate(cep, kline_address, "kline-address");
  7137.             if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
  7138.             {
  7139.                 config_error("%s:%i: set::kline-address must be an e-mail or an URL",
  7140.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7141.                 errors++;
  7142.                 continue;
  7143.             }
  7144.             else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
  7145.             {
  7146.                 config_error("%s:%i: set::kline-address may not be an UnrealIRCd Team address",
  7147.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7148.                 errors++; continue;
  7149.             }
  7150.         }
  7151.         else if (!strcmp(cep->ce_varname, "gline-address")) {
  7152.             CheckNull(cep);
  7153.             CheckDuplicate(cep, gline_address, "gline-address");
  7154.             if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
  7155.             {
  7156.                 config_error("%s:%i: set::gline-address must be an e-mail or an URL",
  7157.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7158.                 errors++;
  7159.                 continue;
  7160.             }
  7161.             else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
  7162.             {
  7163.                 config_error("%s:%i: set::gline-address may not be an UnrealIRCd Team address",
  7164.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7165.                 errors++; continue;
  7166.             }
  7167.         }
  7168.         else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
  7169.             char *p;
  7170.             CheckNull(cep);
  7171.             CheckDuplicate(cep, modes_on_connect, "modes-on-connect");
  7172.             for (p = cep->ce_vardata; *p; p++)
  7173.                 if (strchr("oOaANCrzSgHhqtW", *p))
  7174.                 {
  7175.                     config_error("%s:%i: set::modes-on-connect may not include mode '%c'",
  7176.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
  7177.                     errors++;
  7178.                 }
  7179.             templong = (long) set_usermode(cep->ce_vardata);
  7180.         }
  7181.         else if (!strcmp(cep->ce_varname, "modes-on-join")) {
  7182.             char *c;
  7183.             struct ChMode temp;
  7184.             bzero(&temp, sizeof(temp));
  7185.             CheckNull(cep);
  7186.             CheckDuplicate(cep, modes_on_join, "modes-on-join");
  7187.             for (c = cep->ce_vardata; *c; c++)
  7188.             {
  7189.                 if (*c == ' ')
  7190.                     break; /* don't check the parameter ;p */
  7191.                 switch (*c)
  7192.                 {
  7193.                     case 'q':
  7194.                     case 'a':
  7195.                     case 'o':
  7196.                     case 'h':
  7197.                     case 'v':
  7198.                     case 'b':
  7199.                     case 'e':
  7200.                     case 'I':
  7201.                     case 'k':
  7202.                     case 'l':
  7203.                         config_error("%s:%i: set::modes-on-join may not contain +%c",
  7204.                             cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *c);
  7205.                         errors++;
  7206.                         break;
  7207.                 }
  7208.             }
  7209.             set_channelmodes(cep->ce_vardata, &temp, 1);
  7210.             if (temp.mode & MODE_SECRET && temp.mode & MODE_PRIVATE)
  7211.             {
  7212.                 config_error("%s:%i: set::modes-on-join has both +s and +p",
  7213.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7214.                 errors++;
  7215.             }
  7216.  
  7217.         }
  7218.         else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
  7219.             char *p;
  7220.             CheckNull(cep);
  7221.             CheckDuplicate(cep, modes_on_oper, "modes-on-oper");
  7222.             for (p = cep->ce_vardata; *p; p++)
  7223.                 if (strchr("oOaANCrzS", *p))
  7224.                 {
  7225.                     config_error("%s:%i: set::modes-on-oper may not include mode '%c'",
  7226.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
  7227.                     errors++;
  7228.                 }
  7229.             templong = (long) set_usermode(cep->ce_vardata);
  7230.         }
  7231.         else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
  7232.             CheckNull(cep);
  7233.             CheckDuplicate(cep, snomask_on_oper, "snomask-on-oper");
  7234.         }
  7235.         else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
  7236.             CheckNull(cep);
  7237.             CheckDuplicate(cep, snomask_on_connect, "snomask-on-connect");
  7238.         }
  7239.         else if (!strcmp(cep->ce_varname, "level-on-join")) {
  7240.             char *p;
  7241.             CheckNull(cep);
  7242.             CheckDuplicate(cep, level_on_join, "level-on-join");
  7243.             if (!channellevel_to_int(cep->ce_vardata))
  7244.             {
  7245.                 config_error("%s:%i: set::level-on-join: unknown value '%s', should be one of: none, voice, halfop, op, protect, owner",
  7246.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
  7247.                 errors++;
  7248.             }
  7249.         }
  7250.         else if (!strcmp(cep->ce_varname, "static-quit")) {
  7251.             CheckNull(cep);
  7252.             CheckDuplicate(cep, static_quit, "static-quit");
  7253.         }
  7254.         else if (!strcmp(cep->ce_varname, "static-part")) {
  7255.             CheckNull(cep);
  7256.             CheckDuplicate(cep, static_part, "static-part");
  7257.         }
  7258.         else if (!strcmp(cep->ce_varname, "who-limit")) {
  7259.             CheckNull(cep);
  7260.             CheckDuplicate(cep, who_limit, "who-limit");
  7261.         }
  7262.         else if (!strcmp(cep->ce_varname, "maxbans")) {
  7263.             CheckNull(cep);
  7264.             CheckDuplicate(cep, maxbans, "maxbans");
  7265.         }
  7266.         else if (!strcmp(cep->ce_varname, "maxbanlength")) {
  7267.             CheckNull(cep);
  7268.             CheckDuplicate(cep, maxbanlength, "maxbanlength");
  7269.         }
  7270.         else if (!strcmp(cep->ce_varname, "silence-limit")) {
  7271.             CheckNull(cep);
  7272.             CheckDuplicate(cep, silence_limit, "silence-limit");
  7273.         }
  7274.         else if (!strcmp(cep->ce_varname, "auto-join")) {
  7275.             CheckNull(cep);
  7276.             CheckDuplicate(cep, auto_join, "auto-join");
  7277.         }
  7278.         else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
  7279.             CheckNull(cep);
  7280.             CheckDuplicate(cep, oper_auto_join, "oper-auto-join");
  7281.         }
  7282.         else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
  7283.             CheckNull(cep);
  7284.             CheckDuplicate(cep, check_target_nick_bans, "check-target-nick-bans");
  7285.         }
  7286.         else if (!strcmp(cep->ce_varname, "pingpong-warning")) {
  7287.             config_error("%s:%i: set::pingpong-warning no longer exists (the warning is always off)",
  7288.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7289.             need_34_upgrade = 1;
  7290.             errors++;
  7291.         }
  7292.         else if (!strcmp(cep->ce_varname, "ping-cookie")) {
  7293.             CheckNull(cep);
  7294.             CheckDuplicate(cep, ping_cookie, "ping-cookie");
  7295.         }
  7296.         else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
  7297.             CheckNull(cep);
  7298.             CheckDuplicate(cep, watch_away_notification, "watch-away-notification");
  7299.         }
  7300.         else if (!strcmp(cep->ce_varname, "uhnames")) {
  7301.             CheckNull(cep);
  7302.             CheckDuplicate(cep, uhnames, "uhnames");
  7303.         }
  7304.         else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
  7305.             CheckNullAllowEmpty(cep);
  7306.             CheckDuplicate(cep, channel_command_prefix, "channel-command-prefix");
  7307.         }
  7308.         else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
  7309.             CheckNull(cep);
  7310.             CheckDuplicate(cep, allow_userhost_change, "allow-userhost-change");
  7311.             if (stricmp(cep->ce_vardata, "always") &&
  7312.                 stricmp(cep->ce_vardata, "never") &&
  7313.                 stricmp(cep->ce_vardata, "not-on-channels") &&
  7314.                 stricmp(cep->ce_vardata, "force-rejoin"))
  7315.             {
  7316.                 config_error("%s:%i: set::allow-userhost-change is invalid",
  7317.                     cep->ce_fileptr->cf_filename,
  7318.                     cep->ce_varlinenum);
  7319.                 errors++;
  7320.                 continue;
  7321.             }
  7322.         }
  7323.         else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
  7324.             if (cep->ce_vardata)
  7325.             {
  7326.                 config_error("%s:%i: set::allowed-nickchars: please use 'allowed-nickchars { name; };' "
  7327.                              "and not 'allowed-nickchars name;'",
  7328.                              cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7329.                 errors++;
  7330.                 continue;
  7331.             }
  7332.             for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
  7333.             {
  7334.                 if (!charsys_test_language(cepp->ce_varname))
  7335.                 {
  7336.                     config_error("%s:%i: set::allowed-nickchars: Unknown (sub)language '%s'",
  7337.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cepp->ce_varname);
  7338.                     errors++;
  7339.                 }
  7340.             }
  7341.         }
  7342.         else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
  7343.             CheckNull(cep);
  7344.             CheckDuplicate(cep, anti_spam_quit_message_time, "anti-spam-quit-message-time");
  7345.         }
  7346.         else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
  7347.             CheckDuplicate(cep, oper_only_stats, "oper-only-stats");
  7348.             if (!cep->ce_entries)
  7349.             {
  7350.                 CheckNull(cep);
  7351.             }
  7352.             else
  7353.             {
  7354.                 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  7355.                 {
  7356.                     if (!cepp->ce_varname)
  7357.                         config_error("%s:%i: blank set::oper-only-stats item",
  7358.                             cepp->ce_fileptr->cf_filename,
  7359.                             cepp->ce_varlinenum);
  7360.                 }
  7361.             }
  7362.         }
  7363.         else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
  7364.             CheckNull(cep);
  7365.             CheckDuplicate(cep, maxchannelsperuser, "maxchannelsperuser");
  7366.             tempi = atoi(cep->ce_vardata);
  7367.             if (tempi < 1)
  7368.             {
  7369.                 config_error("%s:%i: set::maxchannelsperuser must be > 0",
  7370.                     cep->ce_fileptr->cf_filename,
  7371.                     cep->ce_varlinenum);
  7372.                 errors++;
  7373.                 continue;
  7374.             }
  7375.         }
  7376.         else if (!strcmp(cep->ce_varname, "maxdccallow")) {
  7377.             CheckNull(cep);
  7378.             CheckDuplicate(cep, maxdccallow, "maxdccallow");
  7379.         }
  7380.         else if (!strcmp(cep->ce_varname, "network-name")) {
  7381.             char *p;
  7382.             CheckNull(cep);
  7383.             CheckDuplicate(cep, network_name, "network-name");
  7384.             for (p = cep->ce_vardata; *p; p++)
  7385.                 if ((*p < ' ') || (*p > '~'))
  7386.                 {
  7387.                     config_error("%s:%i: set::network-name can only contain ASCII characters 33-126. Invalid character = '%c'",
  7388.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
  7389.                     errors++;
  7390.                     break;
  7391.                 }
  7392.         }
  7393.         else if (!strcmp(cep->ce_varname, "default-server")) {
  7394.             CheckNull(cep);
  7395.             CheckDuplicate(cep, default_server, "default-server");
  7396.         }
  7397.         else if (!strcmp(cep->ce_varname, "services-server")) {
  7398.             CheckNull(cep);
  7399.             CheckDuplicate(cep, services_server, "services-server");
  7400.         }
  7401.         else if (!strcmp(cep->ce_varname, "sasl-server")) {
  7402.             CheckNull(cep);
  7403.             CheckDuplicate(cep, sasl_server, "sasl-server");
  7404.         }
  7405.         else if (!strcmp(cep->ce_varname, "stats-server")) {
  7406.             CheckNull(cep);
  7407.             CheckDuplicate(cep, stats_server, "stats-server");
  7408.         }
  7409.         else if (!strcmp(cep->ce_varname, "help-channel")) {
  7410.             CheckNull(cep);
  7411.             CheckDuplicate(cep, help_channel, "help-channel");
  7412.         }
  7413.         else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
  7414.             CheckNull(cep);
  7415.             CheckDuplicate(cep, hiddenhost_prefix, "hiddenhost-prefix");
  7416.             if (strchr(cep->ce_vardata, ' ') || (*cep->ce_vardata == ':'))
  7417.             {
  7418.                 config_error("%s:%i: set::hiddenhost-prefix must not contain spaces or be prefixed with ':'",
  7419.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7420.                 errors++;
  7421.                 continue;
  7422.             }
  7423.         }
  7424.         else if (!strcmp(cep->ce_varname, "prefix-quit")) {
  7425.             CheckNull(cep);
  7426.             CheckDuplicate(cep, prefix_quit, "prefix-quit");
  7427.         }
  7428.         else if (!strcmp(cep->ce_varname, "hide-ban-reason")) {
  7429.             CheckDuplicate(cep, hide_ban_reason, "hide-ban-reason");
  7430.         }
  7431.         else if (!strcmp(cep->ce_varname, "restrict-usermodes"))
  7432.         {
  7433.             CheckNull(cep);
  7434.             CheckDuplicate(cep, restrict_usermodes, "restrict-usermodes");
  7435.             if (cep->ce_varname) {
  7436.                 int warn = 0;
  7437.                 char *p;
  7438.                 for (p = cep->ce_vardata; *p; p++)
  7439.                     if ((*p == '+') || (*p == '-'))
  7440.                         warn = 1;
  7441.                 if (warn) {
  7442.                     config_status("%s:%i: warning: set::restrict-usermodes: should only contain modechars, no + or -.\n",
  7443.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7444.                 }
  7445.             }
  7446.         }
  7447.         else if (!strcmp(cep->ce_varname, "restrict-channelmodes"))
  7448.         {
  7449.             CheckNull(cep);
  7450.             CheckDuplicate(cep, restrict_channelmodes, "restrict-channelmodes");
  7451.             if (cep->ce_varname) {
  7452.                 int warn = 0;
  7453.                 char *p;
  7454.                 for (p = cep->ce_vardata; *p; p++)
  7455.                     if ((*p == '+') || (*p == '-'))
  7456.                         warn = 1;
  7457.                 if (warn) {
  7458.                     config_status("%s:%i: warning: set::restrict-channelmodes: should only contain modechars, no + or -.\n",
  7459.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7460.                 }
  7461.             }
  7462.         }
  7463.         else if (!strcmp(cep->ce_varname, "restrict-extendedbans"))
  7464.         {
  7465.             CheckDuplicate(cep, restrict_extendedbans, "restrict-extendedbans");
  7466.             CheckNull(cep);
  7467.         }
  7468.         else if (!strcmp(cep->ce_varname, "new-linking-protocol"))
  7469.         {
  7470.             CheckDuplicate(cep, new_linking_protocol, "new-linking-protocol");
  7471.             CheckNull(cep);
  7472.         }
  7473.         else if (!strcmp(cep->ce_varname, "link")) {
  7474.                     for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7475.                         CheckNull(cepp);
  7476.                         if (!strcmp(cepp->ce_varname, "bind-ip")) {
  7477.                             CheckDuplicate(cepp, link_bind_ip, "link::bind-ip");
  7478.                             if (strcmp(cepp->ce_vardata, "*"))
  7479.                             {
  7480.                                 if (!is_valid_ip(cepp->ce_vardata))
  7481.                                 {
  7482.                                     config_error("%s:%i: set::link::bind-ip (%s) is not a valid IP",
  7483.                                         cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
  7484.                                         cepp->ce_vardata);
  7485.                                     errors++;
  7486.                                     continue;
  7487.                                 }
  7488.                             }
  7489.                         }
  7490.                     }
  7491.         }
  7492.         else if (!strcmp(cep->ce_varname, "dns")) {
  7493.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7494.                 CheckNull(cepp);
  7495.                 if (!strcmp(cepp->ce_varname, "nameserver") ||
  7496.                     !strcmp(cepp->ce_varname, "timeout") ||
  7497.                     !strcmp(cepp->ce_varname, "retries"))
  7498.                 {
  7499.                     config_error("%s:%i: set::dns::%s no longer exist in UnrealIRCd 4. "
  7500.                                  "Please remove it from your configuration file.",
  7501.                         cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
  7502.                     errors++;
  7503.                 } else
  7504.                 if (!strcmp(cepp->ce_varname, "bind-ip")) {
  7505.                     CheckDuplicate(cepp, dns_bind_ip, "dns::bind-ip");
  7506.                     if (strcmp(cepp->ce_vardata, "*"))
  7507.                     {
  7508.                         if (!is_valid_ip(cepp->ce_vardata))
  7509.                         {
  7510.                             config_error("%s:%i: set::dns::bind-ip (%s) is not a valid IP",
  7511.                                 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
  7512.                                 cepp->ce_vardata);
  7513.                             errors++;
  7514.                             continue;
  7515.                         }
  7516.                     }
  7517.                 }
  7518.                 else
  7519.                 {
  7520.                     config_error_unknownopt(cepp->ce_fileptr->cf_filename,
  7521.                         cepp->ce_varlinenum, "set::dns",
  7522.                         cepp->ce_varname);
  7523.                         errors++;
  7524.                 }
  7525.             }
  7526.         }
  7527.         else if (!strcmp(cep->ce_varname, "throttle")) {
  7528.             config_error("%s:%i: set::throttle has been renamed. you now use "
  7529.                          "set::anti-flood::connect-flood <connections>:<period>. "
  7530.                          "Or just remove the throttle block and you get the default "
  7531.                          "of 3 per 60 seconds.",
  7532.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7533.             errors++;
  7534.             need_34_upgrade = 1;
  7535.             continue;
  7536.         }
  7537.         else if (!strcmp(cep->ce_varname, "anti-flood")) {
  7538.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7539.                 CheckNull(cepp);
  7540.                 if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
  7541.                 {
  7542.                     CheckDuplicate(cepp, anti_flood_unknown_flood_bantime, "anti-flood::unknown-flood-bantime");
  7543.                 }
  7544.                 else if (!strcmp(cepp->ce_varname, "unknown-flood-amount")) {
  7545.                     CheckDuplicate(cepp, anti_flood_unknown_flood_amount, "anti-flood::unknown-flood-amount");
  7546.                 }
  7547. #ifdef NO_FLOOD_AWAY
  7548.                 else if (!strcmp(cepp->ce_varname, "away-count")) {
  7549.                     int temp = atol(cepp->ce_vardata);
  7550.                     CheckDuplicate(cepp, anti_flood_away_count, "anti-flood::away-count");
  7551.                     if (temp < 1 || temp > 255)
  7552.                     {
  7553.                         config_error("%s:%i: set::anti-flood::away-count must be between 1 and 255",
  7554.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7555.                         errors++;
  7556.                     }
  7557.                 }
  7558.                 else if (!strcmp(cepp->ce_varname, "away-period")) {
  7559.                     int temp = config_checkval(cepp->ce_vardata, CFG_TIME);
  7560.                     CheckDuplicate(cepp, anti_flood_away_period, "anti-flood::away-period");
  7561.                     if (temp < 10)
  7562.                     {
  7563.                         config_error("%s:%i: set::anti-flood::away-period must be greater than 9",
  7564.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7565.                         errors++;
  7566.                     }
  7567.                 }
  7568.                 else if (!strcmp(cepp->ce_varname, "away-flood"))
  7569.                 {
  7570.                     int cnt, period;
  7571.                     if (settings.has_anti_flood_away_period)
  7572.                     {
  7573.                         config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-period",
  7574.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7575.                         continue;
  7576.                     }
  7577.                     if (settings.has_anti_flood_away_count)
  7578.                     {
  7579.                         config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-count",
  7580.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7581.                         continue;
  7582.                     }
  7583.                     settings.has_anti_flood_away_period = 1;
  7584.                     settings.has_anti_flood_away_count = 1;
  7585.                     if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
  7586.                         (cnt < 1) || (cnt > 255) || (period < 10))
  7587.                     {
  7588.                         config_error("%s:%i: set::anti-flood::away-flood error. Syntax is '<count>:<period>' (eg 5:60), "
  7589.                                      "count should be 1-255, period should be greater than 9",
  7590.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7591.                         errors++;
  7592.                     }
  7593.                 }
  7594. #endif
  7595.                 else if (!strcmp(cepp->ce_varname, "nick-flood"))
  7596.                 {
  7597.                     int cnt, period;
  7598.                     CheckDuplicate(cepp, anti_flood_nick_flood, "anti-flood::nick-flood");
  7599.                     if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
  7600.                         (cnt < 1) || (cnt > 255) || (period < 5))
  7601.                     {
  7602.                         config_error("%s:%i: set::anti-flood::nick-flood error. Syntax is '<count>:<period>' (eg 5:60), "
  7603.                                      "count should be 1-255, period should be greater than 4",
  7604.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7605.                         errors++;
  7606.                     }
  7607.                 }
  7608.                 else if (!strcmp(cepp->ce_varname, "connect-flood"))
  7609.                 {
  7610.                     int cnt, period;
  7611.                     CheckDuplicate(cepp, anti_flood_connect_flood, "anti-flood::connect-flood");
  7612.                     if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
  7613.                         (cnt < 1) || (cnt > 255) || (period < 1) || (period > 3600))
  7614.                     {
  7615.                         config_error("%s:%i: set::anti-flood::connect-flood: Syntax is '<count>:<period>' (eg 5:60), "
  7616.                                      "count should be 1-255, period should be 1-3600",
  7617.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  7618.                         errors++;
  7619.                     }
  7620.                 }
  7621.                 else
  7622.                 {
  7623.                     /* hmm.. I don't like this method. but I just quickly copied it from CONFIG_ALLOW for now... */
  7624.                     int used = 0;
  7625.                     Hook *h;
  7626.                     for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  7627.                     {
  7628.                         int value, errs = 0;
  7629.                         if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  7630.                             && !(h->owner->options & MOD_OPT_PERM))
  7631.                             continue;
  7632.                         value = (*(h->func.intfunc))(conf,cepp,CONFIG_SET_ANTI_FLOOD,&errs);
  7633.                         if (value == 2)
  7634.                             used = 1;
  7635.                         if (value == 1)
  7636.                         {
  7637.                             used = 1;
  7638.                             break;
  7639.                         }
  7640.                         if (value == -1)
  7641.                         {
  7642.                             used = 1;
  7643.                             errors += errs;
  7644.                             break;
  7645.                         }
  7646.                         if (value == -2)
  7647.                         {
  7648.                             used = 1;
  7649.                             errors += errs;
  7650.                         }
  7651.                     }
  7652.                     if (!used)
  7653.                     {
  7654.                         config_error_unknownopt(cepp->ce_fileptr->cf_filename,
  7655.                             cepp->ce_varlinenum, "set::anti-flood",
  7656.                             cepp->ce_varname);
  7657.                         errors++;
  7658.                     }
  7659.                     continue;
  7660.                 }
  7661.             }
  7662.         }
  7663.         else if (!strcmp(cep->ce_varname, "options")) {
  7664.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7665.                 if (!strcmp(cepp->ce_varname, "hide-ulines"))
  7666.                 {
  7667.                     CheckDuplicate(cepp, options_hide_ulines, "options::hide-ulines");
  7668.                 }
  7669.                 else if (!strcmp(cepp->ce_varname, "flat-map")) {
  7670.                     CheckDuplicate(cepp, options_flat_map, "options::flat-map");
  7671.                 }
  7672.                 else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
  7673.                     CheckDuplicate(cepp, options_show_opermotd, "options::show-opermotd");
  7674.                 }
  7675.                 else if (!strcmp(cepp->ce_varname, "identd-check")) {
  7676.                     CheckDuplicate(cepp, options_identd_check, "options::identd-check");
  7677.                 }
  7678.                 else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
  7679.                     CheckDuplicate(cepp, options_fail_oper_warn, "options::fail-oper-warn");
  7680.                 }
  7681.                 else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
  7682.                     CheckDuplicate(cepp, options_show_connect_info, "options::show-connect-info");
  7683.                 }
  7684.                 else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
  7685.                     CheckDuplicate(cepp, options_dont_resolve, "options::dont-resolve");
  7686.                 }
  7687.                 else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
  7688.                     CheckDuplicate(cepp, options_mkpasswd_for_everyone, "options::mkpasswd-for-everyone");
  7689.                 }
  7690.                 else if (!strcmp(cepp->ce_varname, "allow-insane-bans")) {
  7691.                     CheckDuplicate(cepp, options_allow_insane_bans, "options::allow-insane-bans");
  7692.                 }
  7693.                 else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
  7694.                     CheckDuplicate(cepp, options_allow_part_if_shunned, "options::allow-part-if-shunned");
  7695.                 }
  7696.                 else if (!strcmp(cepp->ce_varname, "disable-cap")) {
  7697.                     CheckDuplicate(cepp, options_disable_cap, "options::disable-cap");
  7698.                 }
  7699.                 else if (!strcmp(cepp->ce_varname, "disable-ipv6")) {
  7700.                     CheckDuplicate(cepp, options_disable_ipv6, "options::disable-ipv6");
  7701.                     DISABLE_IPV6 = 1; /* ugly ugly. needs to be done here because at conf runtime is too late. */
  7702.                 }
  7703.                 else
  7704.                 {
  7705.                     config_error_unknownopt(cepp->ce_fileptr->cf_filename,
  7706.                         cepp->ce_varlinenum, "set::options",
  7707.                         cepp->ce_varname);
  7708.                     errors++;
  7709.                     continue;
  7710.                 }
  7711.             }
  7712.         }
  7713.         else if (!strcmp(cep->ce_varname, "hosts")) {
  7714.             config_error("%s:%i: set::hosts has been removed in UnrealIRCd 4. You can use oper::vhost now.",
  7715.                 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7716.             errors++;
  7717.             need_34_upgrade = 1;
  7718.         }
  7719.         else if (!strcmp(cep->ce_varname, "cloak-keys"))
  7720.         {
  7721.             CheckDuplicate(cep, cloak_keys, "cloak-keys");
  7722.             for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  7723.             {
  7724.                 int value, errs = 0;
  7725.                 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  7726.                     && !(h->owner->options & MOD_OPT_PERM))
  7727.                     continue;
  7728.                 value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS, &errs);
  7729.  
  7730.                 if (value == 1)
  7731.                     break;
  7732.                 if (value == -1)
  7733.                 {
  7734.                     errors += errs;
  7735.                     break;
  7736.                 }
  7737.                 if (value == -2)
  7738.                     errors += errs;
  7739.             }
  7740.         }
  7741.         else if (!strcmp(cep->ce_varname, "scan")) {
  7742.             config_status("%s:%i: set::scan: WARNING: scanner support has been removed, "
  7743.                 "use BOPM instead: http://www.blitzed.org/bopm/ (*NIX) / http://vulnscan.org/winbopm/ (Windows)",
  7744.                 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  7745.         }
  7746.         else if (!strcmp(cep->ce_varname, "ident")) {
  7747.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  7748.             {
  7749.                 int is_ok = 0;
  7750.                 CheckNull(cepp);
  7751.                 if (!strcmp(cepp->ce_varname, "connect-timeout"))
  7752.                 {
  7753.                     is_ok = 1;
  7754.                     CheckDuplicate(cepp, ident_connect_timeout, "ident::connect-timeout");
  7755.                 }
  7756.                 else if (!strcmp(cepp->ce_varname, "read-timeout"))
  7757.                 {
  7758.                     is_ok = 1;
  7759.                     CheckDuplicate(cepp, ident_read_timeout, "ident::read-timeout");
  7760.                 }
  7761.                 if (is_ok)
  7762.                 {
  7763.                     int v = config_checkval(cepp->ce_vardata,CFG_TIME);
  7764.                     if ((v > 60) || (v < 1))
  7765.                     {
  7766.                         config_error("%s:%i: set::ident::%s value out of range (%d), should be between 1 and 60.",
  7767.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
  7768.                         errors++;
  7769.                         continue;
  7770.                     }
  7771.                 } else {
  7772.                     config_error_unknown(cepp->ce_fileptr->cf_filename,
  7773.                         cepp->ce_varlinenum, "set::ident",
  7774.                         cepp->ce_varname);
  7775.                     errors++;
  7776.                     continue;
  7777.                 }
  7778.             }
  7779.         }
  7780.         else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch")) {
  7781.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  7782.             {
  7783.                 CheckNull(cepp);
  7784.                 if (!strcmp(cepp->ce_varname, "enabled"))
  7785.                 {
  7786.                 }
  7787.                 else if (!strcmp(cepp->ce_varname, "timeout"))
  7788.                 {
  7789.                     int v = config_checkval(cepp->ce_vardata,CFG_TIME);
  7790.                     if ((v > 5) || (v < 1))
  7791.                     {
  7792.                         config_error("%s:%i: set::timesync::%s value out of range (%d), should be between 1 and 5 (higher=unreliable).",
  7793.                             cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
  7794.                         errors++;
  7795.                         continue;
  7796.                     }
  7797.                 } else if (!strcmp(cepp->ce_varname, "server"))
  7798.                 {
  7799.                 } else {
  7800.                     config_error_unknown(cepp->ce_fileptr->cf_filename,
  7801.                         cepp->ce_varlinenum, "set::timesync",
  7802.                         cepp->ce_varname);
  7803.                     errors++;
  7804.                     continue;
  7805.                 }
  7806.             }
  7807.         }
  7808.         else if (!strcmp(cep->ce_varname, "spamfilter")) {
  7809.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  7810.             {
  7811.                 CheckNull(cepp);
  7812.                 if (!strcmp(cepp->ce_varname, "ban-time"))
  7813.                 {
  7814.                     long x;
  7815.                     CheckDuplicate(cepp, spamfilter_ban_time, "spamfilter::ban-time");
  7816.                     x = config_checkval(cepp->ce_vardata,CFG_TIME);
  7817.                     if ((x < 0) > (x > 2000000000))
  7818.                     {
  7819.                         config_error("%s:%i: set::spamfilter:ban-time: value '%ld' out of range",
  7820.                             cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
  7821.                         errors++;
  7822.                         continue;
  7823.                     }
  7824.                 } else
  7825.                 if (!strcmp(cepp->ce_varname, "ban-reason"))
  7826.                 {
  7827.                     CheckDuplicate(cepp, spamfilter_ban_reason, "spamfilter::ban-reason");
  7828.  
  7829.                 }
  7830.                 else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
  7831.                 {
  7832.                     CheckDuplicate(cepp, spamfilter_virus_help_channel, "spamfilter::virus-help-channel");
  7833.                     if ((cepp->ce_vardata[0] != '#') || (strlen(cepp->ce_vardata) > CHANNELLEN))
  7834.                     {
  7835.                         config_error("%s:%i: set::spamfilter:virus-help-channel: "
  7836.                                      "specified channelname is too long or contains invalid characters (%s)",
  7837.                                      cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  7838.                                      cepp->ce_vardata);
  7839.                         errors++;
  7840.                         continue;
  7841.                     }
  7842.                 } else
  7843.                 if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
  7844.                 {
  7845.                     CheckDuplicate(cepp, spamfilter_virus_help_channel_deny, "spamfilter::virus-help-channel-deny");
  7846.                 } else
  7847.                 if (!strcmp(cepp->ce_varname, "except"))
  7848.                 {
  7849.                     CheckDuplicate(cepp, spamfilter_except, "spamfilter::except");
  7850.                 } else
  7851. #ifdef SPAMFILTER_DETECTSLOW
  7852.                 if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
  7853.                 {
  7854.                 } else
  7855.                 if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
  7856.                 {
  7857.                 } else
  7858. #endif
  7859.                 if (!strcmp(cepp->ce_varname, "stop-on-first-match"))
  7860.                 {
  7861.                 } else
  7862.                 {
  7863.                     config_error_unknown(cepp->ce_fileptr->cf_filename,
  7864.                         cepp->ce_varlinenum, "set::spamfilter",
  7865.                         cepp->ce_varname);
  7866.                     errors++;
  7867.                     continue;
  7868.                 }
  7869.             }
  7870.         }
  7871. /* TODO: FIX THIS */
  7872.         else if (!strcmp(cep->ce_varname, "default-bantime"))
  7873.         {
  7874.             long x;
  7875.             CheckDuplicate(cep, default_bantime, "default-bantime");
  7876.             CheckNull(cep);
  7877.             x = config_checkval(cep->ce_vardata,CFG_TIME);
  7878.             if ((x < 0) > (x > 2000000000))
  7879.             {
  7880.                 config_error("%s:%i: set::default-bantime: value '%ld' out of range",
  7881.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
  7882.                 errors++;
  7883.             }
  7884.         }
  7885.         else if (!strcmp(cep->ce_varname, "ban-version-tkl-time")) {
  7886.             long x;
  7887.             CheckDuplicate(cep, ban_version_tkl_time, "ban-version-tkl-time");
  7888.             CheckNull(cep);
  7889.             x = config_checkval(cep->ce_vardata,CFG_TIME);
  7890.             if ((x < 0) > (x > 2000000000))
  7891.             {
  7892.                 config_error("%s:%i: set::ban-version-tkl-time: value '%ld' out of range",
  7893.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
  7894.                 errors++;
  7895.             }
  7896.         }
  7897.         else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
  7898.             int v;
  7899.             CheckDuplicate(cep, modef_default_unsettime, "modef-default-unsettime");
  7900.             CheckNull(cep);
  7901.             v = atoi(cep->ce_vardata);
  7902.             if ((v <= 0) || (v > 255))
  7903.             {
  7904.                 config_error("%s:%i: set::modef-default-unsettime: value '%d' out of range (should be 1-255)",
  7905.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
  7906.                 errors++;
  7907.             }
  7908.         }
  7909.         else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
  7910.             int v;
  7911.             CheckDuplicate(cep, modef_max_unsettime, "modef-max-unsettime");
  7912.             CheckNull(cep);
  7913.             v = atoi(cep->ce_vardata);
  7914.             if ((v <= 0) || (v > 255))
  7915.             {
  7916.                 config_error("%s:%i: set::modef-max-unsettime: value '%d' out of range (should be 1-255)",
  7917.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
  7918.                 errors++;
  7919.             }
  7920.         }
  7921.         else if (!strcmp(cep->ce_varname, "nick-length")) {
  7922.             int v;
  7923.             CheckDuplicate(cep, nicklen, "nick-length");
  7924.             CheckNull(cep);
  7925.             v = atoi(cep->ce_vardata);
  7926.             if ((v <= 0) || (v > NICKLEN))
  7927.             {
  7928.                 config_error("%s:%i: set::nick-length: value '%d' out of range (should be 1-%d)",
  7929.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v, NICKLEN);
  7930.                 errors++;
  7931.             }
  7932.         }
  7933.         else if (!strcmp(cep->ce_varname, "ssl")) {
  7934.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  7935.                 if (!strcmp(cepp->ce_varname, "egd")) {
  7936.                     CheckDuplicate(cep, ssl_egd, "ssl::egd");
  7937.                 }
  7938.                 else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
  7939.                 {
  7940.                     CheckDuplicate(cep, renegotiate_timeout, "ssl::renegotiate-timeout");
  7941.                 }
  7942.                 else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
  7943.                 {
  7944.                     CheckDuplicate(cep, renegotiate_bytes, "ssl::renegotiate-bytes");
  7945.                 }
  7946.                 else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
  7947.                 {
  7948.                     CheckNull(cepp);
  7949.                     CheckDuplicate(cep, ssl_server_cipher_list, "ssl::server-cipher-list");
  7950.                 }
  7951.                 else if (!strcmp(cepp->ce_varname, "certificate"))
  7952.                 {
  7953.                     CheckNull(cepp);
  7954.                     CheckDuplicate(cep, ssl_certificate, "ssl::certificate");
  7955.                 }
  7956.                 else if (!strcmp(cepp->ce_varname, "dh"))
  7957.                 {
  7958.                     CheckNull(cepp);
  7959.                     CheckDuplicate(cep, ssl_dh, "ssl::dh");
  7960.                 }
  7961.                 else if (!strcmp(cepp->ce_varname, "key"))
  7962.                 {
  7963.                     CheckNull(cepp);
  7964.                     CheckDuplicate(cep, ssl_key, "ssl::key");
  7965.                 }
  7966.                 else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
  7967.                 {
  7968.                     CheckNull(cepp);
  7969.                     CheckDuplicate(cep, ssl_trusted_ca_file, "ssl::trusted-ca-file");
  7970.                 }
  7971.                 else if (!strcmp(cepp->ce_varname, "options"))
  7972.                 {
  7973.                     CheckDuplicate(cep, ssl_options, "ssl::options");
  7974.                     for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
  7975.                         if (!config_binary_flags_search(_SSLFlags, ceppp->ce_varname, ARRAY_SIZEOF(_SSLFlags)))
  7976.                         {
  7977.                             config_error("%s:%i: unknown SSL flag '%s'",
  7978.                                      ceppp->ce_fileptr->cf_filename,
  7979.                                      ceppp->ce_varlinenum, ceppp->ce_varname);
  7980.                             errors ++;
  7981.                         }
  7982.                 }
  7983.                 else
  7984.                 {
  7985.                     config_error("%s:%i: unknown directive set::ssl::%s",
  7986.                         cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
  7987.                         cepp->ce_varname);
  7988.                     errors++;
  7989.                 }
  7990.             }
  7991.         }
  7992.         else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
  7993.         {
  7994.             /* keep this in sync with _test_allow() */
  7995.             int ipv6mask;
  7996.             ipv6mask = atoi(cep->ce_vardata);
  7997.             if (ipv6mask == 0)
  7998.             {
  7999.                 config_error("%s:%d: set::default-ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
  8000.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  8001.                 errors++;
  8002.             }
  8003.             if (ipv6mask > 128)
  8004.             {
  8005.                 config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
  8006.                          cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  8007.                          ipv6mask);
  8008.                 errors++;
  8009.             }
  8010.             if (ipv6mask <= 32)
  8011.             {
  8012.                 config_warn("%s:%d: set::default-ipv6-clone-mask was given a very small value.",
  8013.                         cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  8014.             }
  8015.         }
  8016.         else
  8017.         {
  8018.             int used = 0;
  8019.             for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  8020.             {
  8021.                 int value, errs = 0;
  8022.                 if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
  8023.                                 !(h->owner->options & MOD_OPT_PERM))
  8024.                     continue;
  8025.                 value = (*(h->func.intfunc))(conf,cep,CONFIG_SET, &errs);
  8026.                 if (value == 2)
  8027.                     used = 1;
  8028.                 if (value == 1)
  8029.                 {
  8030.                     used = 1;
  8031.                     break;
  8032.                 }
  8033.                 if (value == -1)
  8034.                 {
  8035.                     used = 1;
  8036.                     errors += errs;
  8037.                     break;
  8038.                 }
  8039.                 if (value == -2)
  8040.                 {
  8041.                     used = 1;
  8042.                     errors += errs;
  8043.                 }
  8044.             }
  8045.             if (!used) {
  8046.                 config_error("%s:%i: unknown directive set::%s",
  8047.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  8048.                     cep->ce_varname);
  8049.                 errors++;
  8050.             }
  8051.         }
  8052.     }
  8053.     return errors;
  8054. }
  8055.  
  8056. int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce)
  8057. {
  8058.     char *ret;
  8059.     if (!ce->ce_vardata)
  8060.     {
  8061.         config_status("%s:%i: loadmodule without filename",
  8062.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8063.         return -1;
  8064.     }
  8065.     if (strstr(ce->ce_vardata, "commands.so") || strstr(ce->ce_vardata, "commands.dll"))
  8066.     {
  8067.         config_error("%s:%i: You are trying to load the 'commands' module, this is no longer supported. "
  8068.                      "Fix this by editing your configuration file: remove the loadmodule line for commands and add the following line instead: "
  8069.                      "include \"modules.default.conf\";",
  8070.                      ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8071.         need_34_upgrade = 1;
  8072.         return -1;
  8073.     }
  8074.     if (strstr(ce->ce_vardata, "modules/cloak") && !strcmp(conf->cf_filename, "modules.conf"))
  8075.     {
  8076.         config_error("You seem to have an include for 'modules.conf'.");
  8077.         config_error("If you have this because you are upgrading from 3.4-alpha3 to");
  8078.         config_error("UnrealIRCd 4 then please change the include \"modules.conf\";");
  8079.         config_error("into an include \"modules.default.conf\"; (probably in your");
  8080.         config_error("conf/unrealircd.conf). Yeah, we changed the file name.");
  8081.         // TODO ^: silly win32 wrapping prevents this from being displayed otherwise. PLZ FIX! !
  8082.         /* let it continue to load anyway? */
  8083.     }
  8084.     if ((ret = Module_Create(ce->ce_vardata))) {
  8085.         config_status("%s:%i: loadmodule %s: failed to load: %s",
  8086.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8087.             ce->ce_vardata, ret);
  8088.         return -1;
  8089.     }
  8090.     return 1;
  8091. }
  8092.  
  8093. int _test_loadmodule(ConfigFile *conf, ConfigEntry *ce)
  8094. {
  8095.     return 0;
  8096. }
  8097.  
  8098. void start_listeners(void)
  8099. {
  8100.     ConfigItem_listen   *listenptr;
  8101.     int failed = 0, ports_bound = 0;
  8102.     char boundmsg_ipv4[512], boundmsg_ipv6[512];
  8103.    
  8104.     *boundmsg_ipv4 = *boundmsg_ipv6 = '\0';
  8105.  
  8106.     for (listenptr = conf_listen; listenptr; listenptr = (ConfigItem_listen *) listenptr->next)
  8107.     {
  8108.         /* Try to bind to any ports that are not yet bound and not marked as temporary */
  8109.         if (!(listenptr->options & LISTENER_BOUND) && !listenptr->flag.temporary)
  8110.         {
  8111.             if (add_listener2(listenptr) == -1)
  8112.             {
  8113.                 ircd_log(LOG_ERROR, "Failed to bind to %s:%i", listenptr->ip, listenptr->port);
  8114.                 failed = 1;
  8115.             } else {
  8116.                 if (loop.ircd_booted)
  8117.                 {
  8118.                     ircd_log(LOG_ERROR, "UnrealIRCd is now also listening on %s:%d (%s)%s",
  8119.                         listenptr->ip, listenptr->port,
  8120.                         listenptr->ipv6 ? "IPv6" : "IPv4",
  8121.                         listenptr->options & LISTENER_SSL ? " (SSL)" : "");
  8122.                 } else {
  8123.                     if (listenptr->ipv6)
  8124.                         snprintf(boundmsg_ipv6+strlen(boundmsg_ipv6), sizeof(boundmsg_ipv6)-strlen(boundmsg_ipv6),
  8125.                             "%s:%d%s, ", listenptr->ip, listenptr->port,
  8126.                             listenptr->options & LISTENER_SSL ? "(SSL)" : "");
  8127.                     else
  8128.                         snprintf(boundmsg_ipv4+strlen(boundmsg_ipv4), sizeof(boundmsg_ipv4)-strlen(boundmsg_ipv4),
  8129.                             "%s:%d%s, ", listenptr->ip, listenptr->port,
  8130.                             listenptr->options & LISTENER_SSL ? "(SSL)" : "");
  8131.                 }
  8132.             }
  8133.         }
  8134.  
  8135.         /* NOTE: do not merge this with code above (nor in an else block),
  8136.          * as add_listener2() affects this flag.
  8137.          */
  8138.         if (listenptr->options & LISTENER_BOUND)
  8139.             ports_bound++;
  8140.     }
  8141.  
  8142.     if (ports_bound == 0)
  8143.     {
  8144.         ircd_log(LOG_ERROR, "IRCd could not listen on any ports. If you see 'Address already in use' errors "
  8145.                             "above then most likely the IRCd is already running (or something else is using the "
  8146.                             "specified ports). If you are sure the IRCd is not running then verify your "
  8147.                             "listen blocks, maybe you have to bind to a specific IP rather than \"*\".");
  8148.         exit(-1);
  8149.     }
  8150.    
  8151.     if (failed && !loop.ircd_booted)
  8152.     {
  8153.         ircd_log(LOG_ERROR, "Could not listen on all specified addresses/ports. See errors above. "
  8154.                             "Please fix your listen { } blocks and/or make sure no other programs "
  8155.                             "are listening on the same port.");
  8156.         exit(-1);
  8157.     }
  8158.  
  8159.     if (!loop.ircd_booted)
  8160.     {
  8161.         if (strlen(boundmsg_ipv4) > 2)
  8162.             boundmsg_ipv4[strlen(boundmsg_ipv4)-2] = '\0';
  8163.         if (strlen(boundmsg_ipv6) > 2)
  8164.             boundmsg_ipv6[strlen(boundmsg_ipv6)-2] = '\0';
  8165.  
  8166.         ircd_log(LOG_ERROR, "UnrealIRCd is now listening on the following addresses/ports:");
  8167.         ircd_log(LOG_ERROR, "IPv4: %s", *boundmsg_ipv4 ? boundmsg_ipv4 : "<none>");
  8168.         ircd_log(LOG_ERROR, "IPv6: %s", *boundmsg_ipv6 ? boundmsg_ipv6 : "<none>");
  8169.     }
  8170. }
  8171.  
  8172. /* Actually use configuration */
  8173. void run_configuration(void)
  8174. {
  8175.     start_listeners();
  8176. }
  8177.  
  8178. int _conf_offchans(ConfigFile *conf, ConfigEntry *ce)
  8179. {
  8180.     ConfigEntry *cep, *cepp;
  8181.  
  8182.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8183.     {
  8184.         ConfigItem_offchans *of = MyMallocEx(sizeof(ConfigItem_offchans));
  8185.         strlcpy(of->chname, cep->ce_varname, CHANNELLEN+1);
  8186.         for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
  8187.         {
  8188.             if (!strcmp(cepp->ce_varname, "topic"))
  8189.                 of->topic = strdup(cepp->ce_vardata);
  8190.         }
  8191.         AddListItem(of, conf_offchans);
  8192.     }
  8193.     return 0;
  8194. }
  8195.  
  8196. int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
  8197. {
  8198.     int errors = 0;
  8199.     ConfigEntry *cep, *cep2;
  8200.     char checkchan[CHANNELLEN + 1];
  8201.  
  8202.     if (!ce->ce_entries)
  8203.     {
  8204.         config_error("%s:%i: empty official-channels block",
  8205.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8206.         return 1;
  8207.     }
  8208.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8209.     {
  8210.         if (strlen(cep->ce_varname) > CHANNELLEN)
  8211.         {
  8212.             config_error("%s:%i: official-channels: '%s' name too long (max %d characters).",
  8213.                 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname, CHANNELLEN);
  8214.             errors++;
  8215.             continue;
  8216.         }
  8217.         strcpy(checkchan, cep->ce_varname); /* safe */
  8218.         clean_channelname(checkchan);
  8219.         if (strcmp(checkchan, cep->ce_varname) || (*cep->ce_varname != '#'))
  8220.         {
  8221.             config_error("%s:%i: official-channels: '%s' is not a valid channel name.",
  8222.                 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
  8223.             errors++;
  8224.             continue;
  8225.         }
  8226.         for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
  8227.         {
  8228.             if (!cep2->ce_vardata)
  8229.             {
  8230.                 config_error_empty(cep2->ce_fileptr->cf_filename,
  8231.                     cep2->ce_varlinenum, "official-channels",
  8232.                     cep2->ce_varname);
  8233.                 errors++;
  8234.                 continue;
  8235.             }
  8236.             if (!strcmp(cep2->ce_varname, "topic"))
  8237.             {
  8238.                 if (strlen(cep2->ce_vardata) > TOPICLEN)
  8239.                 {
  8240.                     config_error("%s:%i: official-channels::%s: topic too long (max %d characters).",
  8241.                         cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname, TOPICLEN);
  8242.                     errors++;
  8243.                     continue;
  8244.                 }
  8245.             } else {
  8246.                 config_error_unknown(cep2->ce_fileptr->cf_filename,
  8247.                     cep2->ce_varlinenum, "official-channels",
  8248.                     cep2->ce_varname);
  8249.                 errors++;
  8250.                 continue;
  8251.             }
  8252.         }
  8253.     }
  8254.     return errors;
  8255. }
  8256.  
  8257. int _conf_alias(ConfigFile *conf, ConfigEntry *ce)
  8258. {
  8259.     ConfigItem_alias *alias = NULL;
  8260.     ConfigItem_alias_format *format;
  8261.     ConfigEntry             *cep, *cepp;
  8262.     aCommand *cmptr;
  8263.  
  8264.     if ((cmptr = find_Command(ce->ce_vardata, 0, M_ALIAS)))
  8265.         del_Command(ce->ce_vardata, cmptr->func);
  8266.     if (find_Command_simple(ce->ce_vardata))
  8267.     {
  8268.         config_warn("%s:%i: Alias '%s' would conflict with command (or server token) '%s', alias not added.",
  8269.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8270.             ce->ce_vardata, ce->ce_vardata);
  8271.         return 0;
  8272.     }
  8273.     if ((alias = Find_alias(ce->ce_vardata)))
  8274.         DelListItem(alias, conf_alias);
  8275.     alias = MyMallocEx(sizeof(ConfigItem_alias));
  8276.     safestrdup(alias->alias, ce->ce_vardata);
  8277.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8278.     {
  8279.         if (!strcmp(cep->ce_varname, "format")) {
  8280.             format = MyMallocEx(sizeof(ConfigItem_alias_format));
  8281.             safestrdup(format->format, cep->ce_vardata);
  8282.             format->expr = unreal_create_match(MATCH_PCRE_REGEX, cep->ce_vardata, NULL);
  8283.             if (!format->expr)
  8284.                 abort(); /* Impossible due to _test_alias earlier */
  8285.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  8286.                 if (!strcmp(cepp->ce_varname, "nick") ||
  8287.                     !strcmp(cepp->ce_varname, "target") ||
  8288.                     !strcmp(cepp->ce_varname, "command")) {
  8289.                     safestrdup(format->nick, cepp->ce_vardata);
  8290.                 }
  8291.                 else if (!strcmp(cepp->ce_varname, "parameters")) {
  8292.                     safestrdup(format->parameters, cepp->ce_vardata);
  8293.                 }
  8294.                 else if (!strcmp(cepp->ce_varname, "type")) {
  8295.                     if (!strcmp(cepp->ce_vardata, "services"))
  8296.                         format->type = ALIAS_SERVICES;
  8297.                     else if (!strcmp(cepp->ce_vardata, "stats"))
  8298.                         format->type = ALIAS_STATS;
  8299.                     else if (!strcmp(cepp->ce_vardata, "normal"))
  8300.                         format->type = ALIAS_NORMAL;
  8301.                     else if (!strcmp(cepp->ce_vardata, "channel"))
  8302.                         format->type = ALIAS_CHANNEL;
  8303.                     else if (!strcmp(cepp->ce_vardata, "real"))
  8304.                         format->type = ALIAS_REAL;
  8305.                 }
  8306.             }
  8307.             AddListItem(format, alias->format);
  8308.         }
  8309.  
  8310.         else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
  8311.         {
  8312.             safestrdup(alias->nick, cep->ce_vardata);
  8313.         }
  8314.         else if (!strcmp(cep->ce_varname, "type")) {
  8315.             if (!strcmp(cep->ce_vardata, "services"))
  8316.                 alias->type = ALIAS_SERVICES;
  8317.             else if (!strcmp(cep->ce_vardata, "stats"))
  8318.                 alias->type = ALIAS_STATS;
  8319.             else if (!strcmp(cep->ce_vardata, "normal"))
  8320.                 alias->type = ALIAS_NORMAL;
  8321.             else if (!strcmp(cep->ce_vardata, "channel"))
  8322.                 alias->type = ALIAS_CHANNEL;
  8323.             else if (!strcmp(cep->ce_vardata, "command"))
  8324.                 alias->type = ALIAS_COMMAND;
  8325.         }
  8326.         else if (!strcmp(cep->ce_varname, "spamfilter"))
  8327.             alias->spamfilter = config_checkval(cep->ce_vardata, CFG_YESNO);
  8328.     }
  8329.     if (BadPtr(alias->nick) && alias->type != ALIAS_COMMAND) {
  8330.         safestrdup(alias->nick, alias->alias);
  8331.     }
  8332.     CommandAdd(NULL, alias->alias, (void *)m_alias, 1, M_USER|M_ALIAS);
  8333.    
  8334.     AddListItem(alias, conf_alias);
  8335.     return 0;
  8336. }
  8337.  
  8338.  
  8339. int _test_alias(ConfigFile *conf, ConfigEntry *ce) {
  8340.     int errors = 0;
  8341.     ConfigEntry *cep, *cepp;
  8342.     char has_type = 0, has_target = 0, has_format = 0;
  8343.     char type = 0;
  8344.  
  8345.     if (!ce->ce_entries)
  8346.     {
  8347.         config_error("%s:%i: empty alias block",
  8348.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8349.         return 1;
  8350.     }
  8351.     if (!ce->ce_vardata)
  8352.     {
  8353.         config_error("%s:%i: alias without name",
  8354.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8355.         errors++;
  8356.     }
  8357.     else if (!find_Command(ce->ce_vardata, 0, M_ALIAS) && find_Command(ce->ce_vardata, 0, 0)) {
  8358.         config_status("%s:%i: %s is an existing command, can not add alias",
  8359.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ce->ce_vardata);
  8360.         errors++;
  8361.     }
  8362.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8363.     {
  8364.         if (config_is_blankorempty(cep, "alias"))
  8365.         {
  8366.             errors++;
  8367.             continue;
  8368.         }
  8369.         if (!strcmp(cep->ce_varname, "format")) {
  8370.             char *err = NULL;
  8371.             aMatch *expr;
  8372.             char has_type = 0, has_target = 0, has_parameters = 0;
  8373.  
  8374.             has_format = 1;
  8375.             expr = unreal_create_match(MATCH_PCRE_REGEX, cep->ce_vardata, &err);
  8376.             if (!expr)
  8377.             {
  8378.                 config_error("%s:%i: alias::format contains an invalid regex: %s",
  8379.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum, err);
  8380.                 config_error("Upgrading from 3.2.x to UnrealIRCd 4? Note that regex changed from POSIX Regex "
  8381.                              "to PCRE Regex!"); /* TODO: refer to some url ? */
  8382.             } else {
  8383.                 unreal_delete_match(expr);
  8384.             }
  8385.  
  8386.             for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
  8387.                 if (config_is_blankorempty(cepp, "alias::format"))
  8388.                 {
  8389.                     errors++;
  8390.                     continue;
  8391.                 }
  8392.                 if (!strcmp(cepp->ce_varname, "nick") ||
  8393.                     !strcmp(cepp->ce_varname, "command") ||
  8394.                     !strcmp(cepp->ce_varname, "target"))
  8395.                 {
  8396.                     if (has_target)
  8397.                     {
  8398.                         config_warn_duplicate(cepp->ce_fileptr->cf_filename,
  8399.                             cepp->ce_varlinenum,
  8400.                             "alias::format::target");
  8401.                         continue;
  8402.                     }
  8403.                     has_target = 1;
  8404.                 }
  8405.                 else if (!strcmp(cepp->ce_varname, "type"))
  8406.                 {
  8407.                     if (has_type)
  8408.                     {
  8409.                         config_warn_duplicate(cepp->ce_fileptr->cf_filename,
  8410.                             cepp->ce_varlinenum,
  8411.                             "alias::format::type");
  8412.                         continue;
  8413.                     }
  8414.                     has_type = 1;
  8415.                     if (!strcmp(cepp->ce_vardata, "services"))
  8416.                         ;
  8417.                     else if (!strcmp(cepp->ce_vardata, "stats"))
  8418.                         ;
  8419.                     else if (!strcmp(cepp->ce_vardata, "normal"))
  8420.                         ;
  8421.                     else if (!strcmp(cepp->ce_vardata, "channel"))
  8422.                         ;
  8423.                     else if (!strcmp(cepp->ce_vardata, "real"))
  8424.                         ;
  8425.                     else
  8426.                     {
  8427.                         config_error("%s:%i: unknown alias type",
  8428.                         cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
  8429.                         errors++;
  8430.                     }
  8431.                 }
  8432.                 else if (!strcmp(cepp->ce_varname, "parameters"))
  8433.                 {
  8434.                     if (has_parameters)
  8435.                     {
  8436.                         config_warn_duplicate(cepp->ce_fileptr->cf_filename,
  8437.                             cepp->ce_varlinenum,
  8438.                             "alias::format::parameters");
  8439.                         continue;
  8440.                     }
  8441.                     has_parameters = 1;
  8442.                 }
  8443.                 else
  8444.                 {
  8445.                     config_error_unknown(cepp->ce_fileptr->cf_filename,
  8446.                         cepp->ce_varlinenum, "alias::format",
  8447.                         cepp->ce_varname);
  8448.                     errors++;
  8449.                 }
  8450.             }
  8451.             if (!has_target)
  8452.             {
  8453.                 config_error_missing(cep->ce_fileptr->cf_filename,
  8454.                     cep->ce_varlinenum, "alias::format::target");
  8455.                 errors++;
  8456.             }
  8457.             if (!has_type)
  8458.             {
  8459.                 config_error_missing(cep->ce_fileptr->cf_filename,
  8460.                     cep->ce_varlinenum, "alias::format::type");
  8461.                 errors++;
  8462.             }
  8463.             if (!has_parameters)
  8464.             {
  8465.                 config_error_missing(cep->ce_fileptr->cf_filename,
  8466.                     cep->ce_varlinenum, "alias::format::parameters");
  8467.                 errors++;
  8468.             }
  8469.         }
  8470.         else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
  8471.         {
  8472.             if (has_target)
  8473.             {
  8474.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8475.                     cep->ce_varlinenum, "alias::target");
  8476.                 continue;
  8477.             }
  8478.             has_target = 1;
  8479.         }
  8480.         else if (!strcmp(cep->ce_varname, "type")) {
  8481.             if (has_type)
  8482.             {
  8483.                 config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8484.                     cep->ce_varlinenum, "alias::type");
  8485.                 continue;
  8486.             }
  8487.             has_type = 1;
  8488.             if (!strcmp(cep->ce_vardata, "services"))
  8489.                 ;
  8490.             else if (!strcmp(cep->ce_vardata, "stats"))
  8491.                 ;
  8492.             else if (!strcmp(cep->ce_vardata, "normal"))
  8493.                 ;
  8494.             else if (!strcmp(cep->ce_vardata, "channel"))
  8495.                 ;
  8496.             else if (!strcmp(cep->ce_vardata, "command"))
  8497.                 type = 'c';
  8498.             else {
  8499.                 config_error("%s:%i: unknown alias type",
  8500.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  8501.                 errors++;
  8502.             }
  8503.         }
  8504.         else if (!strcmp(cep->ce_varname, "spamfilter"))
  8505.             ;
  8506.         else {
  8507.             config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
  8508.                 "alias", cep->ce_varname);
  8509.             errors++;
  8510.         }
  8511.     }
  8512.     if (!has_type)
  8513.     {
  8514.         config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8515.             "alias::type");
  8516.         errors++;
  8517.     }
  8518.     if (!has_format && type == 'c')
  8519.     {
  8520.         config_error("%s:%d: alias::type is 'command' but no alias::format was specified",
  8521.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8522.         errors++;
  8523.     }
  8524.     else if (has_format && type != 'c')
  8525.     {
  8526.         config_error("%s:%d: alias::format specified when type is not 'command'",
  8527.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8528.         errors++;
  8529.     }
  8530.     return errors;
  8531. }
  8532.  
  8533. int _conf_deny(ConfigFile *conf, ConfigEntry *ce)
  8534. {
  8535. Hook *h;
  8536.  
  8537.     if (!strcmp(ce->ce_vardata, "dcc"))
  8538.         _conf_deny_dcc(conf, ce);
  8539.     else if (!strcmp(ce->ce_vardata, "channel"))
  8540.         _conf_deny_channel(conf, ce);
  8541.     else if (!strcmp(ce->ce_vardata, "link"))
  8542.         _conf_deny_link(conf, ce);
  8543.     else if (!strcmp(ce->ce_vardata, "version"))
  8544.         _conf_deny_version(conf, ce);
  8545.     else
  8546.     {
  8547.         int value;
  8548.         for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
  8549.         {
  8550.             value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY);
  8551.             if (value == 1)
  8552.                 break;
  8553.         }
  8554.         return 0;
  8555.     }
  8556.     return 0;
  8557. }
  8558.  
  8559. int _conf_deny_dcc(ConfigFile *conf, ConfigEntry *ce)
  8560. {
  8561.     ConfigItem_deny_dcc     *deny = NULL;
  8562.     ConfigEntry             *cep;
  8563.  
  8564.     deny = MyMallocEx(sizeof(ConfigItem_deny_dcc));
  8565.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8566.     {
  8567.         if (!strcmp(cep->ce_varname, "filename"))
  8568.         {
  8569.             safestrdup(deny->filename, cep->ce_vardata);
  8570.         }
  8571.         else if (!strcmp(cep->ce_varname, "reason"))
  8572.         {
  8573.             safestrdup(deny->reason, cep->ce_vardata);
  8574.         }
  8575.         else if (!strcmp(cep->ce_varname, "soft"))
  8576.         {
  8577.             int x = config_checkval(cep->ce_vardata,CFG_YESNO);
  8578.             if (x == 1)
  8579.                 deny->flag.type = DCCDENY_SOFT;
  8580.         }
  8581.     }
  8582.     if (!deny->reason)
  8583.     {
  8584.         if (deny->flag.type == DCCDENY_HARD)
  8585.             safestrdup(deny->reason, "Possible infected virus file");
  8586.         else
  8587.             safestrdup(deny->reason, "Possible executable content");
  8588.     }
  8589.     AddListItem(deny, conf_deny_dcc);
  8590.     return 0;
  8591. }
  8592.  
  8593. int _conf_deny_channel(ConfigFile *conf, ConfigEntry *ce)
  8594. {
  8595.     ConfigItem_deny_channel     *deny = NULL;
  8596.     ConfigEntry             *cep;
  8597.  
  8598.     deny = MyMallocEx(sizeof(ConfigItem_deny_channel));
  8599.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8600.     {
  8601.         if (!strcmp(cep->ce_varname, "channel"))
  8602.         {
  8603.             safestrdup(deny->channel, cep->ce_vardata);
  8604.         }
  8605.         else if (!strcmp(cep->ce_varname, "redirect"))
  8606.         {
  8607.             safestrdup(deny->redirect, cep->ce_vardata);
  8608.         }
  8609.         else if (!strcmp(cep->ce_varname, "reason"))
  8610.         {
  8611.             safestrdup(deny->reason, cep->ce_vardata);
  8612.         }
  8613.         else if (!strcmp(cep->ce_varname, "warn"))
  8614.         {
  8615.             deny->warn = config_checkval(cep->ce_vardata,CFG_YESNO);
  8616.         }
  8617.         else if (!strcmp(cep->ce_varname, "class"))
  8618.         {
  8619.             safestrdup(deny->class, cep->ce_vardata);
  8620.         }
  8621.     }
  8622.     AddListItem(deny, conf_deny_channel);
  8623.     return 0;
  8624. }
  8625. int _conf_deny_link(ConfigFile *conf, ConfigEntry *ce)
  8626. {
  8627.     ConfigItem_deny_link    *deny = NULL;
  8628.     ConfigEntry             *cep;
  8629.  
  8630.     deny = MyMallocEx(sizeof(ConfigItem_deny_link));
  8631.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8632.     {
  8633.         if (!strcmp(cep->ce_varname, "mask"))
  8634.         {
  8635.             safestrdup(deny->mask, cep->ce_vardata);
  8636.         }
  8637.         else if (!strcmp(cep->ce_varname, "rule"))
  8638.         {
  8639.             deny->rule = (char *)crule_parse(cep->ce_vardata);
  8640.             safestrdup(deny->prettyrule, cep->ce_vardata);
  8641.         }
  8642.         else if (!strcmp(cep->ce_varname, "type")) {
  8643.             if (!strcmp(cep->ce_vardata, "all"))
  8644.                 deny->flag.type = CRULE_ALL;
  8645.             else if (!strcmp(cep->ce_vardata, "auto"))
  8646.                 deny->flag.type = CRULE_AUTO;
  8647.         }
  8648.     }
  8649.     AddListItem(deny, conf_deny_link);
  8650.     return 0;
  8651. }
  8652.  
  8653. int _conf_deny_version(ConfigFile *conf, ConfigEntry *ce)
  8654. {
  8655.     ConfigItem_deny_version *deny = NULL;
  8656.     ConfigEntry             *cep;
  8657.  
  8658.     deny = MyMallocEx(sizeof(ConfigItem_deny_version));
  8659.     for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8660.     {
  8661.         if (!strcmp(cep->ce_varname, "mask"))
  8662.         {
  8663.             safestrdup(deny->mask, cep->ce_vardata);
  8664.         }
  8665.         else if (!strcmp(cep->ce_varname, "version"))
  8666.         {
  8667.             safestrdup(deny->version, cep->ce_vardata);
  8668.         }
  8669.         else if (!strcmp(cep->ce_varname, "flags"))
  8670.         {
  8671.             safestrdup(deny->flags, cep->ce_vardata);
  8672.         }
  8673.     }
  8674.     AddListItem(deny, conf_deny_version);
  8675.     return 0;
  8676. }
  8677.  
  8678. int     _test_deny(ConfigFile *conf, ConfigEntry *ce)
  8679. {
  8680.     ConfigEntry *cep;
  8681.     int     errors = 0;
  8682.     Hook    *h;
  8683.  
  8684.     if (!ce->ce_vardata)
  8685.     {
  8686.         config_error("%s:%i: deny without type",
  8687.             ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  8688.         return 1;
  8689.     }
  8690.     if (!strcmp(ce->ce_vardata, "dcc"))
  8691.     {
  8692.         char has_filename = 0, has_reason = 0, has_soft = 0;
  8693.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8694.         {
  8695.             if (config_is_blankorempty(cep, "deny dcc"))
  8696.             {
  8697.                 errors++;
  8698.                 continue;
  8699.             }
  8700.             if (!strcmp(cep->ce_varname, "filename"))
  8701.             {
  8702.                 if (has_filename)
  8703.                 {
  8704.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8705.                         cep->ce_varlinenum, "deny dcc::filename");
  8706.                     continue;
  8707.                 }
  8708.                 has_filename = 1;
  8709.             }
  8710.             else if (!strcmp(cep->ce_varname, "reason"))
  8711.             {
  8712.                 if (has_reason)
  8713.                 {
  8714.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8715.                         cep->ce_varlinenum, "deny dcc::reason");
  8716.                     continue;
  8717.                 }
  8718.                 has_reason = 1;
  8719.             }
  8720.             else if (!strcmp(cep->ce_varname, "soft"))
  8721.             {
  8722.                 if (has_soft)
  8723.                 {
  8724.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8725.                         cep->ce_varlinenum, "deny dcc::soft");
  8726.                     continue;
  8727.                 }
  8728.                 has_soft = 1;
  8729.             }
  8730.             else
  8731.             {
  8732.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  8733.                     cep->ce_varlinenum, "deny dcc", cep->ce_varname);
  8734.                 errors++;
  8735.             }
  8736.         }
  8737.         if (!has_filename)
  8738.         {
  8739.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8740.                 "deny dcc::filename");
  8741.             errors++;
  8742.         }
  8743.         if (!has_reason)
  8744.         {
  8745.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8746.                 "deny dcc::reason");
  8747.             errors++;
  8748.         }
  8749.     }
  8750.     else if (!strcmp(ce->ce_vardata, "channel"))
  8751.     {
  8752.         char has_channel = 0, has_warn = 0, has_reason = 0, has_redirect = 0, has_class = 0;
  8753.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8754.         {
  8755.             if (config_is_blankorempty(cep, "deny channel"))
  8756.             {
  8757.                 errors++;
  8758.                 continue;
  8759.             }
  8760.             if (!strcmp(cep->ce_varname, "channel"))
  8761.             {
  8762.                 if (has_channel)
  8763.                 {
  8764.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8765.                         cep->ce_varlinenum, "deny channel::channel");
  8766.                     continue;
  8767.                 }
  8768.                 has_channel = 1;
  8769.             }
  8770.             else if (!strcmp(cep->ce_varname, "redirect"))
  8771.             {
  8772.                 if (has_redirect)
  8773.                 {
  8774.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8775.                         cep->ce_varlinenum, "deny channel::redirect");
  8776.                     continue;
  8777.                 }
  8778.                 has_redirect = 1;
  8779.             }
  8780.             else if (!strcmp(cep->ce_varname, "reason"))
  8781.             {
  8782.                 if (has_reason)
  8783.                 {
  8784.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8785.                         cep->ce_varlinenum, "deny channel::reason");
  8786.                     continue;
  8787.                 }
  8788.                 has_reason = 1;
  8789.             }
  8790.             else if (!strcmp(cep->ce_varname, "warn"))
  8791.             {
  8792.                 if (has_warn)
  8793.                 {
  8794.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8795.                         cep->ce_varlinenum, "deny channel::warn");
  8796.                     continue;
  8797.                 }
  8798.                 has_warn = 1;
  8799.             }
  8800.             else if (!strcmp(cep->ce_varname, "class"))
  8801.             {
  8802.                 if (has_class)
  8803.                 {
  8804.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8805.                         cep->ce_varlinenum, "deny channel::class");
  8806.                     continue;
  8807.                 }
  8808.                 has_class = 1;
  8809.             }
  8810.             else
  8811.             {
  8812.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  8813.                     cep->ce_varlinenum, "deny channel", cep->ce_varname);
  8814.                 errors++;
  8815.             }
  8816.         }
  8817.         if (!has_channel)
  8818.         {
  8819.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8820.                 "deny channel::channel");
  8821.             errors++;
  8822.         }
  8823.         if (!has_reason)
  8824.         {
  8825.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8826.                 "deny channel::reason");
  8827.             errors++;
  8828.         }
  8829.     }
  8830.     else if (!strcmp(ce->ce_vardata, "link"))
  8831.     {
  8832.         char has_mask = 0, has_rule = 0, has_type = 0;
  8833.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8834.         {
  8835.             if (config_is_blankorempty(cep, "deny link"))
  8836.             {
  8837.                 errors++;
  8838.                 continue;
  8839.             }
  8840.             if (!strcmp(cep->ce_varname, "mask"))
  8841.             {
  8842.                 if (has_mask)
  8843.                 {
  8844.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8845.                         cep->ce_varlinenum, "deny link::mask");
  8846.                     continue;
  8847.                 }
  8848.                 has_mask = 1;
  8849.             }
  8850.             else if (!strcmp(cep->ce_varname, "rule"))
  8851.             {
  8852.                 int val = 0;
  8853.                 if (has_rule)
  8854.                 {
  8855.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8856.                         cep->ce_varlinenum, "deny link::rule");
  8857.                     continue;
  8858.                 }
  8859.                 has_rule = 1;
  8860.                 if ((val = crule_test(cep->ce_vardata)))
  8861.                 {
  8862.                     config_error("%s:%i: deny link::rule contains an invalid expression: %s",
  8863.                         cep->ce_fileptr->cf_filename,
  8864.                         cep->ce_varlinenum,
  8865.                         crule_errstring(val));
  8866.                     errors++;
  8867.                 }
  8868.             }
  8869.             else if (!strcmp(cep->ce_varname, "type"))
  8870.             {
  8871.                 if (has_type)
  8872.                 {
  8873.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8874.                         cep->ce_varlinenum, "deny link::type");
  8875.                     continue;
  8876.                 }
  8877.                 has_type = 1;
  8878.                 if (!strcmp(cep->ce_vardata, "auto"))
  8879.                 ;
  8880.                 else if (!strcmp(cep->ce_vardata, "all"))
  8881.                 ;
  8882.                 else {
  8883.                     config_status("%s:%i: unknown deny link type",
  8884.                     cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
  8885.                     errors++;
  8886.                 }
  8887.             }
  8888.             else
  8889.             {
  8890.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  8891.                     cep->ce_varlinenum, "deny link", cep->ce_varname);
  8892.                 errors++;
  8893.             }
  8894.         }
  8895.         if (!has_mask)
  8896.         {
  8897.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8898.                 "deny link::mask");
  8899.             errors++;
  8900.         }
  8901.         if (!has_rule)
  8902.         {
  8903.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8904.                 "deny link::rule");
  8905.             errors++;
  8906.         }
  8907.         if (!has_type)
  8908.         {
  8909.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8910.                 "deny link::type");
  8911.             errors++;
  8912.         }
  8913.     }
  8914.     else if (!strcmp(ce->ce_vardata, "version"))
  8915.     {
  8916.         char has_mask = 0, has_version = 0, has_flags = 0;
  8917.         for (cep = ce->ce_entries; cep; cep = cep->ce_next)
  8918.         {
  8919.             if (config_is_blankorempty(cep, "deny version"))
  8920.             {
  8921.                 errors++;
  8922.                 continue;
  8923.             }
  8924.             if (!strcmp(cep->ce_varname, "mask"))
  8925.             {
  8926.                 if (has_mask)
  8927.                 {
  8928.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8929.                         cep->ce_varlinenum, "deny version::mask");
  8930.                     continue;
  8931.                 }
  8932.                 has_mask = 1;
  8933.             }
  8934.             else if (!strcmp(cep->ce_varname, "version"))
  8935.             {
  8936.                 if (has_version)
  8937.                 {
  8938.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8939.                         cep->ce_varlinenum, "deny version::version");
  8940.                     continue;
  8941.                 }
  8942.                 has_version = 1;
  8943.             }
  8944.             else if (!strcmp(cep->ce_varname, "flags"))
  8945.             {
  8946.                 if (has_flags)
  8947.                 {
  8948.                     config_warn_duplicate(cep->ce_fileptr->cf_filename,
  8949.                         cep->ce_varlinenum, "deny version::flags");
  8950.                     continue;
  8951.                 }
  8952.                 has_flags = 1;
  8953.             }
  8954.             else
  8955.             {
  8956.                 config_error_unknown(cep->ce_fileptr->cf_filename,
  8957.                     cep->ce_varlinenum, "deny version", cep->ce_varname);
  8958.                 errors++;
  8959.             }
  8960.         }
  8961.         if (!has_mask)
  8962.         {
  8963.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8964.                 "deny version::mask");
  8965.             errors++;
  8966.         }
  8967.         if (!has_version)
  8968.         {
  8969.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8970.                 "deny version::version");
  8971.             errors++;
  8972.         }
  8973.         if (!has_flags)
  8974.         {
  8975.             config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  8976.                 "deny version::flags");
  8977.             errors++;
  8978.         }
  8979.     }
  8980.     else
  8981.     {
  8982.         int used = 0;
  8983.         for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
  8984.         {
  8985.             int value, errs = 0;
  8986.             if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
  8987.                 && !(h->owner->options & MOD_OPT_PERM))
  8988.                 continue;
  8989.             value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY, &errs);
  8990.             if (value == 2)
  8991.                 used = 1;
  8992.             if (value == 1)
  8993.             {
  8994.                 used = 1;
  8995.                 break;
  8996.             }
  8997.             if (value == -1)
  8998.             {
  8999.                 used = 1;
  9000.                 errors += errs;
  9001.                 break;
  9002.             }
  9003.             if (value == -2)
  9004.             {
  9005.                 used = 1;
  9006.                 errors += errs;
  9007.             }
  9008.         }
  9009.         if (!used) {
  9010.             config_error("%s:%i: unknown deny type %s",
  9011.                 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  9012.                 ce->ce_vardata);
  9013.             return 1;
  9014.         }
  9015.         return errors;
  9016.     }
  9017.  
  9018.     return errors;
  9019. }
  9020.  
  9021. #ifdef USE_LIBCURL
  9022. static void conf_download_complete(const char *url, const char *file, const char *errorbuf, int cached, void *inc_key)
  9023. {
  9024.     ConfigItem_include *inc;
  9025.     if (!loop.ircd_rehashing)
  9026.         return;
  9027.  
  9028.     /*
  9029.       use inc_key to find the correct include block. This
  9030.       should be cheaper than using the full URL.
  9031.      */
  9032.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9033.     {
  9034.         if ( inc_key != (void *)inc )
  9035.             continue;
  9036.         if (!(inc->flag.type & INCLUDE_REMOTE))
  9037.             continue;
  9038.         if (inc->flag.type & INCLUDE_NOTLOADED)
  9039.             continue;
  9040.         if (stricmp(url, inc->url))
  9041.             continue;
  9042.  
  9043.         inc->flag.type &= ~INCLUDE_DLQUEUED;
  9044.         break;
  9045.     }
  9046.     if (!inc)
  9047.     {
  9048.         ircd_log(LOG_ERROR, "Downloaded remote include which matches no include statement.");
  9049.         return;
  9050.     }
  9051.  
  9052.     if (!file && !cached)
  9053.         update_remote_include(inc, file, 0, errorbuf); /* DOWNLOAD FAILED */
  9054.     else
  9055.     {
  9056.         char *urlfile = url_getfilename(url);
  9057.         char *file_basename = unreal_getfilename(urlfile);
  9058.         char *tmp = unreal_mktemp(TMPDIR, file_basename ? file_basename : "download.conf");
  9059.         free(urlfile);
  9060.  
  9061.         if (cached)
  9062.         {
  9063.             unreal_copyfileex(inc->file, tmp, 1);
  9064. #ifdef REMOTEINC_SPECIALCACHE
  9065.             unreal_copyfileex(inc->file, unreal_mkcache(url), 0);
  9066. #endif
  9067.             update_remote_include(inc, tmp, 0, NULL);
  9068.         }
  9069.         else
  9070.         {
  9071.             /*
  9072.               copy/hardlink file to another file because our caller will
  9073.               remove(file).
  9074.             */
  9075.             unreal_copyfileex(file, tmp, 1);
  9076.             update_remote_include(inc, tmp, 0, NULL);
  9077. #ifdef REMOTEINC_SPECIALCACHE
  9078.             unreal_copyfileex(file, unreal_mkcache(url), 0);
  9079. #endif
  9080.         }
  9081.     }
  9082.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9083.     {
  9084.         if (inc->flag.type & INCLUDE_DLQUEUED)
  9085.             return;
  9086.     }
  9087.     rehash_internal(loop.rehash_save_cptr, loop.rehash_save_sptr, loop.rehash_save_sig);
  9088. }
  9089. #endif
  9090.  
  9091. int     rehash(aClient *cptr, aClient *sptr, int sig)
  9092. {
  9093. #ifdef USE_LIBCURL
  9094.     ConfigItem_include *inc;
  9095.     char found_remote = 0;
  9096.     if (loop.ircd_rehashing)
  9097.     {
  9098.         if (!sig)
  9099.             sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress",
  9100.                 me.name, sptr->name);
  9101.         return 0;
  9102.     }
  9103.  
  9104.     loop.ircd_rehashing = 1;
  9105.     loop.rehash_save_cptr = cptr;
  9106.     loop.rehash_save_sptr = sptr;
  9107.     loop.rehash_save_sig = sig;
  9108.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9109.     {
  9110.         time_t modtime;
  9111.         if (!(inc->flag.type & INCLUDE_REMOTE))
  9112.             continue;
  9113.  
  9114.         if (inc->flag.type & INCLUDE_NOTLOADED)
  9115.             continue;
  9116.         found_remote = 1;
  9117.         modtime = unreal_getfilemodtime(inc->file);
  9118.         inc->flag.type |= INCLUDE_DLQUEUED;
  9119.  
  9120.         /*
  9121.           use (void *)inc as the key for finding which
  9122.           include block conf_download_complete() should use.
  9123.         */
  9124.         download_file_async(inc->url, modtime, conf_download_complete, (void *)inc);
  9125.     }
  9126.     if (!found_remote)
  9127.         return rehash_internal(cptr, sptr, sig);
  9128.     return 0;
  9129. #else
  9130.     loop.ircd_rehashing = 1;
  9131.     return rehash_internal(cptr, sptr, sig);
  9132. #endif
  9133. }
  9134.  
  9135. int rehash_internal(aClient *cptr, aClient *sptr, int sig)
  9136. {
  9137.     if (sig == 1)
  9138.     {
  9139.         sendto_ops("Got signal SIGHUP, reloading %s file", configfile);
  9140. #ifdef  ULTRIX
  9141.         if (fork() > 0)
  9142.             exit(0);
  9143.         write_pidfile();
  9144. #endif
  9145.     }
  9146.     loop.ircd_rehashing = 1; /* double checking.. */
  9147.     if (init_conf(configfile, 1) == 0)
  9148.         run_configuration();
  9149.     if (sig == 1)
  9150.         reread_motdsandrules();
  9151.     unload_all_unused_snomasks();
  9152.     unload_all_unused_umodes();
  9153.     unload_all_unused_extcmodes();
  9154.     extcmodes_check_for_changes();
  9155.     loop.ircd_rehashing = 0;
  9156.     remote_rehash_client = NULL;
  9157.     return 1;
  9158. }
  9159.  
  9160. void link_cleanup(ConfigItem_link *link_ptr)
  9161. {
  9162.     safefree(link_ptr->servername);
  9163.     unreal_delete_masks(link_ptr->incoming.mask);
  9164.     Auth_DeleteAuthStruct(link_ptr->auth);
  9165.     safefree(link_ptr->outgoing.bind_ip);
  9166.     safefree(link_ptr->outgoing.hostname);
  9167.     safefree(link_ptr->hub);
  9168.     safefree(link_ptr->leaf);
  9169.     safefree(link_ptr->ciphers);
  9170. }
  9171.  
  9172. void delete_linkblock(ConfigItem_link *link_ptr)
  9173. {
  9174.     Debug((DEBUG_ERROR, "delete_linkblock: deleting %s, refcount=%d",
  9175.         link_ptr->servername, link_ptr->refcount));
  9176.     if (link_ptr->class)
  9177.     {
  9178.         link_ptr->class->xrefcount--;
  9179.         /* Perhaps the class is temporary too and we need to free it... */
  9180.         if (link_ptr->class->flag.temporary &&
  9181.             !link_ptr->class->clients && !link_ptr->class->xrefcount)
  9182.         {
  9183.             delete_classblock(link_ptr->class);
  9184.             link_ptr->class = NULL;
  9185.         }
  9186.     }
  9187.     link_cleanup(link_ptr);
  9188.     DelListItem(link_ptr, conf_link);
  9189.     MyFree(link_ptr);
  9190. }
  9191.  
  9192. void delete_classblock(ConfigItem_class *class_ptr)
  9193. {
  9194.     Debug((DEBUG_ERROR, "delete_classblock: deleting %s, clients=%d, xrefcount=%d",
  9195.         class_ptr->name, class_ptr->clients, class_ptr->xrefcount));
  9196.     safefree(class_ptr->name);
  9197.     DelListItem(class_ptr, conf_class);
  9198.     MyFree(class_ptr);
  9199. }
  9200.  
  9201. void    listen_cleanup()
  9202. {
  9203.     int i = 0;
  9204.     ConfigItem_listen *listen_ptr;
  9205.     ListStruct *next;
  9206.     for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)next)
  9207.     {
  9208.         next = (ListStruct *)listen_ptr->next;
  9209.         if (listen_ptr->flag.temporary && !listen_ptr->clients)
  9210.         {
  9211.             safefree(listen_ptr->ip);
  9212.             DelListItem(listen_ptr, conf_listen);
  9213.             MyFree(listen_ptr);
  9214.             i++;
  9215.         }
  9216.     }
  9217.     if (i)
  9218.         close_listeners();
  9219. }
  9220.  
  9221. #ifdef USE_LIBCURL
  9222. char *find_remote_include(char *url, char **errorbuf)
  9223. {
  9224.     ConfigItem_include *inc;
  9225.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9226.     {
  9227.         if (!(inc->flag.type & INCLUDE_NOTLOADED))
  9228.             continue;
  9229.         if (!(inc->flag.type & INCLUDE_REMOTE))
  9230.             continue;
  9231.         if (!stricmp(url, inc->url))
  9232.         {
  9233.             *errorbuf = inc->errorbuf;
  9234.             return inc->file;
  9235.         }
  9236.     }
  9237.     return NULL;
  9238. }
  9239.  
  9240. char *find_loaded_remote_include(char *url)
  9241. {
  9242.     ConfigItem_include *inc;
  9243.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9244.     {
  9245.         if ((inc->flag.type & INCLUDE_NOTLOADED))
  9246.             continue;
  9247.         if (!(inc->flag.type & INCLUDE_REMOTE))
  9248.             continue;
  9249.         if (!stricmp(url, inc->url))
  9250.             return inc->file;
  9251.     }
  9252.     return NULL;
  9253. }
  9254.  
  9255. /**
  9256.  * Non-asynchronous remote inclusion to give a user better feedback
  9257.  * when first starting his IRCd.
  9258.  *
  9259.  * The asynchronous friend is rehash() which merely queues remote
  9260.  * includes for download using download_file_async().
  9261.  */
  9262. int remote_include(ConfigEntry *ce)
  9263. {
  9264.     char *errorbuf = NULL;
  9265.     char *url = ce->ce_vardata;
  9266.     char *file = find_remote_include(url, &errorbuf);
  9267.     int ret;
  9268.     if (!loop.ircd_rehashing || (loop.ircd_rehashing && !file && !errorbuf))
  9269.     {
  9270.         char *error;
  9271.         if (config_verbose > 0)
  9272.             config_status("Downloading %s", url);
  9273.         file = download_file(url, &error);
  9274.         if (!file)
  9275.         {
  9276. #ifdef REMOTEINC_SPECIALCACHE
  9277.             if (has_cached_version(url))
  9278.             {
  9279.                 config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
  9280.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  9281.                     url, error);
  9282.                 file = strdup(unreal_mkcache(url));
  9283.                 /* Let it pass to load_conf()... */
  9284.             } else {
  9285. #endif
  9286.                 config_error("%s:%i: include: error downloading '%s': %s",
  9287.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  9288.                      url, error);
  9289.                 return -1;
  9290. #ifdef REMOTEINC_SPECIALCACHE
  9291.             }
  9292. #endif
  9293.         } else {
  9294. #ifdef REMOTEINC_SPECIALCACHE
  9295.             unreal_copyfileex(file, unreal_mkcache(url), 0);
  9296. #endif
  9297.         }
  9298.         add_remote_include(file, url, 0, NULL, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  9299.         ret = load_conf(file, url);
  9300.         free(file);
  9301.         return ret;
  9302.     }
  9303.     else
  9304.     {
  9305.         if (errorbuf)
  9306.         {
  9307. #ifdef REMOTEINC_SPECIALCACHE
  9308.             if (has_cached_version(url))
  9309.             {
  9310.                 config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
  9311.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  9312.                     url, errorbuf);
  9313.                 /* Let it pass to load_conf()... */
  9314.                 file = strdup(unreal_mkcache(url));
  9315.             } else {
  9316. #endif
  9317.                 config_error("%s:%i: include: error downloading '%s': %s",
  9318.                     ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
  9319.                     url, errorbuf);
  9320.                 return -1;
  9321. #ifdef REMOTEINC_SPECIALCACHE
  9322.             }
  9323. #endif
  9324.         }
  9325.         if (config_verbose > 0)
  9326.             config_status("Loading %s from download", url);
  9327.         add_remote_include(file, url, 0, NULL, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
  9328.         ret = load_conf(file, url);
  9329.         return ret;
  9330.     }
  9331.     return 0;
  9332. }
  9333. #endif
  9334.  
  9335. /**
  9336.  * Add an item to the conf_include list for the specified file.
  9337.  *
  9338.  * Checks for whether or not we're performing recursive includes
  9339.  * belong in conf_load() because that function is able to return an
  9340.  * error code. Any checks in here will end up being ignored by callers
  9341.  * and thus will gain us nothing.
  9342.  *
  9343.  * @param file path to the include file.
  9344.  */
  9345. void add_include(const char *file, const char *included_from, int included_from_line)
  9346. {
  9347.     ConfigItem_include *inc;
  9348.  
  9349.     inc = MyMallocEx(sizeof(ConfigItem_include));
  9350.     inc->file = strdup(file);
  9351.     inc->flag.type = INCLUDE_NOTLOADED;
  9352.     inc->included_from = strdup(included_from);
  9353.     inc->included_from_line = included_from_line;
  9354.     AddListItem(inc, conf_include);
  9355. }
  9356.  
  9357. #ifdef USE_LIBCURL
  9358. /**
  9359.  * Adds a remote include entry to the config_include list.
  9360.  *
  9361.  * This is to be called whenever the included_from and
  9362.  * included_from_line parameters are known. This means that during a
  9363.  * rehash when downloads are done asynchronously, you call this with
  9364.  * the inclued_from and included_from_line information. After the
  9365.  * download is complete and you know there it is stored in the FS,
  9366.  * call update_remote_include().
  9367.  */
  9368. void add_remote_include(const char *file, const char *url, int flags, const char *errorbuf, const char *included_from, int included_from_line)
  9369. {
  9370.     ConfigItem_include *inc;
  9371.  
  9372.     /* we rely on MyMallocEx() zeroing the ConfigItem_include */
  9373.     inc = MyMallocEx(sizeof(ConfigItem_include));
  9374.     if (included_from)
  9375.     {
  9376.         inc->included_from = strdup(included_from);
  9377.         inc->included_from_line = included_from_line;
  9378.     }
  9379.     inc->url = strdup(url);
  9380.  
  9381.     update_remote_include(inc, file, INCLUDE_NOTLOADED|INCLUDE_REMOTE|flags, errorbuf);
  9382.     AddListItem(inc, conf_include);
  9383. }
  9384.  
  9385. /**
  9386.  * Update certain information in a remote include's config_include list entry.
  9387.  *
  9388.  * @param file the place on disk where the downloaded remote include
  9389.  *        may be found
  9390.  * @param flags additional flags to set on the config_include entry
  9391.  * @param errorbuf non-NULL if there were errors encountered in
  9392.  *        downloading. The error will be stored into the config_include
  9393.  *        entry.
  9394.  */
  9395. void update_remote_include(ConfigItem_include *inc, const char *file, int flags, const char *errorbuf)
  9396. {
  9397.     /*
  9398.      * file may be NULL when errorbuf is non-NULL and vice-versa.
  9399.      */
  9400.     if (file)
  9401.         inc->file = strdup(file);
  9402.     inc->flag.type |= flags;
  9403.  
  9404.     if (errorbuf)
  9405.         inc->errorbuf = strdup(errorbuf);
  9406. }
  9407. #endif
  9408.  
  9409. /**
  9410.  * Clean up conf_include after a rehash fails because of a
  9411.  * configuration file error.
  9412.  *
  9413.  * Duplicates some in unload_loaded_include().
  9414.  */
  9415. void unload_notloaded_includes(void)
  9416. {
  9417.     ConfigItem_include *inc, *next;
  9418.  
  9419.     for (inc = conf_include; inc; inc = next)
  9420.     {
  9421.         next = (ConfigItem_include *)inc->next;
  9422.         if ((inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
  9423.         {
  9424. #ifdef USE_LIBCURL
  9425.             if (inc->flag.type & INCLUDE_REMOTE)
  9426.             {
  9427.                 /* Delete the file, but only if it's not a cached version */
  9428.                 if (strncmp(inc->file, CACHEDIR, strlen(CACHEDIR)))
  9429.                 {
  9430.                     remove(inc->file);
  9431.                 }
  9432.                 free(inc->url);
  9433.                 if (inc->errorbuf)
  9434.                     free(inc->errorbuf);
  9435.             }
  9436. #endif
  9437.             free(inc->file);
  9438.             free(inc->included_from);
  9439.             DelListItem(inc, conf_include);
  9440.             free(inc);
  9441.         }
  9442.     }
  9443. }
  9444.  
  9445. /**
  9446.  * Clean up conf_include after a successful rehash to make way for
  9447.  * load_includes().
  9448.  */
  9449. void unload_loaded_includes(void)
  9450. {
  9451.     ConfigItem_include *inc, *next;
  9452.  
  9453.     for (inc = conf_include; inc; inc = next)
  9454.     {
  9455.         next = (ConfigItem_include *)inc->next;
  9456.         if (!(inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
  9457.         {
  9458. #ifdef USE_LIBCURL
  9459.             if (inc->flag.type & INCLUDE_REMOTE)
  9460.             {
  9461.                 /* Delete the file, but only if it's not a cached version */
  9462.                 if (strncmp(inc->file, CACHEDIR, strlen(CACHEDIR)))
  9463.                 {
  9464.                     remove(inc->file);
  9465.                 }
  9466.                 free(inc->url);
  9467.                 if (inc->errorbuf)
  9468.                     free(inc->errorbuf);
  9469.             }
  9470. #endif
  9471.             free(inc->file);
  9472.             free(inc->included_from);
  9473.             DelListItem(inc, conf_include);
  9474.             free(inc);
  9475.         }
  9476.     }
  9477. }
  9478.  
  9479. /**
  9480.  * Mark loaded includes as loaded by removing the INCLUDE_NOTLOADED
  9481.  * flag. Meant to be called only after calling
  9482.  * unload_loaded_includes().
  9483.  */
  9484. void load_includes(void)
  9485. {
  9486.     ConfigItem_include *inc;
  9487.  
  9488.     /* Doing this for all the includes should actually be faster
  9489.      * than only doing it for includes that are not-loaded
  9490.      */
  9491.     for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
  9492.         inc->flag.type &= ~INCLUDE_NOTLOADED;
  9493. }
  9494.  
  9495. /** Check if an important SSL option is used in config. Only checks link and listen at this time.
  9496.  * This will generate a warning on boot & REHASH.
  9497.  * If booting, the IRCd will stop.
  9498.  */
  9499. int ssl_used_in_config_but_unavail(void)
  9500. {
  9501.     int errors = 0;
  9502.     ConfigItem_link *link;
  9503.     ConfigItem_listen *listener;
  9504.  
  9505.     if (ctx_server && ctx_client)
  9506.         return 0; /* everything is functional */
  9507.  
  9508.     for (listener = conf_listen; listener; listener = (ConfigItem_listen *)listener->next)
  9509.         if (listener->options & LISTENER_SSL)
  9510.         {
  9511.             config_error("Listen block %s:%d is configured to use SSL, however SSL is unavailable due to an earlier error (certificate/key not loaded?)", listener->ip, listener->port);
  9512.             errors++;
  9513.         }
  9514.  
  9515.     for (link = conf_link; link; link = (ConfigItem_link *)link->next)
  9516.         if (link->options & CONNECT_SSL)
  9517.         {
  9518.             config_error("Link block %s is configured to use SSL, however SSL is unavailable due to an earlier error (certificate/key not loaded?)", link->servername);
  9519.             errors++;
  9520.         }
  9521.  
  9522.     return (errors ? 1 : 0);
  9523. }
  9524.  
  9525. /** Check if the user attempts to unload (eg: by commenting out) a module
  9526.  * that is currently loaded and is tagged as MOD_OPT_PERM_RELOADABLE
  9527.  * (in other words: a module that allows re-loading but not un-loading)
  9528.  */
  9529. int reloadable_perm_module_unloaded(void)
  9530. {
  9531. Module *m, *m2;
  9532. extern Module *Modules;
  9533. int ret = 0;
  9534.  
  9535.     for (m = Modules; m; m = m->next)
  9536.     {
  9537.         if ((m->options & MOD_OPT_PERM_RELOADABLE) && (m->flags & MODFLAG_LOADED))
  9538.         {
  9539.             /* For each module w/MOD_OPT_PERM_RELOADABLE that is currently fully loaded... */
  9540.             int found = 0;
  9541.             for (m2 = Modules; m2; m2 = m2->next)
  9542.             {
  9543.                 if ((m != m2) && !strcmp(m->header->name, m2->header->name))
  9544.                     found = 1;
  9545.             }
  9546.             if (!found)
  9547.             {
  9548.                 config_error("Attempt to unload module '%s' is not permitted. Module is permanent and reloadable only.", m->header->name);
  9549.                 ret = 1;
  9550.                 /* we don't return straight away so the user gets to see all errors and not just one */
  9551.             }
  9552.         }
  9553.     }
  9554.     return ret;
  9555. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement