]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conf.c
ngIRCd Release 27
[ngircd-alex.git] / src / ngircd / conf.c
index 70c96092a12912c7042d4d36226f3f6b099dcb64..e4cd8963f3072e4bbcee1c6e062fe660c1fe49e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,9 +16,7 @@
  * Configuration management (reading, parsing & validation)
  */
 
-#include "imp.h"
 #include <assert.h>
-#include <ctype.h>
 #include <errno.h>
 #ifdef PROTOTYPES
 #      include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <time.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <grp.h>
 #include <sys/types.h>
-#include <unistd.h>
 #include <dirent.h>
+#include <netdb.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#      include <sys/resource.h>
+#endif
 
-#include "array.h"
 #include "ngircd.h"
 #include "conn.h"
 #include "channel.h"
-#include "defines.h"
 #include "log.h"
 #include "match.h"
-#include "tool.h"
 
-#include "exp.h"
 #include "conf.h"
 
 
@@ -93,6 +92,12 @@ static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
 #define DEFAULT_LISTEN_ADDRSTR "0.0.0.0"
 #endif
 
+#ifdef HAVE_LIBSSL
+#define DEFAULT_CIPHERS                "HIGH:!aNULL:@STRENGTH:!SSLv3"
+#endif
+#ifdef HAVE_LIBGNUTLS
+#define DEFAULT_CIPHERS                "SECURE128:-VERS-SSL3.0"
+#endif
 
 #ifdef SSL_SUPPORT
 
@@ -112,11 +117,20 @@ ConfSSL_Init(void)
        free(Conf_SSLOptions.CertFile);
        Conf_SSLOptions.CertFile = NULL;
 
+       free(Conf_SSLOptions.CAFile);
+       Conf_SSLOptions.CAFile = NULL;
+
+       free(Conf_SSLOptions.CRLFile);
+       Conf_SSLOptions.CRLFile = NULL;
+
        free(Conf_SSLOptions.DHFile);
        Conf_SSLOptions.DHFile = NULL;
        array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
 
        array_free(&Conf_SSLOptions.ListenPorts);
+
+       free(Conf_SSLOptions.CipherList);
+       Conf_SSLOptions.CipherList = NULL;
 }
 
 /**
@@ -207,7 +221,7 @@ ports_puts(array *a)
  * Parse a comma separated string into an array of port numbers (integers).
  */
 static void
-ports_parse(array *a, int Line, char *Arg)
+ports_parse(array *a, const char *File, int Line, char *Arg)
 {
        char *ptr;
        int port;
@@ -223,10 +237,10 @@ ports_parse(array *a, int Line, char *Arg)
                        port16 = (UINT16) port;
                        if (!array_catb(a, (char*)&port16, sizeof port16))
                                Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
-                                                       NGIRCd_ConfFile, Line, port, strerror(errno));
+                                            File, Line, port, strerror(errno));
                } else {
                        Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
-                                                                       NGIRCd_ConfFile, Line, port );
+                                    File, Line, port );
                }
 
                ptr = strtok( NULL, "," );
@@ -317,7 +331,7 @@ opers_puts(void)
  * This function waits for a keypress of the user when stdin/stdout are valid
  * tty's ("you can read our nice message and we can read in your keypress").
  *
- * @return     0 on succes, 1 on failure(s); therefore the result code can
+ * @return     0 on success, 1 on failure(s); therefore the result code can
  *             directly be used by exit() when running "ngircd --configtest".
  */
 GLOBAL int
@@ -325,7 +339,7 @@ Conf_Test( void )
 {
        struct passwd *pwd;
        struct group *grp;
-       unsigned int i;
+       unsigned int i, j;
        bool config_valid;
        size_t predef_channel_count;
        struct Conf_Channel *predef_chan;
@@ -360,9 +374,9 @@ Conf_Test( void )
                printf("  MotdPhrase = %s\n", array_bytes(&Conf_Motd)
                       ? (const char*) array_start(&Conf_Motd) : "");
        }
-#ifndef PAM
-       printf("  Password = %s\n", Conf_ServerPwd);
-#endif
+       printf("  Network = %s\n", Conf_Network);
+       if (!Conf_PAM)
+               printf("  Password = %s\n", Conf_ServerPwd);
        printf("  PidFile = %s\n", Conf_PidFile);
        printf("  Ports = ");
        ports_puts(&Conf_ListenPorts);
