2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2009 Alexander Barton (alex@barton.de)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * Please read the file COPYING, README and AUTHORS for more information.
11 * Configuration management (reading, parsing & validation)
32 #include <sys/types.h>
54 static bool Use_Log = true;
55 static CONF_SERVER New_Server;
56 static int New_Server_Idx;
58 static size_t Conf_Channel_Count;
59 static void Set_Defaults PARAMS(( bool InitServers ));
60 static bool Read_Config PARAMS(( bool ngircd_starting ));
61 static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
63 static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
64 static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
65 static void Handle_SERVER PARAMS(( int Line, char *Var, char *Arg ));
66 static void Handle_CHANNEL PARAMS(( int Line, char *Var, char *Arg ));
68 static void Config_Error PARAMS(( const int Level, const char *Format, ... ));
70 static void Config_Error_NaN PARAMS(( const int LINE, const char *Value ));
71 static void Config_Error_TooLong PARAMS(( const int LINE, const char *Value ));
73 static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
76 #define DEFAULT_LISTEN_ADDRSTR "::,0.0.0.0"
78 #define DEFAULT_LISTEN_ADDRSTR "0.0.0.0"
82 struct SSLOptions Conf_SSLOptions;
87 free(Conf_SSLOptions.KeyFile);
88 Conf_SSLOptions.KeyFile = NULL;
90 free(Conf_SSLOptions.CertFile);
91 Conf_SSLOptions.CertFile = NULL;
93 free(Conf_SSLOptions.DHFile);
94 Conf_SSLOptions.DHFile = NULL;
95 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
99 can_open(const char *name, const char *file)
101 FILE *fp = fopen(file, "r");
105 fprintf(stderr, "ERROR: %s \"%s\": %s\n",
106 name, file, strerror(errno));
115 if (Conf_SSLOptions.KeyFile) {
116 printf( " SSLKeyFile = %s\n", Conf_SSLOptions.KeyFile);
117 ret = can_open("SSLKeyFile", Conf_SSLOptions.KeyFile);
119 if (Conf_SSLOptions.CertFile) {
120 printf( " SSLCertFile = %s\n", Conf_SSLOptions.CertFile);
121 if (!can_open("SSLCertFile", Conf_SSLOptions.CertFile))
124 if (Conf_SSLOptions.DHFile) {
125 printf( " SSLDHFile = %s\n", Conf_SSLOptions.DHFile);
126 if (!can_open("SSLDHFile", Conf_SSLOptions.DHFile))
129 if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
130 puts(" SSLKeyFilePassword = <secret>" );
131 array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
138 strdup_warn(const char *str)
140 char *ptr = strdup(str);
142 Config_Error(LOG_ERR, "Could not allocate mem for string: %s", str);
152 len = array_length(a, sizeof(UINT16));
154 ports = (UINT16*) array_start(a);
155 printf("%u", (unsigned int) *ports);
158 printf(", %u", (unsigned int) *ports);
166 ports_parse(array *a, int Line, char *Arg)
174 /* Ports on that the server should listen. More port numbers
175 * must be separated by "," */
176 ptr = strtok( Arg, "," );
180 if (port > 0 && port < 0xFFFF) {
181 port16 = (UINT16) port;
182 if (!array_catb(a, (char*)&port16, sizeof port16))
183 Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
184 NGIRCd_ConfFile, Line, port, strerror(errno));
186 Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
187 NGIRCd_ConfFile, Line, port );
190 ptr = strtok( NULL, "," );
199 Validate_Config(false, false);
206 if (!Read_Config(false))
208 Validate_Config(false, true);
210 /* Update CLIENT structure of local server */
211 Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
213 } /* Config_Rehash */
217 yesno_to_str(int boolean_value)
228 /* Read configuration, validate and output it. */
234 size_t predef_channel_count;
235 struct Conf_Channel *predef_chan;
239 if (! Read_Config(true))
242 config_valid = Validate_Config(true, false);
244 /* If stdin and stdout ("you can read our nice message and we can
245 * read in your keypress") are valid tty's, wait for a key: */
246 if( isatty( fileno( stdin )) && isatty( fileno( stdout ))) {
247 puts( "OK, press enter to see a dump of your service configuration ..." );
250 puts( "Ok, dump of your server configuration follows:\n" );
254 printf( " Name = %s\n", Conf_ServerName );
255 printf( " Info = %s\n", Conf_ServerInfo );
256 printf( " Password = %s\n", Conf_ServerPwd );
257 printf( " AdminInfo1 = %s\n", Conf_ServerAdmin1 );
258 printf( " AdminInfo2 = %s\n", Conf_ServerAdmin2 );
259 printf( " AdminEMail = %s\n", Conf_ServerAdminMail );
260 printf( " MotdFile = %s\n", Conf_MotdFile );
261 printf( " MotdPhrase = %s\n", Conf_MotdPhrase );
262 printf( " ChrootDir = %s\n", Conf_Chroot );
263 printf( " PidFile = %s\n", Conf_PidFile);
264 printf(" Listen = %s\n", Conf_ListenAddress);
265 fputs(" Ports = ", stdout);
267 ports_puts(&Conf_ListenPorts);
269 fputs(" SSLPorts = ", stdout);
270 ports_puts(&Conf_SSLOptions.ListenPorts);
272 config_valid = false;
275 pwd = getpwuid( Conf_UID );
276 if( pwd ) printf( " ServerUID = %s\n", pwd->pw_name );
277 else printf( " ServerUID = %ld\n", (long)Conf_UID );
278 grp = getgrgid( Conf_GID );
279 if( grp ) printf( " ServerGID = %s\n", grp->gr_name );
280 else printf( " ServerGID = %ld\n", (long)Conf_GID );
281 printf( " PingTimeout = %d\n", Conf_PingTimeout );
282 printf( " PongTimeout = %d\n", Conf_PongTimeout );
283 printf( " ConnectRetry = %d\n", Conf_ConnectRetry );
284 printf( " OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
285 printf( " OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
286 printf( " PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
287 printf( " NoDNS = %s\n", yesno_to_str(Conf_NoDNS));
288 printf( " NoIdent = %s\n", yesno_to_str(Conf_NoIdent));
291 printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
292 printf(" ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
294 printf( " MaxConnections = %ld\n", Conf_MaxConnections);
295 printf( " MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
296 printf( " MaxJoins = %d\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
297 printf( " MaxNickLength = %u\n\n", Conf_MaxNickLength - 1);
299 for( i = 0; i < Conf_Oper_Count; i++ ) {
300 if( ! Conf_Oper[i].name[0] ) continue;
302 /* Valid "Operator" section */
303 puts( "[OPERATOR]" );
304 printf( " Name = %s\n", Conf_Oper[i].name );
305 printf( " Password = %s\n", Conf_Oper[i].pwd );
306 if ( Conf_Oper[i].mask ) printf( " Mask = %s\n", Conf_Oper[i].mask );
310 for( i = 0; i < MAX_SERVERS; i++ ) {
311 if( ! Conf_Server[i].name[0] ) continue;
313 /* Valid "Server" section */
315 printf( " Name = %s\n", Conf_Server[i].name );
316 printf( " Host = %s\n", Conf_Server[i].host );
317 printf( " Port = %u\n", (unsigned int)Conf_Server[i].port );
319 printf( " SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
321 printf( " MyPassword = %s\n", Conf_Server[i].pwd_in );
322 printf( " PeerPassword = %s\n", Conf_Server[i].pwd_out );
323 printf( " ServiceMask = %s\n", Conf_Server[i].svs_mask);
324 printf( " Group = %d\n", Conf_Server[i].group );
325 printf( " Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
328 predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan));
329 predef_chan = array_start(&Conf_Channels);
331 for (i = 0; i < predef_channel_count; i++, predef_chan++) {
332 if (!predef_chan->name[0])
335 /* Valid "Channel" section */
337 printf(" Name = %s\n", predef_chan->name);
338 printf(" Modes = %s\n", predef_chan->modes);
339 printf(" Key = %s\n", predef_chan->key);
340 printf(" MaxUsers = %lu\n", predef_chan->maxusers);
341 printf(" Topic = %s\n", predef_chan->topic);
342 printf(" KeyFile = %s\n\n", predef_chan->keyfile);
345 return (config_valid ? 0 : 1);
350 Conf_UnsetServer( CONN_ID Idx )
352 /* Set next time for next connection attempt, if this is a server
353 * link that is (still) configured here. If the server is set as
354 * "once", delete it from our configuration.
355 * Non-Server-Connections will be silently ignored. */
360 /* Check all our configured servers */
361 for( i = 0; i < MAX_SERVERS; i++ ) {
362 if( Conf_Server[i].conn_id != Idx ) continue;
364 /* Gotcha! Mark server configuration as "unused": */
365 Conf_Server[i].conn_id = NONE;
367 if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
368 /* Delete configuration here */
369 Init_Server_Struct( &Conf_Server[i] );
371 /* Set time for next connect attempt */
373 if (Conf_Server[i].lasttry < t - Conf_ConnectRetry) {
374 /* The connection has been "long", so we don't
375 * require the next attempt to be delayed. */
376 Conf_Server[i].lasttry =
377 t - Conf_ConnectRetry + RECONNECT_DELAY;
379 Conf_Server[i].lasttry = t;
382 } /* Conf_UnsetServer */
386 Conf_SetServer( int ConfServer, CONN_ID Idx )
388 /* Set connection for specified configured server */
390 assert( ConfServer > NONE );
391 assert( Idx > NONE );
393 Conf_Server[ConfServer].conn_id = Idx;
394 } /* Conf_SetServer */
398 Conf_GetServer( CONN_ID Idx )
400 /* Get index of server in configuration structure */
404 assert( Idx > NONE );
406 for( i = 0; i < MAX_SERVERS; i++ ) {
407 if( Conf_Server[i].conn_id == Idx ) return i;
410 } /* Conf_GetServer */
414 Conf_EnableServer( const char *Name, UINT16 Port )
416 /* Enable specified server and adjust port */
420 assert( Name != NULL );
422 for( i = 0; i < MAX_SERVERS; i++ ) {
423 if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
424 /* Gotcha! Set port and enable server: */
425 Conf_Server[i].port = Port;
426 Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
427 return (Conf_Server[i].port && Conf_Server[i].host[0]);
431 } /* Conf_EnableServer */
435 Conf_EnablePassiveServer(const char *Name)
437 /* Enable specified server */
440 assert( Name != NULL );
441 for (i = 0; i < MAX_SERVERS; i++) {
442 if ((strcasecmp( Conf_Server[i].name, Name ) == 0) && (Conf_Server[i].port > 0)) {
443 /* BINGO! Enable server */
444 Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
449 } /* Conf_EnablePassiveServer */
453 Conf_DisableServer( const char *Name )
455 /* Enable specified server and adjust port */
459 assert( Name != NULL );
461 for( i = 0; i < MAX_SERVERS; i++ ) {
462 if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
463 /* Gotcha! Disable and disconnect server: */
464 Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
465 if( Conf_Server[i].conn_id > NONE ) Conn_Close( Conf_Server[i].conn_id, NULL, "Server link terminated on operator request", true);
470 } /* Conf_DisableServer */
474 Conf_AddServer( const char *Name, UINT16 Port, const char *Host, const char *MyPwd, const char *PeerPwd )
476 /* Add new server to configuration */
480 assert( Name != NULL );
481 assert( Host != NULL );
482 assert( MyPwd != NULL );
483 assert( PeerPwd != NULL );
485 /* Search unused item in server configuration structure */
486 for( i = 0; i < MAX_SERVERS; i++ ) {
487 /* Is this item used? */
488 if( ! Conf_Server[i].name[0] ) break;
490 if( i >= MAX_SERVERS ) return false;
492 Init_Server_Struct( &Conf_Server[i] );
493 strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
494 strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
495 strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
496 strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
497 Conf_Server[i].port = Port;
498 Conf_Server[i].flags = CONF_SFLAG_ONCE;
501 } /* Conf_AddServer */
505 * Check if the given nick name is an service
508 Conf_IsService(int ConfServer, const char *Nick)
510 return MatchCaseInsensitive(Conf_Server[ConfServer].svs_mask, Nick);
511 } /* Conf_IsService */
515 Set_Defaults( bool InitServers )
517 /* Initialize configuration variables with default values. */
521 strcpy( Conf_ServerName, "" );
522 snprintf( Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION );
523 strcpy( Conf_ServerPwd, "" );
525 strcpy( Conf_ServerAdmin1, "" );
526 strcpy( Conf_ServerAdmin2, "" );
527 strcpy( Conf_ServerAdminMail, "" );
529 strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile ));
530 strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile ));
532 strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase ));
534 strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot ));
536 strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile ));
538 free(Conf_ListenAddress);
539 Conf_ListenAddress = NULL;
540 Conf_UID = Conf_GID = 0;
542 Conf_PingTimeout = 120;
543 Conf_PongTimeout = 20;
545 Conf_ConnectRetry = 60;
548 Conf_Channel_Count = 0;
550 Conf_OperCanMode = false;
552 Conf_NoIdent = false;
553 Conf_PredefChannelsOnly = false;
554 Conf_OperServerMode = false;
556 Conf_ConnectIPv4 = true;
557 Conf_ConnectIPv6 = true;
559 Conf_MaxConnections = 0;
560 Conf_MaxConnectionsIP = 5;
562 Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
564 /* Initialize server configuration structures */
565 if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
572 size_t cnt = array_bytes(&Conf_ListenPorts);
574 cnt += array_bytes(&Conf_SSLOptions.ListenPorts);
580 Read_Config( bool ngircd_starting )
582 /* Read configuration file. */
584 char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
585 const UINT16 defaultport = 6667;
589 /* Open configuration file */
590 fd = fopen( NGIRCd_ConfFile, "r" );
592 /* No configuration file found! */
593 Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
594 NGIRCd_ConfFile, strerror( errno ));
595 if (!ngircd_starting)
597 Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
601 Set_Defaults( ngircd_starting );
603 Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
605 /* Clean up server configuration structure: mark all already
606 * configured servers as "once" so that they are deleted
607 * after the next disconnect and delete all unused servers.
608 * And delete all servers which are "duplicates" of servers
609 * that are already marked as "once" (such servers have been
610 * created by the last rehash but are now useless). */
611 for( i = 0; i < MAX_SERVERS; i++ ) {
612 if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
614 /* This structure is in use ... */
615 if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
616 /* Check for duplicates */
617 for( n = 0; n < MAX_SERVERS; n++ ) {
618 if( n == i ) continue;
620 if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
621 Init_Server_Struct( &Conf_Server[n] );
623 Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
629 /* Mark server as "once" */
630 Conf_Server[i].flags |= CONF_SFLAG_ONCE;
631 Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
636 /* Initialize variables */
638 strcpy( section, "" );
639 Init_Server_Struct( &New_Server );
640 New_Server_Idx = NONE;
644 /* Read configuration file */
646 if( ! fgets( str, LINE_LEN, fd )) break;
650 /* Skip comments and empty lines */
651 if( str[0] == ';' || str[0] == '#' || str[0] == '\0' ) continue;
653 /* Is this the beginning of a new section? */
654 if(( str[0] == '[' ) && ( str[strlen( str ) - 1] == ']' )) {
655 strlcpy( section, str, sizeof( section ));
656 if( strcasecmp( section, "[GLOBAL]" ) == 0 )
659 if( strcasecmp( section, "[OPERATOR]" ) == 0 ) {
660 if( Conf_Oper_Count + 1 > MAX_OPERATORS )
661 Config_Error( LOG_ERR, "Too many operators configured.");
663 /* Initialize new operator structure */
664 Conf_Oper[Conf_Oper_Count].name[0] = '\0';
665 Conf_Oper[Conf_Oper_Count].pwd[0] = '\0';
666 if (Conf_Oper[Conf_Oper_Count].mask) {
667 free(Conf_Oper[Conf_Oper_Count].mask );
668 Conf_Oper[Conf_Oper_Count].mask = NULL;
674 if( strcasecmp( section, "[SERVER]" ) == 0 ) {
675 /* Check if there is already a server to add */
676 if( New_Server.name[0] ) {
677 /* Copy data to "real" server structure */
678 assert( New_Server_Idx > NONE );
679 Conf_Server[New_Server_Idx] = New_Server;
682 /* Re-init structure for new server */
683 Init_Server_Struct( &New_Server );
685 /* Search unused item in server configuration structure */
686 for( i = 0; i < MAX_SERVERS; i++ ) {
687 /* Is this item used? */
688 if( ! Conf_Server[i].name[0] ) break;
690 if( i >= MAX_SERVERS ) {
691 /* Oops, no free item found! */
692 Config_Error( LOG_ERR, "Too many servers configured." );
693 New_Server_Idx = NONE;
695 else New_Server_Idx = i;
698 if (strcasecmp(section, "[CHANNEL]") == 0) {
699 Conf_Channel_Count++;
703 Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section );
706 if( section[0] == 0x1 ) continue;
708 /* Split line into variable name and parameters */
709 ptr = strchr( str, '=' );
711 Config_Error( LOG_ERR, "%s, line %d: Syntax error!", NGIRCd_ConfFile, line );
715 var = str; ngt_TrimStr( var );
716 arg = ptr + 1; ngt_TrimStr( arg );
718 if( strcasecmp( section, "[GLOBAL]" ) == 0 ) Handle_GLOBAL( line, var, arg );
719 else if( strcasecmp( section, "[OPERATOR]" ) == 0 ) Handle_OPERATOR( line, var, arg );
720 else if( strcasecmp( section, "[SERVER]" ) == 0 ) Handle_SERVER( line, var, arg );
721 else if( strcasecmp( section, "[CHANNEL]" ) == 0 ) Handle_CHANNEL( line, var, arg );
722 else Config_Error( LOG_ERR, "%s, line %d: Variable \"%s\" outside section!", NGIRCd_ConfFile, line, var );
725 /* Close configuration file */
728 /* Check if there is still a server to add */
729 if( New_Server.name[0] ) {
730 /* Copy data to "real" server structure */
731 assert( New_Server_Idx > NONE );
732 Conf_Server[New_Server_Idx] = New_Server;
735 /* not a single listening port? Add default. */
736 if (no_listenports() &&
737 !array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport))
739 Config_Error(LOG_ALERT, "Could not add default listening Port %u: %s",
740 (unsigned int) defaultport, strerror(errno));
745 if (!Conf_ListenAddress)
746 Conf_ListenAddress = strdup_warn(DEFAULT_LISTEN_ADDRSTR);
748 if (!Conf_ListenAddress) {
749 Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
757 Check_ArgIsTrue( const char *Arg )
759 if( strcasecmp( Arg, "yes" ) == 0 ) return true;
760 if( strcasecmp( Arg, "true" ) == 0 ) return true;
761 if( atoi( Arg ) != 0 ) return true;
764 } /* Check_ArgIsTrue */
767 static unsigned int Handle_MaxNickLength(int Line, const char *Arg)
771 new = (unsigned) atoi(Arg) + 1;
772 if (new > CLIENT_NICK_LEN) {
773 Config_Error(LOG_WARNING,
774 "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
775 NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
776 return CLIENT_NICK_LEN;
779 Config_Error(LOG_WARNING,
780 "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
781 NGIRCd_ConfFile, Line);
785 } /* Handle_MaxNickLength */
789 Handle_GLOBAL( int Line, char *Var, char *Arg )
796 assert( Var != NULL );
797 assert( Arg != NULL );
799 if( strcasecmp( Var, "Name" ) == 0 ) {
801 len = strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName ));
802 if (len >= sizeof( Conf_ServerName ))
803 Config_Error_TooLong( Line, Var );
806 if( strcasecmp( Var, "Info" ) == 0 ) {
807 /* Info text of server */
808 len = strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo ));
809 if (len >= sizeof( Conf_ServerInfo ))
810 Config_Error_TooLong ( Line, Var );
813 if( strcasecmp( Var, "Password" ) == 0 ) {
814 /* Global server password */
815 len = strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd ));
816 if (len >= sizeof( Conf_ServerPwd ))
817 Config_Error_TooLong( Line, Var );
820 if( strcasecmp( Var, "AdminInfo1" ) == 0 ) {
821 /* Administrative info #1 */
822 len = strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 ));
823 if (len >= sizeof( Conf_ServerAdmin1 ))
824 Config_Error_TooLong ( Line, Var );
827 if( strcasecmp( Var, "AdminInfo2" ) == 0 ) {
828 /* Administrative info #2 */
829 len = strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 ));
830 if (len >= sizeof( Conf_ServerAdmin2 ))
831 Config_Error_TooLong ( Line, Var );
834 if( strcasecmp( Var, "AdminEMail" ) == 0 ) {
835 /* Administrative email contact */
836 len = strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail ));
837 if (len >= sizeof( Conf_ServerAdminMail ))
838 Config_Error_TooLong( Line, Var );
842 if( strcasecmp( Var, "Ports" ) == 0 ) {
843 ports_parse(&Conf_ListenPorts, Line, Arg);
846 if( strcasecmp( Var, "MotdFile" ) == 0 ) {
847 /* "Message of the day" (MOTD) file */
848 len = strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile ));
849 if (len >= sizeof( Conf_MotdFile ))
850 Config_Error_TooLong( Line, Var );
853 if( strcasecmp( Var, "MotdPhrase" ) == 0 ) {
854 /* "Message of the day" phrase (instead of file) */
855 len = strlcpy( Conf_MotdPhrase, Arg, sizeof( Conf_MotdPhrase ));
856 if (len >= sizeof( Conf_MotdPhrase ))
857 Config_Error_TooLong( Line, Var );
860 if( strcasecmp( Var, "ChrootDir" ) == 0 ) {
861 /* directory for chroot() */
862 len = strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot ));
863 if (len >= sizeof( Conf_Chroot ))
864 Config_Error_TooLong( Line, Var );
867 if ( strcasecmp( Var, "PidFile" ) == 0 ) {
868 /* name of pidfile */
869 len = strlcpy( Conf_PidFile, Arg, sizeof( Conf_PidFile ));
870 if (len >= sizeof( Conf_PidFile ))
871 Config_Error_TooLong( Line, Var );
874 if( strcasecmp( Var, "ServerUID" ) == 0 ) {
875 /* UID the daemon should switch to */
876 pwd = getpwnam( Arg );
877 if( pwd ) Conf_UID = pwd->pw_uid;
880 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
883 Conf_UID = (unsigned int)atoi( Arg );
887 if( strcasecmp( Var, "ServerGID" ) == 0 ) {
888 /* GID the daemon should use */
889 grp = getgrnam( Arg );
890 if( grp ) Conf_GID = grp->gr_gid;
893 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
896 Conf_GID = (unsigned int)atoi( Arg );
900 if( strcasecmp( Var, "PingTimeout" ) == 0 ) {
902 Conf_PingTimeout = atoi( Arg );
903 if( Conf_PingTimeout < 5 ) {
904 Config_Error( LOG_WARNING, "%s, line %d: Value of \"PingTimeout\" too low!",
905 NGIRCd_ConfFile, Line );
906 Conf_PingTimeout = 5;
910 if( strcasecmp( Var, "PongTimeout" ) == 0 ) {
912 Conf_PongTimeout = atoi( Arg );
913 if( Conf_PongTimeout < 5 ) {
914 Config_Error( LOG_WARNING, "%s, line %d: Value of \"PongTimeout\" too low!",
915 NGIRCd_ConfFile, Line );
916 Conf_PongTimeout = 5;
920 if( strcasecmp( Var, "ConnectRetry" ) == 0 ) {
921 /* Seconds between connection attempts to other servers */
922 Conf_ConnectRetry = atoi( Arg );
923 if( Conf_ConnectRetry < 5 ) {
924 Config_Error( LOG_WARNING, "%s, line %d: Value of \"ConnectRetry\" too low!",
925 NGIRCd_ConfFile, Line );
926 Conf_ConnectRetry = 5;
930 if( strcasecmp( Var, "PredefChannelsOnly" ) == 0 ) {
931 /* Should we only allow pre-defined-channels? (i.e. users cannot create their own channels) */
932 Conf_PredefChannelsOnly = Check_ArgIsTrue( Arg );
935 if( strcasecmp( Var, "NoDNS" ) == 0 ) {
936 /* don't do reverse dns lookups when clients connect? */
937 Conf_NoDNS = Check_ArgIsTrue( Arg );
940 if (strcasecmp(Var, "NoIdent") == 0) {
941 /* don't do IDENT lookups when clients connect? */
942 Conf_NoIdent = Check_ArgIsTrue(Arg);
945 /* user has enabled ident lookups explicitly, but ... */
946 Config_Error(LOG_WARNING,
947 "%s: line %d: NoIdent=False, but ngircd was built without IDENT support",
948 NGIRCd_ConfFile, Line);
954 /* the default setting for all the WANT_IPV6 special options is 'true' */
955 if( strcasecmp( Var, "ConnectIPv6" ) == 0 ) {
956 /* connect to other hosts using ipv6, if they have an AAAA record? */
957 Conf_ConnectIPv6 = Check_ArgIsTrue( Arg );
960 if( strcasecmp( Var, "ConnectIPv4" ) == 0 ) {
961 /* connect to other hosts using ipv4.
962 * again, this can be used for ipv6-only setups */
963 Conf_ConnectIPv4 = Check_ArgIsTrue( Arg );
967 if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
968 /* Are IRC operators allowed to use MODE in channels they aren't Op in? */
969 Conf_OperCanMode = Check_ArgIsTrue( Arg );
972 if( strcasecmp( Var, "OperServerMode" ) == 0 ) {
973 /* Mask IRC operator as if coming from the server? (ircd-irc2 compat hack) */
974 Conf_OperServerMode = Check_ArgIsTrue( Arg );
977 if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
978 /* Maximum number of connections. 0 -> "no limit". */
980 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
983 Conf_MaxConnections = atol( Arg );
986 if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
987 /* Maximum number of simultaneous connections from one IP. 0 -> "no limit" */
989 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
992 Conf_MaxConnectionsIP = atoi( Arg );
995 if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
996 /* Maximum number of channels a user can join. 0 -> "no limit". */
998 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
1001 Conf_MaxJoins = atoi( Arg );
1004 if( strcasecmp( Var, "MaxNickLength" ) == 0 ) {
1005 /* Maximum length of a nick name; must be same on all servers
1006 * within the IRC network! */
1007 Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
1011 if( strcasecmp( Var, "Listen" ) == 0 ) {
1012 /* IP-Address to bind sockets */
1013 if (Conf_ListenAddress) {
1014 Config_Error(LOG_ERR, "Multiple Listen= options, ignoring: %s", Arg);
1017 Conf_ListenAddress = strdup_warn(Arg);
1019 * if allocation fails, we're in trouble:
1020 * we cannot ignore the error -- otherwise ngircd
1021 * would listen on all interfaces.
1023 if (!Conf_ListenAddress) {
1024 Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
1031 if( strcasecmp( Var, "SSLPorts" ) == 0 ) {
1032 ports_parse(&Conf_SSLOptions.ListenPorts, Line, Arg);
1036 if( strcasecmp( Var, "SSLKeyFile" ) == 0 ) {
1037 assert(Conf_SSLOptions.KeyFile == NULL );
1038 Conf_SSLOptions.KeyFile = strdup_warn(Arg);
1041 if( strcasecmp( Var, "SSLCertFile" ) == 0 ) {
1042 assert(Conf_SSLOptions.CertFile == NULL );
1043 Conf_SSLOptions.CertFile = strdup_warn(Arg);
1047 if( strcasecmp( Var, "SSLKeyFilePassword" ) == 0 ) {
1048 assert(array_bytes(&Conf_SSLOptions.KeyFilePassword) == 0);
1049 if (!array_copys(&Conf_SSLOptions.KeyFilePassword, Arg))
1050 Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Could not copy %s: %s!",
1051 NGIRCd_ConfFile, Line, Var, strerror(errno));
1054 if( strcasecmp( Var, "SSLDHFile" ) == 0 ) {
1055 assert(Conf_SSLOptions.DHFile == NULL);
1056 Conf_SSLOptions.DHFile = strdup_warn( Arg );
1060 Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
1061 NGIRCd_ConfFile, Line, Var);
1062 } /* Handle_GLOBAL */
1066 Handle_OPERATOR( int Line, char *Var, char *Arg )
1068 unsigned int opercount;
1071 assert( Var != NULL );
1072 assert( Arg != NULL );
1073 assert( Conf_Oper_Count > 0 );
1075 if ( Conf_Oper_Count == 0 )
1078 opercount = Conf_Oper_Count - 1;
1080 if( strcasecmp( Var, "Name" ) == 0 ) {
1081 /* Name of IRC operator */
1082 len = strlcpy( Conf_Oper[opercount].name, Arg, sizeof( Conf_Oper[opercount].name ));
1083 if (len >= sizeof( Conf_Oper[opercount].name ))
1084 Config_Error_TooLong( Line, Var );
1087 if( strcasecmp( Var, "Password" ) == 0 ) {
1088 /* Password of IRC operator */
1089 len = strlcpy( Conf_Oper[opercount].pwd, Arg, sizeof( Conf_Oper[opercount].pwd ));
1090 if (len >= sizeof( Conf_Oper[opercount].pwd ))
1091 Config_Error_TooLong( Line, Var );
1094 if( strcasecmp( Var, "Mask" ) == 0 ) {
1095 if (Conf_Oper[opercount].mask) return; /* Hostname already configured */
1097 Conf_Oper[opercount].mask = strdup_warn( Arg );
1100 Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!",
1101 NGIRCd_ConfFile, Line, Var );
1102 } /* Handle_OPERATOR */
1106 Handle_SERVER( int Line, char *Var, char *Arg )
1112 assert( Var != NULL );
1113 assert( Arg != NULL );
1115 /* Ignore server block if no space is left in server configuration structure */
1116 if( New_Server_Idx <= NONE ) return;
1118 if( strcasecmp( Var, "Host" ) == 0 ) {
1119 /* Hostname of the server */
1120 len = strlcpy( New_Server.host, Arg, sizeof( New_Server.host ));
1121 if (len >= sizeof( New_Server.host ))
1122 Config_Error_TooLong ( Line, Var );
1125 if( strcasecmp( Var, "Name" ) == 0 ) {
1126 /* Name of the server ("Nick"/"ID") */
1127 len = strlcpy( New_Server.name, Arg, sizeof( New_Server.name ));
1128 if (len >= sizeof( New_Server.name ))
1129 Config_Error_TooLong( Line, Var );
1132 if (strcasecmp(Var, "Bind") == 0) {
1133 if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
1136 Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
1137 NGIRCd_ConfFile, Line, Arg);
1140 if( strcasecmp( Var, "MyPassword" ) == 0 ) {
1141 /* Password of this server which is sent to the peer */
1143 Config_Error(LOG_ERR,
1144 "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
1145 NGIRCd_ConfFile, Line);
1147 len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
1148 if (len >= sizeof( New_Server.pwd_in ))
1149 Config_Error_TooLong( Line, Var );
1152 if( strcasecmp( Var, "PeerPassword" ) == 0 ) {
1153 /* Passwort of the peer which must be received */
1154 len = strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out ));
1155 if (len >= sizeof( New_Server.pwd_out ))
1156 Config_Error_TooLong( Line, Var );
1159 if( strcasecmp( Var, "Port" ) == 0 ) {
1160 /* Port to which this server should connect */
1162 if( port > 0 && port < 0xFFFF )
1163 New_Server.port = (UINT16)port;
1165 Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Illegal port number %ld!",
1166 NGIRCd_ConfFile, Line, port );
1170 if( strcasecmp( Var, "SSLConnect" ) == 0 ) {
1171 New_Server.SSLConnect = Check_ArgIsTrue(Arg);
1175 if( strcasecmp( Var, "Group" ) == 0 ) {
1178 if( ! isdigit( (int)*Arg ))
1179 Config_Error_NaN( Line, Var );
1182 New_Server.group = atoi( Arg );
1185 if( strcasecmp( Var, "Passive" ) == 0 ) {
1186 if (Check_ArgIsTrue(Arg))
1187 New_Server.flags |= CONF_SFLAG_DISABLED;
1190 if (strcasecmp(Var, "ServiceMask") == 0) {
1191 len = strlcpy(New_Server.svs_mask, ngt_LowerStr(Arg),
1192 sizeof(New_Server.svs_mask));
1193 if (len >= sizeof(New_Server.svs_mask))
1194 Config_Error_TooLong(Line, Var);
1198 Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
1199 NGIRCd_ConfFile, Line, Var );
1200 } /* Handle_SERVER */
1204 Handle_Channelname(struct Conf_Channel *new_chan, const char *name)
1206 size_t size = sizeof(new_chan->name);
1207 char *dest = new_chan->name;
1209 if (!Channel_IsValidName(name)) {
1211 * maybe user forgot to add a '#'.
1212 * This is only here for user convenience.
1218 return size > strlcpy(dest, name, size);
1223 Handle_CHANNEL(int Line, char *Var, char *Arg)
1227 struct Conf_Channel *chan;
1230 assert( Var != NULL );
1231 assert( Arg != NULL );
1232 assert(Conf_Channel_Count > 0);
1234 chancount = Conf_Channel_Count - 1;
1236 chan = array_alloc(&Conf_Channels, sizeof(*chan), chancount);
1238 Config_Error(LOG_ERR, "Could not allocate memory for predefined channel (%d:%s = %s)", Line, Var, Arg);
1241 if (strcasecmp(Var, "Name") == 0) {
1242 if (!Handle_Channelname(chan, Arg))
1243 Config_Error_TooLong(Line, Var);
1246 if (strcasecmp(Var, "Modes") == 0) {
1248 len = strlcpy(chan->modes, Arg, sizeof(chan->modes));
1249 if (len >= sizeof(chan->modes))
1250 Config_Error_TooLong( Line, Var );
1253 if( strcasecmp( Var, "Topic" ) == 0 ) {
1255 len = strlcpy(chan->topic, Arg, sizeof(chan->topic));
1256 if (len >= sizeof(chan->topic))
1257 Config_Error_TooLong( Line, Var );
1260 if( strcasecmp( Var, "Key" ) == 0 ) {
1261 /* Initial Channel Key (mode k) */
1262 len = strlcpy(chan->key, Arg, sizeof(chan->key));
1263 if (len >= sizeof(chan->key))
1264 Config_Error_TooLong(Line, Var);
1267 if( strcasecmp( Var, "MaxUsers" ) == 0 ) {
1268 /* maximum user limit, mode l */
1269 chan->maxusers = (unsigned long) atol(Arg);
1270 if (chan->maxusers == 0)
1271 Config_Error_NaN(Line, Var);
1274 if (strcasecmp(Var, "KeyFile") == 0) {
1276 len = strlcpy(chan->keyfile, Arg, sizeof(chan->keyfile));
1277 if (len >= sizeof(chan->keyfile))
1278 Config_Error_TooLong(Line, Var);
1282 Config_Error( LOG_ERR, "%s, line %d (section \"Channel\"): Unknown variable \"%s\"!",
1283 NGIRCd_ConfFile, Line, Var );
1284 } /* Handle_CHANNEL */
1288 Validate_Config(bool Configtest, bool Rehash)
1290 /* Validate configuration settings. */
1293 int i, servers, servers_once;
1295 bool config_valid = true;
1298 /* Validate configured server name, see RFC 2812 section 2.3.1 */
1299 ptr = Conf_ServerName;
1301 if (*ptr >= 'a' && *ptr <= 'z') continue;
1302 if (*ptr >= 'A' && *ptr <= 'Z') continue;
1303 if (*ptr >= '0' && *ptr <= '9') continue;
1304 if (ptr > Conf_ServerName) {
1305 if (*ptr == '.' || *ptr == '-')
1308 Conf_ServerName[0] = '\0';
1312 if (!Conf_ServerName[0]) {
1313 /* No server name configured! */
1314 config_valid = false;
1315 Config_Error(LOG_ALERT,
1316 "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
1318 if (!Configtest && !Rehash) {
1319 Config_Error(LOG_ALERT,
1320 "%s exiting due to fatal errors!",
1326 if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
1327 /* No dot in server name! */
1328 config_valid = false;
1329 Config_Error(LOG_ALERT,
1330 "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
1333 Config_Error(LOG_ALERT,
1334 "%s exiting due to fatal errors!",
1341 if (!Conf_ServerAdminMail[0]) {
1342 /* No administrative contact configured! */
1343 config_valid = false;
1344 Config_Error(LOG_ALERT,
1345 "No administrator email address configured in \"%s\" ('AdminEMail')!",
1348 Config_Error(LOG_ALERT,
1349 "%s exiting due to fatal errors!",
1356 if (!Conf_ServerAdmin1[0] && !Conf_ServerAdmin2[0]
1357 && !Conf_ServerAdminMail[0]) {
1358 /* No administrative information configured! */
1359 Config_Error(LOG_WARNING,
1360 "No administrative information configured but required by RFC!");
1364 servers = servers_once = 0;
1365 for (i = 0; i < MAX_SERVERS; i++) {
1366 if (Conf_Server[i].name[0]) {
1368 if (Conf_Server[i].flags & CONF_SFLAG_ONCE)
1373 "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
1374 Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
1377 return config_valid;
1378 } /* Validate_Config */
1382 Config_Error_TooLong ( const int Line, const char *Item )
1384 Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" too long!", NGIRCd_ConfFile, Line, Item );
1389 Config_Error_NaN( const int Line, const char *Item )
1391 Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!",
1392 NGIRCd_ConfFile, Line, Item );
1397 static void Config_Error( const int Level, const char *Format, ... )
1399 static void Config_Error( Level, Format, va_alist )
1405 /* Error! Write to console and/or logfile. */
1407 char msg[MAX_LOG_MSG_LEN];
1410 assert( Format != NULL );
1413 va_start( ap, Format );
1417 vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap );
1420 /* During "normal operations" the log functions of the daemon should
1421 * be used, but during testing of the configuration file, all messages
1422 * should go directly to the console: */
1423 if (Use_Log) Log( Level, "%s", msg );
1425 } /* Config_Error */
1429 Init_Server_Struct( CONF_SERVER *Server )
1431 /* Initialize server configuration structur to default values */
1433 assert( Server != NULL );
1435 memset( Server, 0, sizeof (CONF_SERVER) );
1437 Server->group = NONE;
1438 Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
1440 if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
1442 Resolve_Init(&Server->res_stat);
1443 Server->conn_id = NONE;
1444 memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
1445 } /* Init_Server_Struct */