]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conf.c
New "chroot" feature (from Benjamin Pineau), introducing new configuration
[ngircd-alex.git] / src / ngircd / conf.c
index c12658d9e17329a8c3cfe9408cced78b9b938cac..1ea1fe741ef3397c35a6d151c1bac575c4c1eec7 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: conf.c,v 1.52 2002/12/30 00:01:45 alex Exp $";
+static char UNUSED id[] = "$Id: conf.c,v 1.64 2004/05/07 11:19:21 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -23,6 +23,7 @@ static char UNUSED id[] = "$Id: conf.c,v 1.52 2002/12/30 00:01:45 alex Exp $";
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <grp.h>
@@ -108,11 +109,13 @@ Conf_Test( VOID )
        puts( "[GLOBAL]" );
        printf( "  ServerName = %s\n", Conf_ServerName );
        printf( "  ServerInfo = %s\n", Conf_ServerInfo );
-       printf( "  ServerPwd = %s\n", Conf_ServerPwd );
+       printf( "  Password = %s\n", Conf_ServerPwd );
        printf( "  AdminInfo1 = %s\n", Conf_ServerAdmin1 );
        printf( "  AdminInfo2 = %s\n", Conf_ServerAdmin2 );
        printf( "  AdminEMail = %s\n", Conf_ServerAdminMail );
        printf( "  MotdFile = %s\n", Conf_MotdFile );
+       printf( "  MotdPhrase = %s\n", Conf_MotdPhrase );
+       printf( "  ChrootDir= %s\n", Conf_Chroot );
        printf( "  Ports = " );
        for( i = 0; i < Conf_ListenPorts_Count; i++ )
        {
@@ -120,6 +123,7 @@ Conf_Test( VOID )
                printf( "%u", Conf_ListenPorts[i] );
        }
        puts( "" );
+       printf( "  Listen = %s\n", Conf_ListenAddress );
        pwd = getpwuid( Conf_UID );
        if( pwd ) printf( "  ServerUID = %s\n", pwd->pw_name );
        else printf( "  ServerUID = %ld\n", (LONG)Conf_UID );
@@ -132,6 +136,8 @@ Conf_Test( VOID )
        printf( "  OperCanUseMode = %s\n", Conf_OperCanMode == TRUE ? "yes" : "no" );
        if( Conf_MaxConnections > 0 ) printf( "  MaxConnections = %ld\n", Conf_MaxConnections );
        else printf( "  MaxConnections = -1\n" );
+       if( Conf_MaxConnectionsIP > 0 ) printf( "  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP );
+       else printf( "  MaxConnectionsIP = -1\n" );
        if( Conf_MaxJoins > 0 ) printf( "  MaxJoins = %d\n", Conf_MaxJoins );
        else printf( "  MaxJoins = -1\n" );
        puts( "" );
@@ -196,7 +202,7 @@ Conf_UnsetServer( CONN_ID Idx )
                /* Gotcha! Mark server configuration as "unused": */
                Conf_Server[i].conn_id = NONE;
 
-               if( Conf_Server[i].once )
+               if( Conf_Server[i].flags & CONF_SFLAG_ONCE )
                {
                        /* Delete configuration here */
                        Init_Server_Struct( &Conf_Server[i] );
@@ -210,7 +216,6 @@ Conf_UnsetServer( CONN_ID Idx )
                                Conf_Server[i].lasttry = time( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY;
                        }
                }
-               break;
        }
 } /* Conf_UnsetServer */
 
@@ -231,9 +236,9 @@ GLOBAL INT
 Conf_GetServer( CONN_ID Idx )
 {
        /* Get index of server in configuration structure */
-
-       INT i;
-
+       
+       INT i = 0;
+       
        assert( Idx > NONE );
 
        for( i = 0; i < MAX_SERVERS; i++ )
@@ -244,6 +249,84 @@ Conf_GetServer( CONN_ID Idx )
 } /* Conf_GetServer */
 
 