@@ -385,6 +399,7 @@ Conf_Test( void )
        printf("  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
        printf("  MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
        printf("  MaxNickLength = %u\n", Conf_MaxNickLength - 1);
+       printf("  MaxPenaltyTime = %ld\n", (long)Conf_MaxPenaltyTime);
        printf("  MaxListSize = %d\n", Conf_MaxListSize);
        printf("  PingTimeout = %d\n", Conf_PingTimeout);
        printf("  PongTimeout = %d\n", Conf_PongTimeout);
@@ -402,19 +417,21 @@ Conf_Test( void )
        printf("  ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
        printf("  ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
 #endif
+       printf("  DefaultUserModes = %s\n", Conf_DefaultUserModes);
        printf("  DNS = %s\n", yesno_to_str(Conf_DNS));
-#ifdef IDENT
+#ifdef IDENTAUTH
        printf("  Ident = %s\n", yesno_to_str(Conf_Ident));
 #endif
        printf("  IncludeDir = %s\n", Conf_IncludeDir);
        printf("  MorePrivacy = %s\n", yesno_to_str(Conf_MorePrivacy));
-       printf("  NoticeAuth = %s\n", yesno_to_str(Conf_NoticeAuth));
+       printf("  NoticeBeforeRegistration = %s\n", yesno_to_str(Conf_NoticeBeforeRegistration));
        printf("  OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
        printf("  OperChanPAutoOp = %s\n", yesno_to_str(Conf_OperChanPAutoOp));
        printf("  OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
 #ifdef PAM
        printf("  PAM = %s\n", yesno_to_str(Conf_PAM));
        printf("  PAMIsOptional = %s\n", yesno_to_str(Conf_PAMIsOptional));
+       printf("  PAMServiceName = %s\n", Conf_PAMServiceName);
 #endif
 #ifndef STRICT_RFC
        printf("  RequireAuthPing = %s\n", yesno_to_str(Conf_AuthPing));
@@ -429,8 +446,14 @@ Conf_Test( void )
 
 #ifdef SSL_SUPPORT
        puts("[SSL]");
+       printf("  CAFile = %s\n", Conf_SSLOptions.CAFile
+                                       ? Conf_SSLOptions.CAFile : "");
        printf("  CertFile = %s\n", Conf_SSLOptions.CertFile
                                        ? Conf_SSLOptions.CertFile : "");
+       printf("  CipherList = %s\n", Conf_SSLOptions.CipherList ?
+              Conf_SSLOptions.CipherList : DEFAULT_CIPHERS);
+       printf("  CRLFile = %s\n", Conf_SSLOptions.CRLFile
+                                       ? Conf_SSLOptions.CRLFile : "");
        printf("  DHFile = %s\n", Conf_SSLOptions.DHFile
                                        ? Conf_SSLOptions.DHFile : "");
        printf("  KeyFile = %s\n", Conf_SSLOptions.KeyFile
@@ -456,13 +479,16 @@ Conf_Test( void )
                printf( "  Host = %s\n", Conf_Server[i].host );
                printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
 #ifdef SSL_SUPPORT
-               printf( "  SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
+               printf("  SSLConnect = %s\n",
+                      yesno_to_str(Conf_Server[i].SSLConnect));
+               printf("  SSLVerify = %s\n",
+                      yesno_to_str(Conf_Server[i].SSLVerify));
 #endif
                printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
                printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
                printf( "  ServiceMask = %s\n", Conf_Server[i].svs_mask);
                printf( "  Group = %d\n", Conf_Server[i].group );
-               printf( "  Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
+               printf( "  Passive = %s\n\n", yesno_to_str(Conf_Server[i].flags & CONF_SFLAG_DISABLED));
        }
 
        predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan));
@@ -475,10 +501,12 @@ Conf_Test( void )
                /* Valid "Channel" section */
                puts( "[CHANNEL]" );
                printf("  Name = %s\n", predef_chan->name);
-               printf("  Modes = %s\n", predef_chan->modes);
+               for(j = 0; j < predef_chan->modes_num; j++)
+                       printf("  Modes = %s\n", predef_chan->modes[j]);
                printf("  Key = %s\n", predef_chan->key);
                printf("  MaxUsers = %lu\n", predef_chan->maxusers);
                printf("  Topic = %s\n", predef_chan->topic);
+               printf("  Autojoin = %s\n", yesno_to_str(predef_chan->autojoin));
                printf("  KeyFile = %s\n\n", predef_chan->keyfile);
        }
 
@@ -521,7 +549,11 @@ Conf_UnsetServer( CONN_ID Idx )
                                /* "Short" connection, enforce "ConnectRetry"
                                 * but randomize it a little bit: 15 seconds. */
                                Conf_Server[i].lasttry =
+#ifdef HAVE_ARC4RANDOM
+                                       t + (arc4random() % 15);
+#else
                                        t + rand() / (RAND_MAX / 15);
+#endif
                        }
                }
        }
@@ -608,6 +640,7 @@ Conf_EnablePassiveServer(const char *Name)
                    && (Conf_Server[i].port > 0)) {
                        /* BINGO! Enable server */
                        Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
+                       Conf_Server[i].lasttry = 0;
                        return true;
                }
        }
@@ -699,7 +732,6 @@ Conf_NickIsService(int ConfServer, const char *Nick)
 /**
  * Check if the given nickname is blocked for "normal client" use.
  *
- * @param ConfServer The server index or NONE to check all configured servers.
  * @param Nick The nickname to check.
  * @returns true if the given nickname belongs to an "IRC service".
  */
@@ -733,6 +765,7 @@ Set_Defaults(bool InitServers)
        strcpy(Conf_ServerAdminMail, "");
        snprintf(Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s",
                 PACKAGE_NAME, PACKAGE_VERSION);
+       strcpy(Conf_Network, "");
        free(Conf_ListenAddress);
        Conf_ListenAddress = NULL;
        array_free(&Conf_ListenPorts);
@@ -753,6 +786,7 @@ Set_Defaults(bool InitServers)
        Conf_MaxConnectionsIP = 5;
        Conf_MaxJoins = 10;
        Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
+       Conf_MaxPenaltyTime = -1;
        Conf_MaxListSize = 100;
        Conf_PingTimeout = 120;
        Conf_PongTimeout = 20;
@@ -776,6 +810,7 @@ Set_Defaults(bool InitServers)
 #else
        Conf_ConnectIPv6 = false;
 #endif
+       strcpy(Conf_DefaultUserModes, "");
        Conf_DNS = true;
 #ifdef IDENTAUTH
        Conf_Ident = true;
@@ -784,7 +819,7 @@ Set_Defaults(bool InitServers)
 #endif
        strcpy(Conf_IncludeDir, "");
        Conf_MorePrivacy = false;
-       Conf_NoticeAuth = false;
+       Conf_NoticeBeforeRegistration = false;
        Conf_OperCanMode = false;
        Conf_OperChanPAutoOp = true;
        Conf_OperServerMode = false;
@@ -794,8 +829,9 @@ Set_Defaults(bool InitServers)
        Conf_PAM = false;
 #endif
        Conf_PAMIsOptional = false;
-#ifdef SYSLOG
+       strcpy(Conf_PAMServiceName, "ngircd");
        Conf_ScrubCTCP = false;
+#ifdef SYSLOG
 #ifdef LOG_LOCAL5
        Conf_SyslogFacility = LOG_LOCAL5;
 #else
@@ -830,13 +866,13 @@ no_listenports(void)
  *
  * This function is used to read the MOTD and help text file, for example.
  *
- * @param filename     Name of the file to read.
+ * @param Filename     Name of the file to read.
  * @return             true, when the file has been read in.
  */
 static bool
 Read_TextFile(const char *Filename, const char *Name, array *Destination)
 {
-       char line[127];
+       char line[COMMAND_LEN];
        FILE *fp;
        int line_no = 1;
 
@@ -872,9 +908,9 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination)
  * Please note that this function uses exit(1) on fatal errors and therefore
  * can result in ngIRCd terminating!
  *
- * @param ngircd_starting      Flag indicating if ngIRCd is starting or not.
- * @returns                    true when the configuration file has been read
- *                             successfully; false otherwise.
+ * @param IsStarting   Flag indicating if ngIRCd is starting or not.
+ * @returns            true when the configuration file has been read
+ *                     successfully; false otherwise.
  */
 static bool
 Read_Config(bool TestOnly, bool IsStarting)
