]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conf.c
"NoticeAuth" configuration variable is deprecated now!
[ngircd-alex.git] / src / ngircd / conf.c
index eee1925555abbe8d05a7a3cc4ba85dfced474945..62b5044c87be0daa7569846c6d07d42f1bf67417 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-2014 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 "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"
 
 
@@ -55,6 +49,7 @@ static int New_Server_Idx;
 
 static char Conf_MotdFile[FNAME_LEN];
 static char Conf_HelpFile[FNAME_LEN];
+static char Conf_IncludeDir[FNAME_LEN];
 
 static void Set_Defaults PARAMS(( bool InitServers ));
 static bool Read_Config PARAMS(( bool TestOnly, bool IsStarting ));
@@ -92,6 +87,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
 
@@ -116,6 +117,9 @@ ConfSSL_Init(void)
        array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
 
        array_free(&Conf_SSLOptions.ListenPorts);
+
+       free(Conf_SSLOptions.CipherList);
+       Conf_SSLOptions.CipherList = NULL;
 }
 
 /**
@@ -206,7 +210,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;
@@ -222,10 +226,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, "," );
@@ -316,7 +320,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
@@ -359,9 +363,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);
@@ -390,6 +394,7 @@ Conf_Test( void )
        puts("");
 
        puts("[OPTIONS]");
+       printf("  AllowedChannelTypes = %s\n", Conf_AllowedChannelTypes);
        printf("  AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
        printf("  ChrootDir = %s\n", Conf_Chroot);
        printf("  CloakHost = %s\n", Conf_CloakHost);
@@ -400,12 +405,14 @@ 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
        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));
@@ -413,7 +420,6 @@ Conf_Test( void )
        printf("  PAM = %s\n", yesno_to_str(Conf_PAM));
        printf("  PAMIsOptional = %s\n", yesno_to_str(Conf_PAMIsOptional));
 #endif
-       printf("  PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
 #ifndef STRICT_RFC
        printf("  RequireAuthPing = %s\n", yesno_to_str(Conf_AuthPing));
 #endif
@@ -429,6 +435,8 @@ Conf_Test( void )
        puts("[SSL]");
        printf("  CertFile = %s\n", Conf_SSLOptions.CertFile
                                        ? Conf_SSLOptions.CertFile : "");
+       printf("  CipherList = %s\n", Conf_SSLOptions.CipherList ?
+              Conf_SSLOptions.CipherList : DEFAULT_CIPHERS);
        printf("  DHFile = %s\n", Conf_SSLOptions.DHFile
                                        ? Conf_SSLOptions.DHFile : "");
        printf("  KeyFile = %s\n", Conf_SSLOptions.KeyFile
@@ -519,7 +527,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
                        }
                }
        }
@@ -606,6 +618,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;
                }
        }
@@ -731,6 +744,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);
@@ -756,6 +770,8 @@ Set_Defaults(bool InitServers)
        Conf_PongTimeout = 20;
 
        /* Options */
+       strlcpy(Conf_AllowedChannelTypes, CHANTYPES,
+               sizeof(Conf_AllowedChannelTypes));
        Conf_AllowRemoteOper = false;
 #ifndef STRICT_RFC
        Conf_AuthPing = false;
@@ -772,14 +788,16 @@ Set_Defaults(bool InitServers)
 #else
        Conf_ConnectIPv6 = false;
 #endif
+       strcpy(Conf_DefaultUserModes, "");
        Conf_DNS = true;
 #ifdef IDENTAUTH
        Conf_Ident = true;
 #else
        Conf_Ident = false;
 #endif
+       strcpy(Conf_IncludeDir, "");
        Conf_MorePrivacy = false;
-       Conf_NoticeAuth = false;
+       Conf_NoticeBeforeRegistration = false;
        Conf_OperCanMode = false;
        Conf_OperChanPAutoOp = true;
        Conf_OperServerMode = false;
@@ -789,9 +807,8 @@ Set_Defaults(bool InitServers)
        Conf_PAM = false;
 #endif
        Conf_PAMIsOptional = false;
-       Conf_PredefChannelsOnly = false;
-#ifdef SYSLOG
        Conf_ScrubCTCP = false;
