X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconf.c;h=f00c263346cdbc250cf525a57f9bbe05a01c4d7e;hp=50c9ee1b2c6c764eb1098a1651ed1c26d1d20646;hb=1d08d51e2eaff14b71f20d3f0898d5a86582b7e5;hpb=695631b2984111a825346396dc56635a2fe3a7c4 diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index 50c9ee1b..f00c2633 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -14,15 +14,20 @@ #include "portab.h" -static char UNUSED id[] = "$Id: conf.c,v 1.51 2002/12/26 17:04:54 alex Exp $"; +static char UNUSED id[] = "$Id: conf.c,v 1.70 2005/03/15 16:56:18 alex Exp $"; #include "imp.h" #include #include -#include +#ifdef PROTOTYPES +# include +#else +# include +#endif #include #include #include +#include #include #include #include @@ -46,9 +51,11 @@ static char UNUSED id[] = "$Id: conf.c,v 1.51 2002/12/26 17:04:54 alex Exp $"; LOCAL BOOLEAN Use_Log = TRUE; +LOCAL CONF_SERVER New_Server; +LOCAL INT New_Server_Idx; -LOCAL VOID Set_Defaults PARAMS(( VOID )); +LOCAL VOID Set_Defaults PARAMS(( BOOLEAN InitServers )); LOCAL VOID Read_Config PARAMS(( VOID )); LOCAL VOID Validate_Config PARAMS(( BOOLEAN TestOnly )); @@ -59,16 +66,30 @@ LOCAL VOID Handle_CHANNEL PARAMS(( INT Line, CHAR *Var, CHAR *Arg )); LOCAL VOID Config_Error PARAMS(( CONST INT Level, CONST CHAR *Format, ... )); +LOCAL VOID Config_Error_NaN PARAMS(( INT LINE, CONST CHAR *Value )); +LOCAL VOID Config_Error_TooLong PARAMS(( INT LINE, CONST CHAR *Value )); + +LOCAL VOID Init_Server_Struct PARAMS(( CONF_SERVER *Server )); + GLOBAL VOID Conf_Init( VOID ) { - Set_Defaults( ); + Set_Defaults( TRUE ); Read_Config( ); Validate_Config( FALSE ); } /* Config_Init */ +GLOBAL VOID +Conf_Rehash( VOID ) +{ + Set_Defaults( FALSE ); + Read_Config( ); + Validate_Config( FALSE ); +} /* Config_Rehash */ + + GLOBAL INT Conf_Test( VOID ) { @@ -79,7 +100,7 @@ Conf_Test( VOID ) INT i; Use_Log = FALSE; - Set_Defaults( ); + Set_Defaults( TRUE ); Read_Config( ); Validate_Config( TRUE ); @@ -93,13 +114,16 @@ Conf_Test( VOID ) else puts( "Ok, dump of your server configuration follows:\n" ); puts( "[GLOBAL]" ); - printf( " ServerName = %s\n", Conf_ServerName ); - printf( " ServerInfo = %s\n", Conf_ServerInfo ); - printf( " ServerPwd = %s\n", Conf_ServerPwd ); + printf( " Name = %s\n", Conf_ServerName ); + printf( " Info = %s\n", Conf_ServerInfo ); + 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( " PidFile = %s\n", Conf_PidFile); printf( " Ports = " ); for( i = 0; i < Conf_ListenPorts_Count; i++ ) { @@ -107,6 +131,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 ); @@ -117,8 +142,11 @@ Conf_Test( VOID ) printf( " PongTimeout = %d\n", Conf_PongTimeout ); printf( " ConnectRetry = %d\n", Conf_ConnectRetry ); printf( " OperCanUseMode = %s\n", Conf_OperCanMode == TRUE ? "yes" : "no" ); + printf( " OperServerMode = %s\n", Conf_OperServerMode == 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( "" ); @@ -131,10 +159,11 @@ Conf_Test( VOID ) puts( "[OPERATOR]" ); printf( " Name = %s\n", Conf_Oper[i].name ); printf( " Password = %s\n", Conf_Oper[i].pwd ); + if ( Conf_Oper[i].mask ) printf( " Mask = %s\n", Conf_Oper[i].mask ); puts( "" ); } - for( i = 0; i < Conf_Server_Count; i++ ) + for( i = 0; i < MAX_SERVERS; i++ ) { if( ! Conf_Server[i].name[0] ) continue; @@ -165,13 +194,158 @@ Conf_Test( VOID ) } /* Conf_Test */ +GLOBAL VOID +Conf_UnsetServer( CONN_ID Idx ) +{ + /* Set next time for next connection attempt, if this is a server + * link that is (still) configured here. If the server is set as + * "once", delete it from our configuration. + * Non-Server-Connections will be silently ignored. */ + + INT i; + + /* Check all our configured servers */ + for( i = 0; i < MAX_SERVERS; i++ ) + { + if( Conf_Server[i].conn_id != Idx ) continue; + + /* Gotcha! Mark server configuration as "unused": */ + Conf_Server[i].conn_id = NONE; + + if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) + { + /* Delete configuration here */ + Init_Server_Struct( &Conf_Server[i] ); + } + else + { + /* Set time for next connect attempt */ + if( Conf_Server[i].lasttry < time( NULL ) - Conf_ConnectRetry ) + { + /* Okay, the connection was established "long enough": */ + Conf_Server[i].lasttry = time( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY; + } + } + } +} /* Conf_UnsetServer */ + + +GLOBAL VOID +Conf_SetServer( INT ConfServer, CONN_ID Idx ) +{ + /* Set connection for specified configured server */ + + assert( ConfServer > NONE ); + assert( Idx > NONE ); + + Conf_Server[ConfServer].conn_id = Idx; +} /* Conf_SetServer */ + + +GLOBAL INT +Conf_GetServer( CONN_ID Idx ) +{ + /* Get index of server in configuration structure */ + + INT i = 0; + + assert( Idx > NONE ); + + for( i = 0; i < MAX_SERVERS; i++ ) + { + if( Conf_Server[i].conn_id == Idx ) return i; + } + return NONE; +} /* 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( VOID ) +Set_Defaults( BOOLEAN InitServers ) { /* Initialize configuration variables with default values. */ + INT i; + strcpy( Conf_ServerName, "" ); - sprintf( Conf_ServerInfo, "%s %s", PACKAGE, VERSION ); + sprintf( Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION ); strcpy( Conf_ServerPwd, "" ); strcpy( Conf_ServerAdmin1, "" ); @@ -181,7 +355,14 @@ Set_Defaults( VOID ) 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 )); + + strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile )); + Conf_ListenPorts_Count = 0; + strcpy( Conf_ListenAddress, "" ); Conf_UID = Conf_GID = 0; @@ -191,13 +372,17 @@ Set_Defaults( VOID ) Conf_ConnectRetry = 60; Conf_Oper_Count = 0; - Conf_Server_Count = 0; Conf_Channel_Count = 0; Conf_OperCanMode = FALSE; + Conf_OperServerMode = FALSE; Conf_MaxConnections = -1; + Conf_MaxConnectionsIP = 5; Conf_MaxJoins = 10; + + /* Initialize server configuration structures */ + if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] )); } /* Set_Defaults */ @@ -207,22 +392,63 @@ Read_Config( VOID ) /* Read configuration file. */ CHAR section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr; - INT line; + INT line, i, n; FILE *fd; + /* 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 )); - 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 ); } Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile ); + /* 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. + * 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 + { + /* 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 */ line = 0; strcpy( section, "" ); + Init_Server_Struct( &New_Server ); + New_Server_Idx = NONE; + + /* Read configuration file */ while( TRUE ) { if( ! fgets( str, LINE_LEN, fd )) break; @@ -243,29 +469,42 @@ Read_Config( VOID ) else { /* Initialize new operator structure */ - strcpy( Conf_Oper[Conf_Oper_Count].name, "" ); - strcpy( Conf_Oper[Conf_Oper_Count].pwd, "" ); + Conf_Oper[Conf_Oper_Count].name[0] = '\0'; + Conf_Oper[Conf_Oper_Count].pwd[0] = '\0'; + if (Conf_Oper[Conf_Oper_Count].mask) { + free(Conf_Oper[Conf_Oper_Count].mask ); + Conf_Oper[Conf_Oper_Count].mask = NULL; + } Conf_Oper_Count++; } continue; } if( strcasecmp( section, "[SERVER]" ) == 0 ) { - if( Conf_Server_Count + 1 > MAX_SERVERS ) Config_Error( LOG_ERR, "Too many servers configured." ); - else + /* Check if there is already a server to add */ + if( New_Server.name[0] ) + { + /* Copy data to "real" server structure */ + assert( New_Server_Idx > NONE ); + Conf_Server[New_Server_Idx] = New_Server; + } + + /* Re-init structure for new server */ + Init_Server_Struct( &New_Server ); + + /* Search unused item in server configuration structure */ + for( i = 0; i < MAX_SERVERS; i++ ) { - /* Initialize new server structure */ - strcpy( Conf_Server[Conf_Server_Count].host, "" ); - strcpy( Conf_Server[Conf_Server_Count].ip, "" ); - strcpy( Conf_Server[Conf_Server_Count].name, "" ); - strcpy( Conf_Server[Conf_Server_Count].pwd_in, "" ); - strcpy( Conf_Server[Conf_Server_Count].pwd_out, "" ); - Conf_Server[Conf_Server_Count].port = 0; - Conf_Server[Conf_Server_Count].group = -1; - Conf_Server[Conf_Server_Count].lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY; - Conf_Server[Conf_Server_Count].res_stat = NULL; - Conf_Server_Count++; + /* Is this item used? */ + if( ! Conf_Server[i].name[0] ) break; } + if( i >= MAX_SERVERS ) + { + /* Oops, no free item found! */ + Config_Error( LOG_ERR, "Too many servers configured." ); + New_Server_Idx = NONE; + } + else New_Server_Idx = i; continue; } if( strcasecmp( section, "[CHANNEL]" ) == 0 ) @@ -303,8 +542,17 @@ Read_Config( VOID ) else if( strcasecmp( section, "[CHANNEL]" ) == 0 ) Handle_CHANNEL( line, var, arg ); else Config_Error( LOG_ERR, "%s, line %d: Variable \"%s\" outside section!", NGIRCd_ConfFile, line, var ); } - + + /* Close configuration file */ fclose( fd ); + + /* Check if there is still a server to add */ + if( New_Server.name[0] ) + { + /* Copy data to "real" server structure */ + assert( New_Server_Idx > NONE ); + Conf_Server[New_Server_Idx] = New_Server; + } /* If there are no ports configured use the default: 6667 */ if( Conf_ListenPorts_Count < 1 ) @@ -315,6 +563,17 @@ Read_Config( VOID ) } /* Read_Config */ +LOCAL BOOLEAN +Check_ArgIsTrue( const char *Arg ) +{ + if( strcasecmp( Arg, "yes" ) == 0 ) return TRUE; + if( strcasecmp( Arg, "true" ) == 0 ) return TRUE; + if( atoi( Arg ) != 0 ) return TRUE; + + return FALSE; +} /* Check_ArgIsTrue */ + + LOCAL VOID Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) { @@ -330,37 +589,43 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) if( strcasecmp( Var, "Name" ) == 0 ) { /* Server name */ - if( strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName )) >= sizeof( Conf_ServerName )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Name\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName )) >= sizeof( Conf_ServerName )) + Config_Error_TooLong( Line, Var ); + return; } if( strcasecmp( Var, "Info" ) == 0 ) { /* Info text of server */ - if( strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo )) >= sizeof( Conf_ServerInfo )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Info\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo )) >= sizeof( Conf_ServerInfo )) + Config_Error_TooLong ( Line, Var ); + return; } if( strcasecmp( Var, "Password" ) == 0 ) { /* Global server password */ - if( strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd )) >= sizeof( Conf_ServerPwd )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Password\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd )) >= sizeof( Conf_ServerPwd )) + Config_Error_TooLong( Line, Var ); + return; } if( strcasecmp( Var, "AdminInfo1" ) == 0 ) { /* Administrative info #1 */ - if( strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 )) >= sizeof( Conf_ServerAdmin1 )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"AdminInfo1\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 )) >= sizeof( Conf_ServerAdmin1 )) Config_Error_TooLong ( Line, Var ); return; } if( strcasecmp( Var, "AdminInfo2" ) == 0 ) { /* Administrative info #2 */ - if( strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 )) >= sizeof( Conf_ServerAdmin2 )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"AdminInfo2\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 )) >= sizeof( Conf_ServerAdmin2 )) Config_Error_TooLong ( Line, Var ); return; } if( strcasecmp( Var, "AdminEMail" ) == 0 ) { /* Administrative email contact */ - if( strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail )) >= sizeof( Conf_ServerAdminMail )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"AdminEMail\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail )) >= sizeof( Conf_ServerAdminMail )) Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Ports" ) == 0 ) @@ -385,9 +650,37 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) if( strcasecmp( Var, "MotdFile" ) == 0 ) { /* "Message of the day" (MOTD) file */ - 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 ); + if( strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile )) >= sizeof( Conf_MotdFile )) + Config_Error_TooLong( Line, Var ); + + 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_TooLong( Line, Var ); + + return; + } + if( strcasecmp( Var, "ChrootDir" ) == 0 ) + { + /* directory for chroot() */ + if( strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot )) >= sizeof( Conf_Chroot )) + Config_Error_TooLong( Line, Var ); + return; } + + if ( strcasecmp( Var, "PidFile" ) == 0 ) + { + /* name of pidfile */ + if( strlcpy( Conf_PidFile, Arg, sizeof( Conf_PidFile )) >= sizeof( Conf_PidFile )) + Config_Error_TooLong( Line, Var ); + + return; + } + if( strcasecmp( Var, "ServerUID" ) == 0 ) { /* UID the daemon should switch to */ @@ -396,7 +689,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_NaN( Line, Var ); else #endif Conf_UID = (UINT)atoi( Arg ); @@ -411,7 +704,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_NaN( Line, Var ); else #endif Conf_GID = (UINT)atoi( Arg ); @@ -454,32 +747,54 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) { /* Are IRC operators allowed to use MODE in channels they aren't Op in? */ - if( strcasecmp( Arg, "yes" ) == 0 ) Conf_OperCanMode = TRUE; - else if( strcasecmp( Arg, "true" ) == 0 ) Conf_OperCanMode = TRUE; - else if( atoi( Arg ) != 0 ) Conf_OperCanMode = TRUE; - else Conf_OperCanMode = FALSE; + Conf_OperCanMode = Check_ArgIsTrue( Arg ); + return; + } + if( strcasecmp( Var, "OperServerMode" ) == 0 ) + { + /* Mask IRC operator as if coming from the server? (ircd-irc2 compat hack) */ + Conf_OperServerMode = Check_ArgIsTrue( Arg ); return; } if( strcasecmp( Var, "MaxConnections" ) == 0 ) { /* 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_NaN( Line, Var); 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_NaN( Line, Var ); + 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_NaN( Line, Var ); 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_TooLong( Line, Var ); + } + return; + } Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var ); } /* Handle_GLOBAL */ @@ -488,6 +803,7 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) LOCAL VOID Handle_OPERATOR( INT Line, CHAR *Var, CHAR *Arg ) { + unsigned int len; assert( Line > 0 ); assert( Var != NULL ); assert( Arg != NULL ); @@ -496,16 +812,28 @@ Handle_OPERATOR( INT Line, CHAR *Var, CHAR *Arg ) if( strcasecmp( Var, "Name" ) == 0 ) { /* Name of IRC operator */ - if( strlcpy( Conf_Oper[Conf_Oper_Count - 1].name, Arg, sizeof( Conf_Oper[Conf_Oper_Count - 1].name )) >= sizeof( Conf_Oper[Conf_Oper_Count - 1].name )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Name\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_Oper[Conf_Oper_Count - 1].name, Arg, sizeof( Conf_Oper[Conf_Oper_Count - 1].name )) >= sizeof( Conf_Oper[Conf_Oper_Count - 1].name )) Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Password" ) == 0 ) { /* Password of IRC operator */ - if( strlcpy( Conf_Oper[Conf_Oper_Count - 1].pwd, Arg, sizeof( Conf_Oper[Conf_Oper_Count - 1].pwd )) >= sizeof( Conf_Oper[Conf_Oper_Count - 1].pwd )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Password\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_Oper[Conf_Oper_Count - 1].pwd, Arg, sizeof( Conf_Oper[Conf_Oper_Count - 1].pwd )) >= sizeof( Conf_Oper[Conf_Oper_Count - 1].pwd )) Config_Error_TooLong( Line, Var ); + return; + } + if( strcasecmp( Var, "Mask" ) == 0 ) + { + if (Conf_Oper[Conf_Oper_Count - 1].mask) return; /* Hostname already configured */ + len = strlen( Arg ) + 1; + Conf_Oper[Conf_Oper_Count - 1].mask = malloc( len ); + if (! Conf_Oper[Conf_Oper_Count - 1].mask) { + Config_Error( LOG_ERR, "%s, line %d: Cannot allocate memory for operator mask: %s", NGIRCd_ConfFile, Line, strerror(errno) ); + return; + } + + strlcpy( Conf_Oper[Conf_Oper_Count - 1].mask, Arg, len); return; } - Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!", NGIRCd_ConfFile, Line, Var ); } /* Handle_OPERATOR */ @@ -519,35 +847,41 @@ Handle_SERVER( INT Line, CHAR *Var, CHAR *Arg ) assert( Var != NULL ); assert( Arg != NULL ); + /* Ignore server block if no space is left in server configuration structure */ + if( New_Server_Idx <= NONE ) return; + if( strcasecmp( Var, "Host" ) == 0 ) { /* Hostname of the server */ - if( strlcpy( Conf_Server[Conf_Server_Count - 1].host, Arg, sizeof( Conf_Server[Conf_Server_Count - 1].host )) >= sizeof( Conf_Server[Conf_Server_Count - 1].host )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Host\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( New_Server.host, Arg, sizeof( New_Server.host )) >= sizeof( New_Server.host )) + Config_Error_TooLong ( Line, Var ); + return; } if( strcasecmp( Var, "Name" ) == 0 ) { /* Name of the server ("Nick"/"ID") */ - if( strlcpy( Conf_Server[Conf_Server_Count - 1].name, Arg, sizeof( Conf_Server[Conf_Server_Count - 1].name )) >= sizeof( Conf_Server[Conf_Server_Count - 1].name )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Name\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( New_Server.name, Arg, sizeof( New_Server.name )) >= sizeof( New_Server.name )) + Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "MyPassword" ) == 0 ) { /* Password of this server which is sent to the peer */ - if( strlcpy( Conf_Server[Conf_Server_Count - 1].pwd_in, Arg, sizeof( Conf_Server[Conf_Server_Count - 1].pwd_in )) >= sizeof( Conf_Server[Conf_Server_Count - 1].pwd_in )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MyPassword\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in )) >= sizeof( New_Server.pwd_in )) Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "PeerPassword" ) == 0 ) { /* Passwort of the peer which must be received */ - if( strlcpy( Conf_Server[Conf_Server_Count - 1].pwd_out, Arg, sizeof( Conf_Server[Conf_Server_Count - 1].pwd_out )) >= sizeof( Conf_Server[Conf_Server_Count - 1].pwd_out )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"PeerPassword\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out )) >= sizeof( New_Server.pwd_out )) Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Port" ) == 0 ) { /* Port to which this server should connect */ port = atol( Arg ); - if( port > 0 && port < 0xFFFF ) Conf_Server[Conf_Server_Count - 1].port = (INT)port; + if( port > 0 && port < 0xFFFF ) New_Server.port = (INT)port; else Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Illegal port number %ld!", NGIRCd_ConfFile, Line, port ); return; } @@ -555,10 +889,10 @@ 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_NaN( Line, Var ); else #endif - Conf_Server[Conf_Server_Count - 1].group = atoi( Arg ); + New_Server.group = atoi( Arg ); return; } @@ -576,19 +910,23 @@ Handle_CHANNEL( INT Line, CHAR *Var, CHAR *Arg ) if( strcasecmp( Var, "Name" ) == 0 ) { /* Name of the channel */ - if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].name, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].name )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].name )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Name\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].name, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].name )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].name )) + Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Modes" ) == 0 ) { /* Initial modes */ - if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].modes, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].modes )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].modes )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Modes\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].modes, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].modes )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].modes )) + Config_Error_TooLong( Line, Var ); return; } if( strcasecmp( Var, "Topic" ) == 0 ) { /* Initial topic */ - if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].topic, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].topic )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].topic )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"Topic\" too long!", NGIRCd_ConfFile, Line ); + if( strlcpy( Conf_Channel[Conf_Channel_Count - 1].topic, Arg, sizeof( Conf_Channel[Conf_Channel_Count - 1].topic )) >= sizeof( Conf_Channel[Conf_Channel_Count - 1].topic )) + Config_Error_TooLong( Line, Var ); + return; } @@ -600,14 +938,29 @@ LOCAL VOID Validate_Config( BOOLEAN Configtest ) { /* Validate configuration settings. */ - + +#ifdef DEBUG + INT i, servers, servers_once; +#endif + 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 ); } } @@ -619,7 +972,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 ); } } @@ -639,9 +992,34 @@ Validate_Config( BOOLEAN Configtest ) #else Config_Error( LOG_WARN, "Don't know how many file descriptors select() can handle on this system, don't set MaxConnections too high!" ); #endif + +#ifdef DEBUG + servers = servers_once = 0; + for( i = 0; i < MAX_SERVERS; i++ ) + { + if( Conf_Server[i].name[0] ) + { + servers++; + 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 ); +#endif } /* Validate_Config */ +LOCAL VOID +Config_Error_TooLong ( CONST INT Line, CONST CHAR *Item ) +{ + Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" too long!", NGIRCd_ConfFile, Line, Item ); +} + +LOCAL VOID +Config_Error_NaN( CONST INT Line, CONST CHAR *Item ) +{ + Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!", NGIRCd_ConfFile, Line, Item ); +} + #ifdef PROTOTYPES LOCAL VOID Config_Error( CONST INT Level, CONST CHAR *Format, ... ) #else @@ -674,4 +1052,22 @@ va_dcl } /* Config_Error */ +LOCAL VOID +Init_Server_Struct( CONF_SERVER *Server ) +{ + /* Initialize server configuration structur to default values */ + + assert( Server != NULL ); + + memset( Server, 0, sizeof (CONF_SERVER) ); + + Server->group = NONE; + Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY; + + if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED; + + Server->conn_id = NONE; +} /* Init_Server_Struct */ + + /* -eof- */