@@ -884,27 +920,46 @@ Read_Config(bool TestOnly, bool IsStarting)
        struct dirent *entry;
        int i, n;
        FILE *fd;
-       DIR *dh;
+       DIR *dh = NULL;
+
+       if (!NGIRCd_ConfFile[0]) {
+               /* No configuration file name explicitly given on the command
+                * line, use defaults but ignore errors when this file can't be
+                * read later on. */
+               strlcpy(file, SYSCONFDIR, sizeof(file));
+               strlcat(file, CONFIG_FILE, sizeof(file));
+               ptr = file;
+       } else
+               ptr = NGIRCd_ConfFile;
+
+       Config_Error(LOG_INFO, "Using %s configuration file \"%s\" ...",
+                    !NGIRCd_ConfFile[0] ? "default" : "specified", ptr);
 
        /* Open configuration file */
-       fd = fopen( NGIRCd_ConfFile, "r" );
-       if( ! fd ) {
-               /* No configuration file found! */
-               Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
-                                       NGIRCd_ConfFile, strerror( errno ));
-               if (!IsStarting)
-                       return false;
-               Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
-               exit( 1 );
+       fd = fopen(ptr, "r");
+       if (!fd) {
+               if (NGIRCd_ConfFile[0]) {
+                       Config_Error(LOG_ALERT,
+                                    "Can't read specified configuration file \"%s\": %s",
+                                    ptr, strerror(errno));
+                       if (IsStarting) {
+                               Config_Error(LOG_ALERT,
+                                            "%s exiting due to fatal errors!",
+                                            PACKAGE_NAME);
+                               exit(1);
+                       }
+               }
+               Config_Error(LOG_WARNING,
+                            "Can't read default configuration file \"%s\": %s - Ignored.",
+                            ptr, strerror(errno));
        }
 
        opers_free();
        Set_Defaults(IsStarting);
 
-       if (TestOnly)
+       if (TestOnly && fd)
                Config_Error(LOG_INFO,
-                            "Reading configuration from \"%s\" ...",
-                            NGIRCd_ConfFile );
+                            "Reading configuration from \"%s\" ...", ptr);
 
        /* Clean up server configuration structure: mark all already
         * configured servers as "once" so that they are deleted
@@ -923,16 +978,13 @@ Read_Config(bool TestOnly, bool IsStarting)
 
                                        if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
                                                Init_Server_Struct( &Conf_Server[n] );
-#ifdef DEBUG
-                                               Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
-                                                                                               n, i );
-#endif
+                                               LogDebug("Deleted unused duplicate server %d (kept %d).", n, i);
                                        }
                                }
                        } else {
                                /* Mark server as "once" */
                                Conf_Server[i].flags |= CONF_SFLAG_ONCE;
-                               Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
+                               LogDebug("Marked server %d as \"once\"", i);
                        }
                }
        }
@@ -944,16 +996,23 @@ Read_Config(bool TestOnly, bool IsStarting)
        ConfSSL_Init();
 #endif
 
-       Read_Config_File(NGIRCd_ConfFile, fd);
-       fclose(fd);
+       if (fd) {
+               Read_Config_File(ptr, fd);
+               fclose(fd);
+       }
 
        if (Conf_IncludeDir[0]) {
+               /* Include directory was set in the main configuration file. So
+                * use it and show errors. */
                dh = opendir(Conf_IncludeDir);
                if (!dh)
                        Config_Error(LOG_ALERT,
                                     "Can't open include directory \"%s\": %s",
                                     Conf_IncludeDir, strerror(errno));
-       } else {
+       } else if (!NGIRCd_ConfFile[0]) {
+               /* No include dir set in the configuration file used (if any)
+                * but no config file explicitly specified either: so use the
+                * default include path here as well! */
                strlcpy(Conf_IncludeDir, SYSCONFDIR, sizeof(Conf_IncludeDir));
                strlcat(Conf_IncludeDir, CONFIG_DIR, sizeof(Conf_IncludeDir));
                dh = opendir(Conf_IncludeDir);
@@ -1025,15 +1084,23 @@ Read_Config(bool TestOnly, bool IsStarting)
        CheckFileReadable("CertFile", Conf_SSLOptions.CertFile);
        CheckFileReadable("DHFile", Conf_SSLOptions.DHFile);
        CheckFileReadable("KeyFile", Conf_SSLOptions.KeyFile);
+
+       /* Set the default ciphers if none were configured */
+       if (!Conf_SSLOptions.CipherList)
+               Conf_SSLOptions.CipherList = strdup_warn(DEFAULT_CIPHERS);
 #endif
 
        return true;
 }
 
 /**
- * ...
+ * Read in and handle a configuration file.
+ *
+ * @param File Name of the configuration file.
+ * @param fd File descriptor already opened for reading.
  */
-static void Read_Config_File(const char *File, FILE *fd)
+static void
+Read_Config_File(const char *File, FILE *fd)
 {
        char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
        int i, line = 0;
@@ -1042,7 +1109,7 @@ static void Read_Config_File(const char *File, FILE *fd)
        /* Read configuration file */
        section[0] = '\0';
        while (true) {
-               if (!fgets(str, LINE_LEN, fd))
+               if (!fgets(str, sizeof(str), fd))
                        break;
                ngt_TrimStr(str);
                line++;
@@ -1051,6 +1118,12 @@ static void Read_Config_File(const char *File, FILE *fd)
                if (str[0] == ';' || str[0] == '#' || str[0] == '\0')
                        continue;
 
+               if (strlen(str) >= sizeof(str) - 1) {
+                       Config_Error(LOG_WARNING, "%s, line %d too long!",
+                                    File, line);
+                       continue;
+               }
+
                /* Is this the beginning of a new section? */
                if ((str[0] == '[') && (str[strlen(str) - 1] == ']')) {
                        strlcpy(section, str, sizeof(section));
@@ -1120,7 +1193,7 @@ static void Read_Config_File(const char *File, FILE *fd)
 
                        Config_Error(LOG_ERR,
                                     "%s, line %d: Unknown section \"%s\"!",
-                                    NGIRCd_ConfFile, line, section);
+                                    File, line, section);
                        section[0] = 0x1;
                }
                if (section[0] == 0x1)
@@ -1130,7 +1203,7 @@ static void Read_Config_File(const char *File, FILE *fd)
                ptr = strchr(str, '=');
                if (!ptr) {
                        Config_Error(LOG_ERR, "%s, line %d: Syntax error!",
-                                    NGIRCd_ConfFile, line);
+                                    File, line);
                        continue;
                }
                *ptr = '\0';