+GLOBAL BOOLEAN
+Conf_EnableServer( CHAR *Name, INT Port )
+{
+       /* Enable specified server and adjust port */
+
+       INT i;
+
+       assert( Name != NULL );
+
+       for( i = 0; i < MAX_SERVERS; i++ )
+       {
+               if( strcasecmp( Conf_Server[i].name, Name ) == 0 )
+               {
+                       /* Gotcha! Set port and enable server: */
+                       Conf_Server[i].port = Port;
+                       Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+} /* Conf_EnableServer */
+
+
+GLOBAL BOOLEAN
+Conf_DisableServer( CHAR *Name )
+{
+       /* Enable specified server and adjust port */
+
+       INT i;
+
+       assert( Name != NULL );
+
+       for( i = 0; i < MAX_SERVERS; i++ )
+       {
+               if( strcasecmp( Conf_Server[i].name, Name ) == 0 )
+               {
+                       /* Gotcha! Disable and disconnect server: */
+                       Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
+                       if( Conf_Server[i].conn_id > NONE ) Conn_Close( Conf_Server[i].conn_id, NULL, "Server link terminated on operator request", TRUE );
+                       return TRUE;
+               }
+       }
+       return FALSE;
+} /* Conf_DisableServer */
+
+
+GLOBAL BOOLEAN
+Conf_AddServer( CHAR *Name, INT Port, CHAR *Host, CHAR *MyPwd, CHAR *PeerPwd )
+{
+       /* Add new server to configuration */
+
+       INT i;
+
+       assert( Name != NULL );
+       assert( Host != NULL );
+       assert( MyPwd != NULL );
+       assert( PeerPwd != NULL );
+
+       /* Search unused item in server configuration structure */
+       for( i = 0; i < MAX_SERVERS; i++ )
+       {
+               /* Is this item used? */
+               if( ! Conf_Server[i].name[0] ) break;
+       }
+       if( i >= MAX_SERVERS ) return FALSE;
+
+       Init_Server_Struct( &Conf_Server[i] );
+       strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
+       strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
+       strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
+       strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
+       Conf_Server[i].port = Port;
+       Conf_Server[i].flags = CONF_SFLAG_ONCE;
+       
+       return TRUE;
+} /* Conf_AddServer */
+
+
 LOCAL VOID
 Set_Defaults( BOOLEAN InitServers )
 {
@@ -252,7 +335,7 @@ Set_Defaults( BOOLEAN InitServers )
        INT i;
 
        strcpy( Conf_ServerName, "" );
-       sprintf( Conf_ServerInfo, "%s %s", PACKAGEVERSION );
+       sprintf( Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION );
        strcpy( Conf_ServerPwd, "" );
 
        strcpy( Conf_ServerAdmin1, "" );
@@ -262,7 +345,12 @@ Set_Defaults( BOOLEAN InitServers )
        strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile ));
        strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile ));
 
+       strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase ));
+
+       strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot ));
+
        Conf_ListenPorts_Count = 0;
+       strcpy( Conf_ListenAddress, "" );
 
        Conf_UID = Conf_GID = 0;
        
@@ -277,6 +365,7 @@ Set_Defaults( BOOLEAN InitServers )
        Conf_OperCanMode = FALSE;
        
        Conf_MaxConnections = -1;
+       Conf_MaxConnectionsIP = 5;
        Conf_MaxJoins = 10;
 
        /* Initialize server configuration structures */
@@ -290,7 +379,7 @@ Read_Config( VOID )
        /* Read configuration file. */
 
        CHAR section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
-       INT line, i;
+       INT line, i, n;
        FILE *fd;
 
        /* Open configuration file */
@@ -299,7 +388,7 @@ Read_Config( VOID )
        {
                /* No configuration file found! */
                Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s", NGIRCd_ConfFile, strerror( errno ));
-               Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE );
+               Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
                exit( 1 );
        }
 
@@ -307,11 +396,37 @@ Read_Config( VOID )
 
        /* Clean up server configuration structure: mark all already
         * configured servers as "once" so that they are deleted
-        * after the next disconnect and delete all unused servers. */
+        * after the next disconnect and delete all unused servers.
+        * And delete all servers which are "duplicates" of servers
+        * that are already marked as "once" (such servers have been
+        * created by the last rehash but are now useless). */
        for( i = 0; i < MAX_SERVERS; i++ )
        {
                if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
-               else Conf_Server[i].once = TRUE;
+               else
+               {
+                       /* This structure is in use ... */
+                       if( Conf_Server[i].flags & CONF_SFLAG_ONCE )
+                       {
+                               /* Check for duplicates */
+                               for( n = 0; n < MAX_SERVERS; n++ )
+                               {
+                                       if( n == i ) continue;
+
+                                       if( Conf_Server[i].conn_id == Conf_Server[n].conn_id )
+                                       {
+                                               Init_Server_Struct( &Conf_Server[n] );
+                                               Log( LOG_DEBUG, "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 );
+                       }
+               }
        }
 
        /* Initialize variables */
@@ -504,6 +619,18 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg )
                if( strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile )) >= sizeof( Conf_MotdFile )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MotdFile\" too long!", NGIRCd_ConfFile, Line );
                return;
        }