+#ifdef SYSLOG
 #ifdef LOG_LOCAL5
        Conf_SyslogFacility = LOG_LOCAL5;
 #else
@@ -824,7 +841,7 @@ no_listenports(void)
 /**
  * Read contents of a text file into an array.
  *
- * This function is used to read the MOTD and help text file, for exampe.
+ * This function is used to read the MOTD and help text file, for example.
  *
  * @param filename     Name of the file to read.
  * @return             true, when the file has been read in.
@@ -876,8 +893,11 @@ static bool
 Read_Config(bool TestOnly, bool IsStarting)
 {
        const UINT16 defaultport = 6667;
+       char *ptr, file[FNAME_LEN];
+       struct dirent *entry;
        int i, n;
        FILE *fd;
+       DIR *dh;
 
        /* Open configuration file */
        fd = fopen( NGIRCd_ConfFile, "r" );
@@ -938,9 +958,43 @@ Read_Config(bool TestOnly, bool IsStarting)
 #endif
 
        Read_Config_File(NGIRCd_ConfFile, fd);
+       fclose(fd);
 
-       /* Close configuration file */
-       fclose( fd );
+       if (Conf_IncludeDir[0]) {
+               dh = opendir(Conf_IncludeDir);
+               if (!dh)
+                       Config_Error(LOG_ALERT,
+                                    "Can't open include directory \"%s\": %s",
+                                    Conf_IncludeDir, strerror(errno));
+       } else {
+               strlcpy(Conf_IncludeDir, SYSCONFDIR, sizeof(Conf_IncludeDir));
+               strlcat(Conf_IncludeDir, CONFIG_DIR, sizeof(Conf_IncludeDir));
+               dh = opendir(Conf_IncludeDir);
+       }
+
+       /* Include further configuration files, if IncludeDir is available */
+       if (dh) {
+               while ((entry = readdir(dh)) != NULL) {
+                       ptr = strrchr(entry->d_name, '.');
+                       if (!ptr || strcasecmp(ptr, ".conf") != 0)
+                               continue;
+                       snprintf(file, sizeof(file), "%s/%s",
+                                Conf_IncludeDir, entry->d_name);
+                       if (TestOnly)
+                               Config_Error(LOG_INFO,
+                                            "Reading configuration from \"%s\" ...",
+                                            file);
+                       fd = fopen(file, "r");
+                       if (fd) {
+                               Read_Config_File(file, fd);
+                               fclose(fd);
+                       } else
+                               Config_Error(LOG_ALERT,
+                                            "Can't read configuration \"%s\": %s",
+                                            file, strerror(errno));
+               }
+               closedir(dh);
+       }
 
        /* Check if there is still a server to add */
        if( New_Server.name[0] ) {
@@ -984,23 +1038,32 @@ 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;
        size_t count;
 
        /* 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++;
@@ -1009,6 +1072,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));
@@ -1078,7 +1147,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)
@@ -1088,7 +1157,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';
@@ -1116,7 +1185,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);
        }
 }
 
@@ -1148,7 +1217,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;
 
@@ -1156,13 +1225,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;
@@ -1172,14 +1241,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
 }
@@ -1188,14 +1257,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
 }
@@ -1204,13 +1273,13 @@ 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);
+                       File, Line);
        }
 #endif
 }
@@ -1340,6 +1409,7 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
        struct group *grp;
        size_t len;
        const char *section;
+       char *ptr;
 
        assert(File != NULL);
        assert(Line > 0);
@@ -1411,17 +1481,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))
@@ -1435,7 +1518,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) {
@@ -1447,7 +1530,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;
        }
@@ -1460,7 +1543,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);
+                                            File, Line, Var);
                }
                return;
        }
@@ -1471,11 +1554,11 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                 * 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));
+                            File, Line, NoNo(Var), InvertArg(Arg));
                if (strcasecmp(Var, "NoIdent") == 0)
-                       WarnIdent(Line);
+                       WarnIdent(File, Line);
                else if (strcasecmp(Var, "NoPam") == 0)
-                       WarnPAM(Line);
+                       WarnPAM(File, Line);
                return;
        }
        if ((section = CheckLegacyGlobalOption(File, Line, Var, Arg))) {
@@ -1485,12 +1568,12 @@ Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
                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,
+                                    File, 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, section);
                }
                return;
        }
@@ -1518,7 +1601,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;
@@ -1548,7 +1631,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) {
@@ -1562,7 +1645,7 @@ Handle_LIMITS(const char *File, int Line, char *Var, char *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;
@@ -1572,7 +1655,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;
@@ -1592,12 +1675,37 @@ static void
 Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
 {
        size_t len;
+       char *p;
 
        assert(File != NULL);
        assert(Line > 0);
        assert(Var != NULL);
        assert(Arg != NULL);
 
+       if (strcasecmp(Var, "AllowedChannelTypes") == 0) {
+               p = Arg;
+               Conf_AllowedChannelTypes[0] = '\0';
+               while (*p) {
+                       if (strchr(Conf_AllowedChannelTypes, *p)) {
+                               /* Prefix is already included; ignore it */
+                               p++;
+                               continue;
+                       }
+
+                       if (strchr(CHANTYPES, *p)) {
+                               len = strlen(Conf_AllowedChannelTypes) + 1;
+                               assert(len < sizeof(Conf_AllowedChannelTypes));
+                               Conf_AllowedChannelTypes[len - 1] = *p;
+                               Conf_AllowedChannelTypes[len] = '\0';
+                       } else {
+                               Config_Error(LOG_WARNING,
+                                            "%s, line %d: Unknown channel prefix \"%c\" in \"AllowedChannelTypes\"!",
+                                            File, Line, *p);
+                       }
+                       p++;
+               }
+               return;
+       }
        if (strcasecmp(Var, "AllowRemoteOper") == 0) {
                Conf_AllowRemoteOper = Check_ArgIsTrue(Arg);
                return;
@@ -1632,20 +1740,56 @@ 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) {
+               if (Conf_IncludeDir[0]) {
+                       Config_Error(LOG_ERR,
+                                    "%s, line %d: Can't overwrite value of \"IncludeDir\" variable!",
+                                    File, Line);
+                       return;
+               }
+               len = strlcpy(Conf_IncludeDir, Arg, sizeof(Conf_IncludeDir));
+               if (len >= sizeof(Conf_IncludeDir))
+                       Config_Error_TooLong(File, Line, Var);
                return;
        }
        if (strcasecmp(Var, "MorePrivacy") == 0) {
@@ -1653,7 +1797,19 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
                return;
        }
        if (strcasecmp(Var, "NoticeAuth") == 0) {
-               Conf_NoticeAuth = Check_ArgIsTrue(Arg);
+               /*
+                * TODO: This section and support for "NoticeAuth" variable
+                * could be removed starting with ngIRCd release 24 (one
+                * release after marking it "deprecated") ...
+                */
+               Config_Error(LOG_WARNING,
+                            "%s, line %d (section \"Options\"): \"%s\" is deprecated, please use \"NoticeBeforeRegistration\"!",
+                            File, Line, Var);
+               Conf_NoticeBeforeRegistration = Check_ArgIsTrue(Arg);
+               return;
+       }
+       if (strcasecmp(Var, "NoticeBeforeRegistration") == 0) {
+               Conf_NoticeBeforeRegistration = Check_ArgIsTrue(Arg);
                return;
        }
        if (strcasecmp(Var, "OperCanUseMode") == 0) {
@@ -1670,7 +1826,7 @@ 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 ) {
@@ -1678,7 +1834,19 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
                return;
        }
        if (strcasecmp(Var, "PredefChannelsOnly") == 0) {
-               Conf_PredefChannelsOnly = Check_ArgIsTrue(Arg);
+               /*
+                * 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));
                return;
        }
 #ifndef STRICT_RFC
@@ -1749,7 +1917,12 @@ 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;
        }
 
@@ -1845,15 +2018,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 ))
@@ -1874,8 +2047,8 @@ 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
@@ -2096,7 +2269,7 @@ 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
@@ -2228,7 +2401,7 @@ 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.
  */