@@ -1158,7 +1231,7 @@ static void Read_Config_File(const char *File, FILE *fd)
                else
                        Config_Error(LOG_ERR,
                                     "%s, line %d: Variable \"%s\" outside section!",
-                                    NGIRCd_ConfFile, line, var);
+                                    File, line, var);
        }
 }
 
@@ -1190,7 +1263,7 @@ Check_ArgIsTrue(const char *Arg)
  * @returns    New configured maximum nickname length.
  */
 static unsigned int
-Handle_MaxNickLength(int Line, const char *Arg)
+Handle_MaxNickLength(const char *File, int Line, const char *Arg)
 {
        unsigned new;
 
@@ -1198,13 +1271,13 @@ Handle_MaxNickLength(int Line, const char *Arg)
        if (new > CLIENT_NICK_LEN) {
                Config_Error(LOG_WARNING,
                             "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
-                            NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
+                            File, Line, CLIENT_NICK_LEN - 1);
                return CLIENT_NICK_LEN;
        }
        if (new < 2) {
                Config_Error(LOG_WARNING,
                             "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
-                            NGIRCd_ConfFile, Line);
+                            File, Line);
                return 2;
        }
        return new;
@@ -1214,14 +1287,14 @@ Handle_MaxNickLength(int Line, const char *Arg)
  * Output a warning messages if IDENT is configured but not compiled in.
  */
 static void
-WarnIdent(int UNUSED Line)
+WarnIdent(const char UNUSED *File, int UNUSED Line)
 {
 #ifndef IDENTAUTH
        if (Conf_Ident) {
                /* user has enabled ident lookups explicitly, but ... */
                Config_Error(LOG_WARNING,
                        "%s: line %d: \"Ident = yes\", but ngircd was built without IDENT support!",
-                       NGIRCd_ConfFile, Line);
+                       File, Line);
        }
 #endif
 }
@@ -1230,14 +1303,14 @@ WarnIdent(int UNUSED Line)
  * Output a warning messages if IPv6 is configured but not compiled in.
  */
 static void
-WarnIPv6(int UNUSED Line)
+WarnIPv6(const char UNUSED *File, int UNUSED Line)
 {
 #ifndef WANT_IPV6
        if (Conf_ConnectIPv6) {
                /* user has enabled IPv6 explicitly, but ... */
                Config_Error(LOG_WARNING,
                        "%s: line %d: \"ConnectIPv6 = yes\", but ngircd was built without IPv6 support!",
-                       NGIRCd_ConfFile, Line);
+                       File, Line);
        }
 #endif
 }
@@ -1246,132 +1319,22 @@ WarnIPv6(int UNUSED Line)
  * Output a warning messages if PAM is configured but not compiled in.
  */
 static void
-WarnPAM(int UNUSED Line)
+WarnPAM(const char UNUSED *File, int UNUSED Line)
 {
 #ifndef PAM
        if (Conf_PAM) {
                Config_Error(LOG_WARNING,
                        "%s: line %d: \"PAM = yes\", but ngircd was built without PAM support!",
-                       NGIRCd_ConfFile, Line);
-       }
-#endif
-}
-
-/**
- * Handle legacy "NoXXX" options in [GLOBAL] section.
- *
- * TODO: This function and support for "NoXXX" could be removed starting
- * with ngIRCd release 19 (one release after marking it "deprecated").
- *
- * @param Var  Variable name.
- * @param Arg  Argument string.
- * @returns    true if a NoXXX option has been processed; false otherwise.
- */
-static bool
-CheckLegacyNoOption(const char *Var, const char *Arg)
-{
-       if(strcasecmp(Var, "NoDNS") == 0) {
-               Conf_DNS = !Check_ArgIsTrue( Arg );
-               return true;
-       }
-       if (strcasecmp(Var, "NoIdent") == 0) {
-               Conf_Ident = !Check_ArgIsTrue(Arg);
-               return true;
-       }
-       if(strcasecmp(Var, "NoPAM") == 0) {
-               Conf_PAM = !Check_ArgIsTrue(Arg);
-               return true;
-       }
-       return false;
-}
-
-/**
- * Handle deprecated legacy options in [GLOBAL] section.
- *
- * TODO: This function and support for these options in the [Global] section
- * could be removed starting with ngIRCd release 19 (one release after
- * marking it "deprecated").
- *
- * @param Var  Variable name.
- * @param Arg  Argument string.
- * @returns    true if a legacy option has been processed; false otherwise.
- */
-static const char*
-CheckLegacyGlobalOption(const char *File, int Line, char *Var, char *Arg)
-{
-       if (strcasecmp(Var, "AllowRemoteOper") == 0
-           || strcasecmp(Var, "ChrootDir") == 0
-           || strcasecmp(Var, "ConnectIPv4") == 0
-           || strcasecmp(Var, "ConnectIPv6") == 0
-           || strcasecmp(Var, "OperCanUseMode") == 0
-           || strcasecmp(Var, "OperChanPAutoOp") == 0
-           || strcasecmp(Var, "OperServerMode") == 0
-           || strcasecmp(Var, "PredefChannelsOnly") == 0
-           || strcasecmp(Var, "SyslogFacility") == 0
-           || strcasecmp(Var, "WebircPassword") == 0) {
-               Handle_OPTIONS(File, Line, Var, Arg);
-               return "[Options]";
-       }
-       if (strcasecmp(Var, "ConnectRetry") == 0
-           || strcasecmp(Var, "IdleTimeout") == 0
-           || strcasecmp(Var, "MaxConnections") == 0
-           || strcasecmp(Var, "MaxConnectionsIP") == 0
-           || strcasecmp(Var, "MaxJoins") == 0
-           || strcasecmp(Var, "MaxNickLength") == 0
-           || strcasecmp(Var, "PingTimeout") == 0
-           || strcasecmp(Var, "PongTimeout") == 0) {
-               Handle_LIMITS(File, Line, Var, Arg);
-               return "[Limits]";
-       }
-#ifdef SSL_SUPPORT
-       if (strcasecmp(Var, "SSLCertFile") == 0
-           || strcasecmp(Var, "SSLDHFile") == 0
-           || strcasecmp(Var, "SSLKeyFile") == 0
-           || strcasecmp(Var, "SSLKeyFilePassword") == 0
-           || strcasecmp(Var, "SSLPorts") == 0) {
-               Handle_SSL(File, Line, Var + 3, Arg);
-               return "[SSL]";
+                       File, Line);
        }
 #endif