+       if( strcasecmp( Var, "MotdPhrase" ) == 0 )
+       {
+               /* "Message of the day" phrase (instead of file) */
+               if( strlcpy( Conf_MotdPhrase, Arg, sizeof( Conf_MotdPhrase )) >= sizeof( Conf_MotdPhrase )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MotdPhrase\" too long!", NGIRCd_ConfFile, Line );
+               return;
+       }
+       if( strcasecmp( Var, "ChrootDir" ) == 0 )
+       {
+               /* directory for chroot() */
+               if( strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot )) >= sizeof( Conf_Chroot )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ChrootDir\" too long!", NGIRCd_ConfFile, Line );
+               return;
+       }
        if( strcasecmp( Var, "ServerUID" ) == 0 )
        {
                /* UID the daemon should switch to */
@@ -512,7 +639,7 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg )
                else
                {
 #ifdef HAVE_ISDIGIT
-                       if( ! isdigit( *Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ServerUID\" is not a number!", NGIRCd_ConfFile, Line );
+                       if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ServerUID\" is not a number!", NGIRCd_ConfFile, Line );
                        else
 #endif
                        Conf_UID = (UINT)atoi( Arg );
@@ -527,7 +654,7 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg )
                else
                {
 #ifdef HAVE_ISDIGIT
-                       if( ! isdigit( *Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ServerGID\" is not a number!", NGIRCd_ConfFile, Line );
+                       if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ServerGID\" is not a number!", NGIRCd_ConfFile, Line );
                        else
 #endif
                        Conf_GID = (UINT)atoi( Arg );
@@ -580,22 +707,41 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg )
        {
                /* Maximum number of connections. Values <= 0 are equal to "no limit". */
 #ifdef HAVE_ISDIGIT
-               if( ! isdigit( *Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MaxConnections\" is not a number!", NGIRCd_ConfFile, Line );
+               if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MaxConnections\" is not a number!", NGIRCd_ConfFile, Line );
                else
 #endif
                Conf_MaxConnections = atol( Arg );
                return;
        }
+       if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 )
+       {
+               /* Maximum number of simoultanous connections from one IP. Values <= 0 are equal to "no limit". */
+#ifdef HAVE_ISDIGIT
+               if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MaxConnectionsIP\" is not a number!", NGIRCd_ConfFile, Line );
+               else
+#endif
+               Conf_MaxConnectionsIP = atoi( Arg );
+               return;
+       }
        if( strcasecmp( Var, "MaxJoins" ) == 0 )
        {
                /* Maximum number of channels a user can join. Values <= 0 are equal to "no limit". */
 #ifdef HAVE_ISDIGIT
-               if( ! isdigit( *Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MaxJoins\" is not a number!", NGIRCd_ConfFile, Line );
+               if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MaxJoins\" is not a number!", NGIRCd_ConfFile, Line );
                else
 #endif
                Conf_MaxJoins = atoi( Arg );
                return;
        }
+       if( strcasecmp( Var, "Listen" ) == 0 )
+       {
+               /* IP-Address to bind sockets */
+               if( strlcpy( Conf_ListenAddress, Arg, sizeof( Conf_ListenAddress )) >= sizeof( Conf_ListenAddress ))
+               {
+                       Config_Error( LOG_WARNING, "%s, line %d: Value of \"Listen\" too long!", NGIRCd_ConfFile, Line );
+               }
+               return;
+       }
 
        Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var );
 } /* Handle_GLOBAL */
@@ -674,7 +820,7 @@ Handle_SERVER( INT Line, CHAR *Var, CHAR *Arg )
        {
                /* Server group */
 #ifdef HAVE_ISDIGIT
-               if( ! isdigit( *Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Group\" is not a number!", NGIRCd_ConfFile, Line );
+               if( ! isdigit( (INT)*Arg )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Group\" is not a number!", NGIRCd_ConfFile, Line );
                else
 #endif
                New_Server.group = atoi( Arg );
@@ -727,10 +873,21 @@ Validate_Config( BOOLEAN Configtest )
        if( ! Conf_ServerName[0] )
        {
                /* No server name configured! */
-               Config_Error( LOG_ALERT, "No server name configured in \"%s\" ('ServerName')!", NGIRCd_ConfFile );
+               Config_Error( LOG_ALERT, "No server name configured in \"%s\" (section 'Global': 'Name')!", NGIRCd_ConfFile );
+               if( ! Configtest )
+               {
+                       Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
+                       exit( 1 );
+               }
+       }
+       
+       if( Conf_ServerName[0] && ! strchr( Conf_ServerName, '.' ))
+       {
+               /* No dot in server name! */
+               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 );
+                       Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
                        exit( 1 );
                }
        }
@@ -742,7 +899,7 @@ Validate_Config( BOOLEAN Configtest )
                Config_Error( LOG_ALERT, "No administrator email address configured in \"%s\" ('AdminEMail')!", NGIRCd_ConfFile );
                if( ! Configtest )
                {
-                       Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE );
+                       Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
                        exit( 1 );
                }
        }
@@ -770,7 +927,7 @@ Validate_Config( BOOLEAN Configtest )
                if( Conf_Server[i].name[0] )
                {
                        servers++;
-                       if( Conf_Server[i].once ) servers_once++;
+                       if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) servers_once++;
                }
        }
        Log( LOG_DEBUG, "Configuration: Operators=%d, Servers=%d[%d], Channels=%d", Conf_Oper_Count, servers, servers_once, Conf_Channel_Count );
@@ -826,7 +983,8 @@ Init_Server_Struct( CONF_SERVER *Server )
        Server->group = NONE;
        Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
        Server->res_stat = NULL;
-       Server->once = FALSE;
+       if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
+       else Server->flags = 0;
        Server->conn_id = NONE;
 } /* Init_Server_Struct */