-
-       return NULL;
 }
 
-/**
- * Strip "no" prefix of a string.
- *
- * TODO: This function and support for "NoXXX" should be removed starting
- * with ngIRCd release 19! (One release after marking it "deprecated").
- *
- * @param str  Pointer to input string starting with "no".
- * @returns    New pointer to string without "no" prefix.
- */
-static const char *
-NoNo(const char *str)
-{
-       assert(strncasecmp("no", str, 2) == 0 && str[2]);
-       return str + 2;
-}
-
-/**
- * Invert "boolean" string.
- *
- * TODO: This function and support for "NoXXX" should be removed starting
- * with ngIRCd release 19! (One release after marking it "deprecated").
- *
- * @param arg  "Boolean" input string.
- * @returns    Pointer to inverted "boolean string".
- */
-static const char *
-InvertArg(const char *arg)
-{
-       return yesno_to_str(!Check_ArgIsTrue(arg));
-}
 
 /**
  * Handle variable in [Global] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1381,7 +1344,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
        struct passwd *pwd;
        struct group *grp;
        size_t len;
-       const char *section;
+       char *ptr;
 
        assert(File != NULL);
        assert(Line > 0);
@@ -1453,17 +1416,30 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                len = strlen(Arg);
                if (len == 0)
                        return;
-               if (len >= LINE_LEN) {
+               if (len >= 127) {
                        Config_Error_TooLong(File, Line, Var);
                        return;
                }
                if (!array_copyb(&Conf_Motd, Arg, len + 1))
                        Config_Error(LOG_WARNING,
                                     "%s, line %d: Could not append MotdPhrase: %s",
-                                    NGIRCd_ConfFile, Line, strerror(errno));
+                                    File, Line, strerror(errno));
                Using_MotdFile = false;
                return;
        }
+       if (strcasecmp(Var, "Network") == 0) {
+               len = strlcpy(Conf_Network, Arg, sizeof(Conf_Network));
+               if (len >= sizeof(Conf_Network))
+                       Config_Error_TooLong(File, Line, Var);
+               ptr = strchr(Conf_Network, ' ');
+               if (ptr) {
+                       Config_Error(LOG_WARNING,
+                                    "%s, line %d: \"Network\" can't contain spaces!",
+                                    File, Line);
+                       *ptr = '\0';
+               }
+               return;
+       }
        if(strcasecmp(Var, "Password") == 0) {
                len = strlcpy(Conf_ServerPwd, Arg, sizeof(Conf_ServerPwd));
                if (len >= sizeof(Conf_ServerPwd))
@@ -1477,7 +1453,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                return;
        }
        if (strcasecmp(Var, "Ports") == 0) {
-               ports_parse(&Conf_ListenPorts, Line, Arg);
+               ports_parse(&Conf_ListenPorts, File, Line, Arg);
                return;
        }
        if (strcasecmp(Var, "ServerGID") == 0) {
@@ -1489,7 +1465,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                        if (!Conf_GID && strcmp(Arg, "0"))
                                Config_Error(LOG_WARNING,
                                             "%s, line %d: Value of \"%s\" is not a valid group name or ID!",
-                                            NGIRCd_ConfFile, Line, Var);
+                                            File, Line, Var);
                }
                return;
        }
@@ -1502,37 +1478,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                        if (!Conf_UID && strcmp(Arg, "0"))
                                Config_Error(LOG_WARNING,
                                             "%s, line %d: Value of \"%s\" is not a valid user name or ID!",
-                                            NGIRCd_ConfFile, Line, Var);
-               }
-               return;
-       }
-
-       if (CheckLegacyNoOption(Var, Arg)) {
-               /* TODO: This function and support for "NoXXX" could be
-                * be removed starting with ngIRCd release 19 (one release
-                * after marking it "deprecated"). */
-               Config_Error(LOG_WARNING,
-                            "%s, line %d (section \"Global\"): \"No\"-Prefix is deprecated, use \"%s = %s\" in [Options] section!",
-                            NGIRCd_ConfFile, Line, NoNo(Var), InvertArg(Arg));
-               if (strcasecmp(Var, "NoIdent") == 0)
-                       WarnIdent(Line);
-               else if (strcasecmp(Var, "NoPam") == 0)
-                       WarnPAM(Line);
-               return;
-       }
-       if ((section = CheckLegacyGlobalOption(File, Line, Var, Arg))) {
-               /** TODO: This function and support for these options in the
-                * [Global] section could be removed starting with ngIRCd
-                * release 19 (one release after marking it "deprecated"). */
-               if (strncasecmp(Var, "SSL", 3) == 0) {
-                       Config_Error(LOG_WARNING,
-                                    "%s, line %d (section \"Global\"): \"%s\" is deprecated here, move it to %s and rename to \"%s\"!",
-                                    NGIRCd_ConfFile, Line, Var, section,
-                                    Var + 3);
-               } else {
-                       Config_Error(LOG_WARNING,
-                                    "%s, line %d (section \"Global\"): \"%s\" is deprecated here, move it to %s!",
-                                    NGIRCd_ConfFile, Line, Var, section);
+                                            File, Line, Var);
                }
                return;
        }
@@ -1543,7 +1489,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
 /**
  * Handle variable in [Limits] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1560,7 +1506,7 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
                if (Conf_ConnectRetry < 5) {
                        Config_Error(LOG_WARNING,
                                     "%s, line %d: Value of \"ConnectRetry\" too low!",
-                                    NGIRCd_ConfFile, Line);
+                                    File, Line);
                        Conf_ConnectRetry = 5;
                }
                return;
@@ -1590,7 +1536,7 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
                return;
        }
        if (strcasecmp(Var, "MaxNickLength") == 0) {
-               Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
+               Conf_MaxNickLength = Handle_MaxNickLength(File, Line, Arg);
                return;
        }
        if (strcasecmp(Var, "MaxListSize") == 0) {
@@ -1599,12 +1545,18 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
                        Config_Error_NaN(File, Line, Var);
                return;
        }
+       if (strcasecmp(Var, "MaxPenaltyTime") == 0) {
+               Conf_MaxPenaltyTime = atol(Arg);
+               if (Conf_MaxPenaltyTime < -1)
+                       Conf_MaxPenaltyTime = -1;       /* "unlimited" */
+               return;
+       }
        if (strcasecmp(Var, "PingTimeout") == 0) {
                Conf_PingTimeout = atoi(Arg);
                if (Conf_PingTimeout < 5) {
                        Config_Error(LOG_WARNING,
                                     "%s, line %d: Value of \"PingTimeout\" too low!",
-                                    NGIRCd_ConfFile, Line);
+                                    File, Line);
                        Conf_PingTimeout = 5;
                }
                return;
@@ -1614,7 +1566,7 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
                if (Conf_PongTimeout < 5) {
                        Config_Error(LOG_WARNING,
                                     "%s, line %d: Value of \"PongTimeout\" too low!",
-                                    NGIRCd_ConfFile, Line);
+                                    File, Line);
                        Conf_PongTimeout = 5;
                }
                return;
@@ -1626,7 +1578,7 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
 /**
  * Handle variable in [Options] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1699,20 +1651,44 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
        }
        if (strcasecmp(Var, "ConnectIPv6") == 0) {
                Conf_ConnectIPv6 = Check_ArgIsTrue(Arg);
-               WarnIPv6(Line);
+               WarnIPv6(File, Line);
                return;
        }
        if (strcasecmp(Var, "ConnectIPv4") == 0) {
                Conf_ConnectIPv4 = Check_ArgIsTrue(Arg);
                return;
        }
+       if (strcasecmp(Var, "DefaultUserModes") == 0) {
+               p = Arg;
+               Conf_DefaultUserModes[0] = '\0';
+               while (*p) {
+                       if (strchr(Conf_DefaultUserModes, *p)) {
+                               /* Mode is already included; ignore it */
+                               p++;
+                               continue;
+                       }
+
+                       if (strchr(USERMODES, *p)) {
+                               len = strlen(Conf_DefaultUserModes) + 1;
+                               assert(len < sizeof(Conf_DefaultUserModes));
+                               Conf_DefaultUserModes[len - 1] = *p;
+                               Conf_DefaultUserModes[len] = '\0';
+                       } else {
+                               Config_Error(LOG_WARNING,
+                                            "%s, line %d: Unknown user mode \"%c\" in \"DefaultUserModes\"!",
+                                            File, Line, *p);
+                       }
+                       p++;
+               }
+               return;
+       }
        if (strcasecmp(Var, "DNS") == 0) {
                Conf_DNS = Check_ArgIsTrue(Arg);
                return;
        }
        if (strcasecmp(Var, "Ident") == 0) {
                Conf_Ident = Check_ArgIsTrue(Arg);
-               WarnIdent(Line);
+               WarnIdent(File, Line);
                return;
        }
        if (strcasecmp(Var, "IncludeDir") == 0) {
@@ -1731,8 +1707,8 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
                Conf_MorePrivacy = Check_ArgIsTrue(Arg);
                return;
        }
-       if (strcasecmp(Var, "NoticeAuth") == 0) {
-               Conf_NoticeAuth = Check_ArgIsTrue(Arg);
+       if (strcasecmp(Var, "NoticeBeforeRegistration") == 0) {
+               Conf_NoticeBeforeRegistration = Check_ArgIsTrue(Arg);
                return;
        }
        if (strcasecmp(Var, "OperCanUseMode") == 0) {
@@ -1749,27 +1725,17 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
        }
        if (strcasecmp(Var, "PAM") == 0) {
                Conf_PAM = Check_ArgIsTrue(Arg);
-               WarnPAM(Line);
+               WarnPAM(File, Line);
                return;
        }
        if (strcasecmp(Var, "PAMIsOptional") == 0 ) {
                Conf_PAMIsOptional = Check_ArgIsTrue(Arg);
                return;
        }
-       if (strcasecmp(Var, "PredefChannelsOnly") == 0) {
-               /*
-                * TODO: This section and support for "PredefChannelsOnly"
-                * could be removed starting with ngIRCd release 22 (one
-                * release after marking it "deprecated") ...
-                */
-               Config_Error(LOG_WARNING,
-                            "%s, line %d (section \"Options\"): \"%s\" is deprecated, please use \"AllowedChannelTypes\"!",
-                            File, Line, Var);
-               if (Check_ArgIsTrue(Arg))
-                       Conf_AllowedChannelTypes[0] = '\0';
-               else
-                       strlcpy(Conf_AllowedChannelTypes, CHANTYPES,
-                               sizeof(Conf_AllowedChannelTypes));
+       if (strcasecmp(Var, "PAMServiceName") == 0) {
+               len = strlcpy(Conf_PAMServiceName, Arg, sizeof(Conf_PAMServiceName));
+               if (len >= sizeof(Conf_PAMServiceName))
+                       Config_Error_TooLong(File, Line, Var);
                return;
        }
 #ifndef STRICT_RFC
@@ -1804,7 +1770,7 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
 /**
  * Handle variable in [SSL] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1840,7 +1806,22 @@ Handle_SSL(const char *File, int Line, char *Var, char *Arg)
                return;
        }
        if (strcasecmp(Var, "Ports") == 0) {
-               ports_parse(&Conf_SSLOptions.ListenPorts, Line, Arg);
+               ports_parse(&Conf_SSLOptions.ListenPorts, File, Line, Arg);
+               return;
+       }
+       if (strcasecmp(Var, "CipherList") == 0) {
+               assert(Conf_SSLOptions.CipherList == NULL);
+               Conf_SSLOptions.CipherList = strdup_warn(Arg);
+               return;
+       }
+       if (strcasecmp(Var, "CAFile") == 0) {
+               assert(Conf_SSLOptions.CAFile == NULL);
+               Conf_SSLOptions.CAFile = strdup_warn(Arg);
+               return;
+       }
+       if (strcasecmp(Var, "CRLFile") == 0) {
+               assert(Conf_SSLOptions.CRLFile == NULL);
+               Conf_SSLOptions.CRLFile = strdup_warn(Arg);
                return;
        }
 
@@ -1852,7 +1833,7 @@ Handle_SSL(const char *File, int Line, char *Var, char *Arg)
 /**
  * Handle variable in [Operator] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1899,7 +1880,7 @@ Handle_OPERATOR(const char *File, int Line, char *Var, char *Arg )
 /**
  * Handle variable in [Server] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -1936,15 +1917,15 @@ Handle_SERVER(const char *File, int Line, char *Var, char *Arg )
                        return;
 
                Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
-                               NGIRCd_ConfFile, Line, Arg);
+                            File, Line, Arg);
                return;
        }
        if( strcasecmp( Var, "MyPassword" ) == 0 ) {
                /* Password of this server which is sent to the peer */
                if (*Arg == ':') {
                        Config_Error(LOG_ERR,
-                               "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
-                                                                               NGIRCd_ConfFile, Line);
+                                    "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
+                                    File, Line);
                }
                len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
                if (len >= sizeof( New_Server.pwd_in ))
@@ -1965,15 +1946,19 @@ Handle_SERVER(const char *File, int Line, char *Var, char *Arg )
                        New_Server.port = (UINT16)port;
                else
                        Config_Error(LOG_ERR,
-                               "%s, line %d (section \"Server\"): Illegal port number %ld!",
-                               NGIRCd_ConfFile, Line, port );
+                                    "%s, line %d (section \"Server\"): Illegal port number %ld!",
+                                    File, Line, port );
                return;
        }
 #ifdef SSL_SUPPORT
        if( strcasecmp( Var, "SSLConnect" ) == 0 ) {
                New_Server.SSLConnect = Check_ArgIsTrue(Arg);
                return;
-        }
+       }
+       if (strcasecmp(Var, "SSLVerify") == 0) {
+               New_Server.SSLVerify = Check_ArgIsTrue(Arg);
+               return;
+       }
 #endif
        if( strcasecmp( Var, "Group" ) == 0 ) {
                /* Server group */
@@ -2029,7 +2014,7 @@ Handle_Channelname(struct Conf_Channel *new_chan, const char *name)
 /**
  * Handle variable in [Channel] configuration section.
  *
- * @param Line Line numer in configuration file.
+ * @param Line Line number in configuration file.
  * @param Var  Variable name.
  * @param Arg  Variable argument.
  */
@@ -2056,8 +2041,12 @@ Handle_CHANNEL(const char *File, int Line, char *Var, char *Arg)
        }
        if (strcasecmp(Var, "Modes") == 0) {
                /* Initial modes */
-               len = strlcpy(chan->modes, Arg, sizeof(chan->modes));
-               if (len >= sizeof(chan->modes))
+               if(chan->modes_num >= sizeof(chan->modes)) {
+                       Config_Error(LOG_ERR, "Too many Modes, option ignored.");
+                       return;
+               }
+               chan->modes[chan->modes_num++] = strndup(Arg, COMMAND_LEN);
+               if(strlen(Arg) >= COMMAND_LEN)
                        Config_Error_TooLong(File, Line, Var);
                return;
        }
@@ -2068,11 +2057,19 @@ Handle_CHANNEL(const char *File, int Line, char *Var, char *Arg)
                        Config_Error_TooLong(File, Line, Var);
                return;
        }
+       if( strcasecmp( Var, "Autojoin" ) == 0 ) {
+               /* Check autojoin */
+               chan->autojoin = Check_ArgIsTrue(Arg);
+               return;
+       }
        if( strcasecmp( Var, "Key" ) == 0 ) {
                /* Initial Channel Key (mode k) */
                len = strlcpy(chan->key, Arg, sizeof(chan->key));
                if (len >= sizeof(chan->key))
                        Config_Error_TooLong(File, Line, Var);
+               Config_Error(LOG_WARNING,
+                            "%s, line %d (section \"Channel\"): \"%s\" is deprecated here, use \"Modes = +k <key>\"!",
+                            File, Line, Var);
                return;
        }
        if( strcasecmp( Var, "MaxUsers" ) == 0 ) {
@@ -2080,6 +2077,9 @@ Handle_CHANNEL(const char *File, int Line, char *Var, char *Arg)
                chan->maxusers = (unsigned long) atol(Arg);
                if (!chan->maxusers && strcmp(Arg, "0"))
                        Config_Error_NaN(File, Line, Var);
+               Config_Error(LOG_WARNING,
+                            "%s, line %d (section \"Channel\"): \"%s\" is deprecated here, use \"Modes = +l <limit>\"!",
+                            File, Line, Var);
                return;
        }
        if (strcasecmp(Var, "KeyFile") == 0) {
@@ -2108,11 +2108,14 @@ Validate_Config(bool Configtest, bool Rehash)
 {
        /* Validate configuration settings. */
 
-#ifdef DEBUG
        int i, servers, servers_once;
-#endif
+       struct hostent *h;
        bool config_valid = true;
        char *ptr;
+#ifdef HAVE_SETRLIMIT
+       struct rlimit rlim;
+       long fd_lim_old;
+#endif
 
        /* Emit a warning when the config file is not a full path name */
        if (NGIRCd_ConfFile[0] && NGIRCd_ConfFile[0] != '/') {
@@ -2121,6 +2124,28 @@ Validate_Config(bool Configtest, bool Rehash)
                        NGIRCd_ConfFile);
        }
 
+       if (!Conf_ServerName[0]) {
+               /* No server name configured, try to get a sane name from the
+                * host name. Note: the IRC server name MUST contain
+                * at least one dot, so the "node name" is not sufficient! */
+               gethostname(Conf_ServerName, sizeof(Conf_ServerName));
+               if (Conf_DNS) {
+                       /* Try to get a proper host name ... */
+                       h = gethostbyname(Conf_ServerName);
+                       if (h)
+                               strlcpy(Conf_ServerName, h->h_name,
+                                       sizeof(Conf_ServerName));
+               }
+               if (!strchr(Conf_ServerName, '.')) {
+                       /* (Still) No dot in the name! */
+                       strlcat(Conf_ServerName, ".host",
+                               sizeof(Conf_ServerName));
+               }
+               Config_Error(LOG_WARNING,
+                            "No server name configured, using host name \"%s\".",
+                            Conf_ServerName);
+       }
+
        /* Validate configured server name, see RFC 2812 section 2.3.1 */
        ptr = Conf_ServerName;
        do {
@@ -2135,12 +2160,10 @@ Validate_Config(bool Configtest, bool Rehash)
                break;
        } while (*(++ptr));
 
-       if (!Conf_ServerName[0]) {
-               /* No server name configured! */
+       if (!Conf_ServerName[0] || !strchr(Conf_ServerName, '.')) {
                config_valid = false;
                Config_Error(LOG_ALERT,
-                            "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
-                            NGIRCd_ConfFile);
+                            "No (valid) server name configured (section 'Global': 'Name')!");
                if (!Configtest && !Rehash) {
                        Config_Error(LOG_ALERT,
                                     "%s exiting due to fatal errors!",
@@ -2149,27 +2172,12 @@ Validate_Config(bool Configtest, bool Rehash)
                }
        }
 
-       if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
-               /* No dot in server name! */
-               config_valid = false;
-               Config_Error(LOG_ALERT,
-                            "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
-                            NGIRCd_ConfFile);
-               if (!Configtest) {
-                       Config_Error(LOG_ALERT,
-                                    "%s exiting due to fatal errors!",
-                                    PACKAGE_NAME);
-                       exit(1);
-               }
-       }
-
 #ifdef STRICT_RFC
        if (!Conf_ServerAdminMail[0]) {
                /* No administrative contact configured! */
                config_valid = false;
                Config_Error(LOG_ALERT,
-                            "No administrator email address configured in \"%s\" ('AdminEMail')!",
-                            NGIRCd_ConfFile);
+                            "No administrator email address configured ('AdminEMail')!");
                if (!Configtest) {
                        Config_Error(LOG_ALERT,
                                     "%s exiting due to fatal errors!",
@@ -2187,12 +2195,58 @@ Validate_Config(bool Configtest, bool Rehash)
        }
 
 #ifdef PAM
-       if (Conf_ServerPwd[0])
+       if (Conf_PAM && Conf_ServerPwd[0])
                Config_Error(LOG_ERR,
                             "This server uses PAM, \"Password\" in [Global] section will be ignored!");
 #endif
 
-#ifdef DEBUG
+       if (Conf_MaxPenaltyTime != -1)
+               Config_Error(LOG_WARNING,
+                            "Maximum penalty increase ('MaxPenaltyTime') is set to %ld, this is not recommended!",
+                            Conf_MaxPenaltyTime);
+
+#ifdef HAVE_SETRLIMIT
+       if(getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
+               LogDebug("Current file descriptor limit is %ld, maximum %ld. \"MaxConnections\" is %ld.",
+                        (long)rlim.rlim_cur, (long)rlim.rlim_max,
+                        Conf_MaxConnections);
+               fd_lim_old = rlim.rlim_cur;
+               /* Don't request "infinite" file descriptors, use a limit! */
+               if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < MAX_FD_LIMIT)
+                       rlim.rlim_cur = rlim.rlim_max;
+               else
+                       rlim.rlim_cur = MAX_FD_LIMIT;
+               if ((long)rlim.rlim_cur != fd_lim_old) {
+                       /* Try to adjust the current file descriptor limit: */
+                       LogDebug("Trying to upgrade \"soft\" file descriptor limit: %ld -> %ld ...",
+                                fd_lim_old, (long)rlim.rlim_cur);
+                       if(setrlimit(RLIMIT_NOFILE, &rlim) != 0)
+                               Config_Error(LOG_ERR, "Failed to adjust file descriptor limit from %ld to %ld: %s",
+                                            fd_lim_old, (long)rlim.rlim_cur,
+                                            strerror(errno));
+               }
+               /* Check the (updated?) file descriptor limit: */
+               getrlimit(RLIMIT_NOFILE, &rlim);
+               if (rlim.rlim_cur != RLIM_INFINITY
+                   && (long)rlim.rlim_cur <= (long)Conf_MaxConnections) {
+                       Config_Error(LOG_WARNING,
+                                    "Current file descriptor limit (%ld) is not higher than configured \"MaxConnections\" (%ld)!",
+                                    (long)rlim.rlim_cur, Conf_MaxConnections);
+               } else if (!Configtest) {
+                       if (Conf_MaxConnections > 0)
+                               Log(LOG_INFO,
+                                   "File descriptor limit is %ld; \"MaxConnections\" is set to %ld.",
+                                   (long)rlim.rlim_cur, Conf_MaxConnections);
+                       else
+                               Log(LOG_INFO,
+                                   "File descriptor limit is %ld; \"MaxConnections\" is not set.",
+                                   (long)rlim.rlim_cur);
+               }
+       } else
+               Config_Error(LOG_ERR, "Failed to get file descriptor limit: %s",
+                            strerror(errno));
+#endif
+
        servers = servers_once = 0;
        for (i = 0; i < MAX_SERVERS; i++) {
                if (Conf_Server[i].name[0]) {
@@ -2201,12 +2255,10 @@ Validate_Config(bool Configtest, bool Rehash)
                                servers_once++;
                }
        }
-       Log(LOG_DEBUG,
-           "Configuration: Operators=%ld, Servers=%d[%d], Channels=%ld",
+       LogDebug("Configuration: Operators=%ld, Servers=%d[%d], Channels=%ld",
            array_length(&Conf_Opers, sizeof(struct Conf_Oper)),
            servers, servers_once,
            array_length(&Conf_Channels, sizeof(struct Conf_Channel)));
-#endif
 
        return config_valid;
 }
@@ -2293,7 +2345,6 @@ va_dcl
                Log(Level, "%s", msg);
 }
 
-#ifdef DEBUG
 
 /**
  * Dump internal state of the "configuration module".
@@ -2303,11 +2354,11 @@ Conf_DebugDump(void)
 {
        int i;
 
-       Log(LOG_DEBUG, "Configured servers:");
+       LogDebug("Configured servers:");
        for (i = 0; i < MAX_SERVERS; i++) {
                if (! Conf_Server[i].name[0])
                        continue;
-               Log(LOG_DEBUG,
+               LogDebug(
                    " - %s: %s:%d, last=%ld, group=%d, flags=%d, conn=%d",
                    Conf_Server[i].name, Conf_Server[i].host,
                    Conf_Server[i].port, Conf_Server[i].lasttry,
@@ -2316,10 +2367,9 @@ Conf_DebugDump(void)
        }
 }
 
-#endif
 
 /**
- * Initialize server configuration structur to default values.
+ * Initialize server configuration structure to default values.
  *
  * @param Server       Pointer to server structure to initialize.
  */
@@ -2338,6 +2388,11 @@ Init_Server_Struct( CONF_SERVER *Server )
        Proc_InitStruct(&Server->res_stat);
        Server->conn_id = NONE;
        memset(&Server->bind_addr, 0, sizeof(Server->bind_addr));
+
+#ifdef SSL_SUPPORT
+       /* Verify SSL connections by default! */
+       Server->SSLVerify = true;
+#endif
 }
 
 /* -eof- */