]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conf.c
Make sourcecode compatible with ansi2knr again
[ngircd-alex.git] / src / ngircd / conf.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
4  *
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.
10  *
11  * Configuration management (reading, parsing & validation)
12  */
13
14
15 #include "portab.h"
16
17 #include "imp.h"
18 #include <assert.h>
19 #include <errno.h>
20 #ifdef PROTOTYPES
21 #       include <stdarg.h>
22 #else
23 #       include <varargs.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <unistd.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #ifdef HAVE_CTYPE_H
36 # include <ctype.h>
37 #endif
38
39 #include "array.h"
40 #include "ngircd.h"
41 #include "conn.h"
42 #include "channel.h"
43 #include "defines.h"
44 #include "log.h"
45 #include "match.h"
46 #include "tool.h"
47
48 #include "exp.h"
49 #include "conf.h"
50
51
52 static bool Use_Log = true;
53 static CONF_SERVER New_Server;
54 static int New_Server_Idx;
55
56 static size_t Conf_Oper_Count;
57 static size_t Conf_Channel_Count;
58 static char Conf_MotdFile[FNAME_LEN];
59
60 static void Set_Defaults PARAMS(( bool InitServers ));
61 static bool Read_Config PARAMS(( bool ngircd_starting ));
62 static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
63
64 static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
65 static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
66 static void Handle_SERVER PARAMS(( int Line, char *Var, char *Arg ));
67 static void Handle_CHANNEL PARAMS(( int Line, char *Var, char *Arg ));
68
69 static void Config_Error PARAMS(( const int Level, const char *Format, ... ));
70
71 static void Config_Error_NaN PARAMS(( const int LINE, const char *Value ));
72 static void Config_Error_TooLong PARAMS(( const int LINE, const char *Value ));
73
74 static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
75
76 #ifdef WANT_IPV6
77 #define DEFAULT_LISTEN_ADDRSTR "::,0.0.0.0"
78 #else
79 #define DEFAULT_LISTEN_ADDRSTR "0.0.0.0"
80 #endif
81
82 #ifdef SSL_SUPPORT
83 struct SSLOptions Conf_SSLOptions;
84
85 static void
86 ConfSSL_Init(void)
87 {
88         free(Conf_SSLOptions.KeyFile);
89         Conf_SSLOptions.KeyFile = NULL;
90
91         free(Conf_SSLOptions.CertFile);
92         Conf_SSLOptions.CertFile = NULL;
93
94         free(Conf_SSLOptions.DHFile);
95         Conf_SSLOptions.DHFile = NULL;
96         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
97 }
98
99 static bool
100 ssl_print_configvar(const char *name, const char *file)
101 {
102         FILE *fp;
103
104         if (!file) {
105                 printf("  %s =\n", name);
106                 return true;
107         }
108
109         fp = fopen(file, "r");
110         if (fp)
111                 fclose(fp);
112         else
113                 fprintf(stderr, "ERROR: %s \"%s\": %s\n",
114                         name, file, strerror(errno));
115
116         printf("  %s = %s\n", name, file);
117         return fp != NULL;
118 }
119
120 static bool
121 ConfSSL_Puts(void)
122 {
123         bool ret;
124
125         ret = ssl_print_configvar("SSLKeyFile", Conf_SSLOptions.KeyFile);
126
127         if (!ssl_print_configvar("SSLCertFile", Conf_SSLOptions.CertFile))
128                 ret = false;
129
130         if (!ssl_print_configvar("SSLDHFile", Conf_SSLOptions.DHFile))
131                 ret = false;
132
133         if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
134                 puts("  SSLKeyFilePassword = <secret>");
135
136         array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
137
138         return ret;
139 }
140 #endif
141
142 static char *
143 strdup_warn(const char *str)
144 {
145         char *ptr = strdup(str);
146         if (!ptr)
147                 Config_Error(LOG_ERR, "Could not allocate mem for string: %s", str);
148         return ptr;
149 }
150
151
152 static void
153 ports_puts(array *a)
154 {
155         size_t len;
156         UINT16 *ports;
157         len = array_length(a, sizeof(UINT16));
158         if (len--) {
159                 ports = (UINT16*) array_start(a);
160                 printf("%u", (unsigned int) *ports);
161                 while (len--) {
162                         ports++;
163                         printf(", %u", (unsigned int) *ports);
164                 }
165         }
166         putc('\n', stdout);
167 }
168
169
170 static void
171 ports_parse(array *a, int Line, char *Arg)
172 {
173         char *ptr;
174         int port;
175         UINT16 port16;
176
177         array_trunc(a);
178
179         /* Ports on that the server should listen. More port numbers
180          * must be separated by "," */
181         ptr = strtok( Arg, "," );
182         while (ptr) {
183                 ngt_TrimStr(ptr);
184                 port = atoi(ptr);
185                 if (port > 0 && port < 0xFFFF) {
186                         port16 = (UINT16) port;
187                         if (!array_catb(a, (char*)&port16, sizeof port16))
188                                 Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
189                                                         NGIRCd_ConfFile, Line, port, strerror(errno));
190                 } else {
191                         Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
192                                                                         NGIRCd_ConfFile, Line, port );
193                 }
194
195                 ptr = strtok( NULL, "," );
196         }
197 }
198
199
200 GLOBAL void
201 Conf_Init( void )
202 {
203         Read_Config( true );
204         Validate_Config(false, false);
205 } /* Config_Init */
206
207
208 GLOBAL bool
209 Conf_Rehash( void )
210 {
211         if (!Read_Config(false))
212                 return false;
213         Validate_Config(false, true);
214
215         /* Update CLIENT structure of local server */
216         Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
217         return true;
218 } /* Config_Rehash */
219
220
221 static const char*
222 yesno_to_str(int boolean_value)
223 {
224         if (boolean_value)
225                 return "yes";
226         return "no";
227 }
228
229
230 static void
231 opers_free(void)
232 {
233         struct Conf_Oper *op;
234         size_t len;
235         
236         len = array_length(&Conf_Opers, sizeof(*op));
237         op = array_start(&Conf_Opers);
238         while (len--) {
239                 free(op->mask);
240                 op++;
241         }
242         array_free(&Conf_Opers);
243 }
244
245 static void
246 opers_puts(void)
247 {
248         struct Conf_Oper *op;
249         size_t len;
250         
251         len = array_length(&Conf_Opers, sizeof(*op));
252         op = array_start(&Conf_Opers);
253         while (len--) {
254                 assert(op->name[0]);
255
256                 puts("[OPERATOR]");
257                 printf("  Name = %s\n", op->name);
258                 printf("  Password = %s\n", op->pwd);
259                 printf("  Mask = %s\n\n", op->mask ? op->mask : "");
260                 op++;
261         }
262 }
263
264
265 GLOBAL int
266 Conf_Test( void )
267 {
268         /* Read configuration, validate and output it. */
269
270         struct passwd *pwd;
271         struct group *grp;
272         unsigned int i;
273         bool config_valid;
274         size_t predef_channel_count;
275         struct Conf_Channel *predef_chan;
276
277         Use_Log = false;
278
279         if (! Read_Config(true))
280                 return 1;
281
282         config_valid = Validate_Config(true, false);
283
284         /* If stdin and stdout ("you can read our nice message and we can
285          * read in your keypress") are valid tty's, wait for a key: */
286         if( isatty( fileno( stdin )) && isatty( fileno( stdout ))) {
287                 puts( "OK, press enter to see a dump of your service configuration ..." );
288                 getchar( );
289         } else {
290                 puts( "Ok, dump of your server configuration follows:\n" );
291         }
292
293         puts( "[GLOBAL]" );
294         printf("  Name = %s\n", Conf_ServerName);
295         printf("  Info = %s\n", Conf_ServerInfo);
296 #ifndef PAM
297         printf("  Password = %s\n", Conf_ServerPwd);
298 #endif
299         printf("  WebircPassword = %s\n", Conf_WebircPwd);
300         printf("  AdminInfo1 = %s\n", Conf_ServerAdmin1);
301         printf("  AdminInfo2 = %s\n", Conf_ServerAdmin2);
302         printf("  AdminEMail = %s\n", Conf_ServerAdminMail);
303         printf("  MotdFile = %s\n", Conf_MotdFile);
304         printf("  MotdPhrase = %.32s\n", array_bytes(&Conf_Motd) ? (const char*) array_start(&Conf_Motd) : "");
305         printf("  ChrootDir = %s\n", Conf_Chroot);
306         printf("  PidFile = %s\n", Conf_PidFile);
307         printf("  Listen = %s\n", Conf_ListenAddress);
308         fputs("  Ports = ", stdout);
309         ports_puts(&Conf_ListenPorts);
310 #ifdef SSL_SUPPORT
311         fputs("  SSLPorts = ", stdout);
312         ports_puts(&Conf_SSLOptions.ListenPorts);
313         if (!ConfSSL_Puts())
314                 config_valid = false;
315 #endif
316
317         pwd = getpwuid(Conf_UID);
318         if (pwd)
319                 printf("  ServerUID = %s\n", pwd->pw_name);
320         else
321                 printf("  ServerUID = %ld\n", (long)Conf_UID);
322         grp = getgrgid(Conf_GID);
323         if (grp)
324                 printf("  ServerGID = %s\n", grp->gr_name);
325         else
326                 printf("  ServerGID = %ld\n", (long)Conf_GID);
327 #ifdef SYSLOG
328         printf("  SyslogFacility = %s\n",
329                ngt_SyslogFacilityName(Conf_SyslogFacility));
330 #endif
331         printf("  PingTimeout = %d\n", Conf_PingTimeout);
332         printf("  PongTimeout = %d\n", Conf_PongTimeout);
333         printf("  ConnectRetry = %d\n", Conf_ConnectRetry);
334         printf("  OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
335         printf("  OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
336         printf("  AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
337         printf("  PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
338         printf("  NoDNS = %s\n", yesno_to_str(Conf_NoDNS));
339         printf("  NoIdent = %s\n", yesno_to_str(Conf_NoIdent));
340         printf("  NoPAM = %s\n", yesno_to_str(Conf_NoPAM));
341         printf("  NoZeroConf = %s\n", yesno_to_str(Conf_NoZeroConf));
342
343 #ifdef WANT_IPV6
344         printf("  ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
345         printf("  ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
346 #endif
347         printf("  MaxConnections = %ld\n", Conf_MaxConnections);
348         printf("  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
349         printf("  MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
350         printf("  MaxNickLength = %u\n\n", Conf_MaxNickLength - 1);
351
352         opers_puts();
353
354         for( i = 0; i < MAX_SERVERS; i++ ) {
355                 if( ! Conf_Server[i].name[0] ) continue;
356
357                 /* Valid "Server" section */
358                 puts( "[SERVER]" );
359                 printf( "  Name = %s\n", Conf_Server[i].name );
360                 printf( "  Host = %s\n", Conf_Server[i].host );
361                 printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
362 #ifdef SSL_SUPPORT
363                 printf( "  SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
364 #endif
365                 printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
366                 printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
367                 printf( "  ServiceMask = %s\n", Conf_Server[i].svs_mask);
368                 printf( "  Group = %d\n", Conf_Server[i].group );
369                 printf( "  Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
370         }
371
372         predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan));
373         predef_chan = array_start(&Conf_Channels);
374
375         for (i = 0; i < predef_channel_count; i++, predef_chan++) {
376                 if (!predef_chan->name[0])
377                         continue;
378
379                 /* Valid "Channel" section */
380                 puts( "[CHANNEL]" );
381                 printf("  Name = %s\n", predef_chan->name);
382                 printf("  Modes = %s\n", predef_chan->modes);
383                 printf("  Key = %s\n", predef_chan->key);
384                 printf("  MaxUsers = %lu\n", predef_chan->maxusers);
385                 printf("  Topic = %s\n", predef_chan->topic);
386                 printf("  KeyFile = %s\n\n", predef_chan->keyfile);
387         }
388
389         return (config_valid ? 0 : 1);
390 } /* Conf_Test */
391
392
393 GLOBAL void
394 Conf_UnsetServer( CONN_ID Idx )
395 {
396         /* Set next time for next connection attempt, if this is a server
397          * link that is (still) configured here. If the server is set as
398          * "once", delete it from our configuration.
399          * Non-Server-Connections will be silently ignored. */
400
401         int i;
402         time_t t;
403
404         /* Check all our configured servers */
405         for( i = 0; i < MAX_SERVERS; i++ ) {
406                 if( Conf_Server[i].conn_id != Idx ) continue;
407
408                 /* Gotcha! Mark server configuration as "unused": */
409                 Conf_Server[i].conn_id = NONE;
410
411                 if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
412                         /* Delete configuration here */
413                         Init_Server_Struct( &Conf_Server[i] );
414                 } else {
415                         /* Set time for next connect attempt */
416                         t = time(NULL);
417                         if (Conf_Server[i].lasttry < t - Conf_ConnectRetry) {
418                                 /* The connection has been "long", so we don't
419                                  * require the next attempt to be delayed. */
420                                 Conf_Server[i].lasttry =
421                                         t - Conf_ConnectRetry + RECONNECT_DELAY;
422                         } else
423                                 Conf_Server[i].lasttry = t;
424                 }
425         }
426 } /* Conf_UnsetServer */
427
428
429 GLOBAL void
430 Conf_SetServer( int ConfServer, CONN_ID Idx )
431 {
432         /* Set connection for specified configured server */
433
434         assert( ConfServer > NONE );
435         assert( Idx > NONE );
436
437         Conf_Server[ConfServer].conn_id = Idx;
438 } /* Conf_SetServer */
439
440
441 GLOBAL int
442 Conf_GetServer( CONN_ID Idx )
443 {
444         /* Get index of server in configuration structure */
445
446         int i = 0;
447
448         assert( Idx > NONE );
449
450         for( i = 0; i < MAX_SERVERS; i++ ) {
451                 if( Conf_Server[i].conn_id == Idx ) return i;
452         }
453         return NONE;
454 } /* Conf_GetServer */
455
456
457 GLOBAL bool
458 Conf_EnableServer( const char *Name, UINT16 Port )
459 {
460         /* Enable specified server and adjust port */
461
462         int i;
463
464         assert( Name != NULL );
465
466         for( i = 0; i < MAX_SERVERS; i++ ) {
467                 if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
468                         /* Gotcha! Set port and enable server: */
469                         Conf_Server[i].port = Port;
470                         Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
471                         return (Conf_Server[i].port && Conf_Server[i].host[0]);
472                 }
473         }
474         return false;
475 } /* Conf_EnableServer */
476
477
478 GLOBAL bool
479 Conf_EnablePassiveServer(const char *Name)
480 {
481         /* Enable specified server */
482         int i;
483
484         assert( Name != NULL );
485         for (i = 0; i < MAX_SERVERS; i++) {
486                 if ((strcasecmp( Conf_Server[i].name, Name ) == 0) && (Conf_Server[i].port > 0)) {
487                         /* BINGO! Enable server */
488                         Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
489                         return true;
490                 }
491         }
492         return false;
493 } /* Conf_EnablePassiveServer */
494
495
496 GLOBAL bool
497 Conf_DisableServer( const char *Name )
498 {
499         /* Enable specified server and adjust port */
500
501         int i;
502
503         assert( Name != NULL );
504
505         for( i = 0; i < MAX_SERVERS; i++ ) {
506                 if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
507                         /* Gotcha! Disable and disconnect server: */
508                         Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
509                         if( Conf_Server[i].conn_id > NONE ) Conn_Close( Conf_Server[i].conn_id, NULL, "Server link terminated on operator request", true);
510                         return true;
511                 }
512         }
513         return false;
514 } /* Conf_DisableServer */
515
516
517 GLOBAL bool
518 Conf_AddServer( const char *Name, UINT16 Port, const char *Host, const char *MyPwd, const char *PeerPwd )
519 {
520         /* Add new server to configuration */
521
522         int i;
523
524         assert( Name != NULL );
525         assert( Host != NULL );
526         assert( MyPwd != NULL );
527         assert( PeerPwd != NULL );
528
529         /* Search unused item in server configuration structure */
530         for( i = 0; i < MAX_SERVERS; i++ ) {
531                 /* Is this item used? */
532                 if( ! Conf_Server[i].name[0] ) break;
533         }
534         if( i >= MAX_SERVERS ) return false;
535
536         Init_Server_Struct( &Conf_Server[i] );
537         strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
538         strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
539         strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
540         strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
541         Conf_Server[i].port = Port;
542         Conf_Server[i].flags = CONF_SFLAG_ONCE;
543
544         return true;
545 } /* Conf_AddServer */
546
547
548 /**
549  * Check if the given nick name is an service
550  */
551 GLOBAL bool
552 Conf_IsService(int ConfServer, const char *Nick)
553 {
554         return MatchCaseInsensitive(Conf_Server[ConfServer].svs_mask, Nick);
555 } /* Conf_IsService */
556
557
558 /**
559  * Initialize configuration settings with their default values.
560  */
561 static void
562 Set_Defaults(bool InitServers)
563 {
564         int i;
565
566         strcpy(Conf_ServerName, "");
567         snprintf(Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s",
568                  PACKAGE_NAME, PACKAGE_VERSION);
569         strcpy(Conf_ServerPwd, "");
570
571         strcpy(Conf_ServerAdmin1, "");
572         strcpy(Conf_ServerAdmin2, "");
573         strcpy(Conf_ServerAdminMail, "");
574
575         strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile));
576         strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile));
577
578         Conf_UID = Conf_GID = 0;
579         strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot));
580         strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile));
581
582         free(Conf_ListenAddress);
583         Conf_ListenAddress = NULL;
584
585         Conf_PingTimeout = 120;
586         Conf_PongTimeout = 20;
587         Conf_ConnectRetry = 60;
588         Conf_NoDNS = false;
589         Conf_NoIdent = false;
590         Conf_NoPAM = false;
591         Conf_NoZeroConf = false;
592
593         Conf_Oper_Count = 0;
594         Conf_Channel_Count = 0;
595
596         Conf_OperCanMode = false;
597         Conf_OperServerMode = false;
598         Conf_AllowRemoteOper = false;
599         Conf_PredefChannelsOnly = false;
600
601         Conf_ConnectIPv4 = true;
602         Conf_ConnectIPv6 = true;
603
604         Conf_MaxConnections = 0;
605         Conf_MaxConnectionsIP = 5;
606         Conf_MaxJoins = 10;
607         Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
608
609 #ifdef SYSLOG
610 #ifdef LOG_LOCAL5
611         Conf_SyslogFacility = LOG_LOCAL5;
612 #else
613         Conf_SyslogFacility = 0;
614 #endif
615 #endif
616
617         /* Initialize server configuration structures */
618         if (InitServers) {
619                 for (i = 0; i < MAX_SERVERS;
620                      Init_Server_Struct(&Conf_Server[i++]));
621         }
622 } /* Set_Defaults */
623
624
625 static bool
626 no_listenports(void)
627 {
628         size_t cnt = array_bytes(&Conf_ListenPorts);
629 #ifdef SSL_SUPPORT
630         cnt += array_bytes(&Conf_SSLOptions.ListenPorts);
631 #endif
632         return cnt == 0;
633 }
634
635 static void
636 Read_Motd(const char *filename)
637 {
638         char line[127];
639         FILE *fp;
640
641         if (*filename == '\0')
642                 return;
643
644         fp = fopen(filename, "r");
645         if (!fp) {
646                 Log(LOG_WARNING, "Can't read MOTD file \"%s\": %s",
647                                         filename, strerror(errno));
648                 return;
649         }
650
651         array_free(&Conf_Motd);
652
653         while (fgets(line, (int)sizeof line, fp)) {
654                 ngt_TrimLastChr( line, '\n');
655
656                 /* add text including \0 */
657                 if (!array_catb(&Conf_Motd, line, strlen(line) + 1)) {
658                         Log(LOG_WARNING, "Cannot add MOTD text: %s", strerror(errno));
659                         break;
660                 }
661         }
662         fclose(fp);
663 }
664
665 static bool
666 Read_Config( bool ngircd_starting )
667 {
668         /* Read configuration file. */
669
670         char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
671         const UINT16 defaultport = 6667;
672         int line, i, n;
673         FILE *fd;
674
675         /* Open configuration file */
676         fd = fopen( NGIRCd_ConfFile, "r" );
677         if( ! fd ) {
678                 /* No configuration file found! */
679                 Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
680                                         NGIRCd_ConfFile, strerror( errno ));
681                 if (!ngircd_starting)
682                         return false;
683                 Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
684                 exit( 1 );
685         }
686
687         opers_free();
688         Set_Defaults( ngircd_starting );
689
690         Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
691
692         /* Clean up server configuration structure: mark all already
693          * configured servers as "once" so that they are deleted
694          * after the next disconnect and delete all unused servers.
695          * And delete all servers which are "duplicates" of servers
696          * that are already marked as "once" (such servers have been
697          * created by the last rehash but are now useless). */
698         for( i = 0; i < MAX_SERVERS; i++ ) {
699                 if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
700                 else {
701                         /* This structure is in use ... */
702                         if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
703                                 /* Check for duplicates */
704                                 for( n = 0; n < MAX_SERVERS; n++ ) {
705                                         if( n == i ) continue;
706
707                                         if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
708                                                 Init_Server_Struct( &Conf_Server[n] );
709 #ifdef DEBUG
710                                                 Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
711                                                                                                 n, i );
712 #endif
713                                         }
714                                 }
715                         } else {
716                                 /* Mark server as "once" */
717                                 Conf_Server[i].flags |= CONF_SFLAG_ONCE;
718                                 Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
719                         }
720                 }
721         }
722
723         /* Initialize variables */
724         line = 0;
725         strcpy( section, "" );
726         Init_Server_Struct( &New_Server );
727         New_Server_Idx = NONE;
728 #ifdef SSL_SUPPORT
729         ConfSSL_Init();
730 #endif
731         /* Read configuration file */
732         while( true ) {
733                 if( ! fgets( str, LINE_LEN, fd )) break;
734                 ngt_TrimStr( str );
735                 line++;
736
737                 /* Skip comments and empty lines */
738                 if( str[0] == ';' || str[0] == '#' || str[0] == '\0' ) continue;
739
740                 /* Is this the beginning of a new section? */
741                 if(( str[0] == '[' ) && ( str[strlen( str ) - 1] == ']' )) {
742                         strlcpy( section, str, sizeof( section ));
743                         if( strcasecmp( section, "[GLOBAL]" ) == 0 )
744                                 continue;
745
746                         if( strcasecmp( section, "[SERVER]" ) == 0 ) {
747                                 /* Check if there is already a server to add */
748                                 if( New_Server.name[0] ) {
749                                         /* Copy data to "real" server structure */
750                                         assert( New_Server_Idx > NONE );
751                                         Conf_Server[New_Server_Idx] = New_Server;
752                                 }
753
754                                 /* Re-init structure for new server */
755                                 Init_Server_Struct( &New_Server );
756
757                                 /* Search unused item in server configuration structure */
758                                 for( i = 0; i < MAX_SERVERS; i++ ) {
759                                         /* Is this item used? */
760                                         if( ! Conf_Server[i].name[0] ) break;
761                                 }
762                                 if( i >= MAX_SERVERS ) {
763                                         /* Oops, no free item found! */
764                                         Config_Error( LOG_ERR, "Too many servers configured." );
765                                         New_Server_Idx = NONE;
766                                 }
767                                 else New_Server_Idx = i;
768                                 continue;
769                         }
770                         if (strcasecmp(section, "[CHANNEL]") == 0) {
771                                 Conf_Channel_Count++;
772                                 continue;
773                         }
774                         if (strcasecmp(section, "[OPERATOR]") == 0) {
775                                 Conf_Oper_Count++;
776                                 continue;
777                         }
778
779                         Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section );
780                         section[0] = 0x1;
781                 }
782                 if( section[0] == 0x1 ) continue;
783
784                 /* Split line into variable name and parameters */
785                 ptr = strchr( str, '=' );
786                 if( ! ptr ) {
787                         Config_Error( LOG_ERR, "%s, line %d: Syntax error!", NGIRCd_ConfFile, line );
788                         continue;
789                 }
790                 *ptr = '\0';
791                 var = str; ngt_TrimStr( var );
792                 arg = ptr + 1; ngt_TrimStr( arg );
793
794                 if( strcasecmp( section, "[GLOBAL]" ) == 0 ) Handle_GLOBAL( line, var, arg );
795                 else if( strcasecmp( section, "[OPERATOR]" ) == 0 ) Handle_OPERATOR( line, var, arg );
796                 else if( strcasecmp( section, "[SERVER]" ) == 0 ) Handle_SERVER( line, var, arg );
797                 else if( strcasecmp( section, "[CHANNEL]" ) == 0 ) Handle_CHANNEL( line, var, arg );
798                 else Config_Error( LOG_ERR, "%s, line %d: Variable \"%s\" outside section!", NGIRCd_ConfFile, line, var );
799         }
800
801         /* Close configuration file */
802         fclose( fd );
803
804         /* Check if there is still a server to add */
805         if( New_Server.name[0] ) {
806                 /* Copy data to "real" server structure */
807                 assert( New_Server_Idx > NONE );
808                 Conf_Server[New_Server_Idx] = New_Server;
809         }
810
811         /* not a single listening port? Add default. */
812         if (no_listenports() &&
813                 !array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport))
814         {
815                 Config_Error(LOG_ALERT, "Could not add default listening Port %u: %s",
816                                         (unsigned int) defaultport, strerror(errno));
817
818                 exit(1);
819         }
820
821         if (!Conf_ListenAddress)
822                 Conf_ListenAddress = strdup_warn(DEFAULT_LISTEN_ADDRSTR);
823
824         if (!Conf_ListenAddress) {
825                 Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
826                 exit(1);
827         }
828
829         /* No MOTD phrase configured? (re)try motd file. */
830         if (array_bytes(&Conf_Motd) == 0)
831                 Read_Motd(Conf_MotdFile);
832         return true;
833 } /* Read_Config */
834
835
836 static bool
837 Check_ArgIsTrue( const char *Arg )
838 {
839         if( strcasecmp( Arg, "yes" ) == 0 ) return true;
840         if( strcasecmp( Arg, "true" ) == 0 ) return true;
841         if( atoi( Arg ) != 0 ) return true;
842
843         return false;
844 } /* Check_ArgIsTrue */
845
846
847 static unsigned int
848 Handle_MaxNickLength(int Line, const char *Arg)
849 {
850         unsigned new;
851
852         new = (unsigned) atoi(Arg) + 1;
853         if (new > CLIENT_NICK_LEN) {
854                 Config_Error(LOG_WARNING,
855                              "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
856                              NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
857                 return CLIENT_NICK_LEN;
858         }
859         if (new < 2) {
860                 Config_Error(LOG_WARNING,
861                              "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
862                              NGIRCd_ConfFile, Line);
863                 return 2;
864         }
865         return new;
866 } /* Handle_MaxNickLength */
867
868
869
870 static void
871 Handle_GLOBAL( int Line, char *Var, char *Arg )
872 {
873         struct passwd *pwd;
874         struct group *grp;
875         size_t len;
876         
877         assert( Line > 0 );
878         assert( Var != NULL );
879         assert( Arg != NULL );
880         
881         if( strcasecmp( Var, "Name" ) == 0 ) {
882                 /* Server name */
883                 len = strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName ));
884                 if (len >= sizeof( Conf_ServerName ))
885                         Config_Error_TooLong( Line, Var );
886                 return;
887         }
888         if( strcasecmp( Var, "Info" ) == 0 ) {
889                 /* Info text of server */
890                 len = strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo ));
891                 if (len >= sizeof( Conf_ServerInfo ))
892                         Config_Error_TooLong ( Line, Var );
893                 return;
894         }
895         if( strcasecmp( Var, "Password" ) == 0 ) {
896                 /* Global server password */
897                 len = strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd ));
898                 if (len >= sizeof( Conf_ServerPwd ))
899                         Config_Error_TooLong( Line, Var );
900                 return;
901         }
902         if (strcasecmp(Var, "WebircPassword") == 0) {
903                 /* Password required for WEBIRC command */
904                 len = strlcpy(Conf_WebircPwd, Arg, sizeof(Conf_WebircPwd));
905                 if (len >= sizeof(Conf_WebircPwd))
906                         Config_Error_TooLong(Line, Var);
907                 return;
908         }
909         if( strcasecmp( Var, "AdminInfo1" ) == 0 ) {
910                 /* Administrative info #1 */
911                 len = strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 ));
912                 if (len >= sizeof( Conf_ServerAdmin1 ))
913                         Config_Error_TooLong ( Line, Var );
914                 return;
915         }
916         if( strcasecmp( Var, "AdminInfo2" ) == 0 ) {
917                 /* Administrative info #2 */
918                 len = strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 ));
919                 if (len >= sizeof( Conf_ServerAdmin2 ))
920                         Config_Error_TooLong ( Line, Var );
921                 return;
922         }
923         if( strcasecmp( Var, "AdminEMail" ) == 0 ) {
924                 /* Administrative email contact */
925                 len = strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail ));
926                 if (len >= sizeof( Conf_ServerAdminMail ))
927                         Config_Error_TooLong( Line, Var );
928                 return;
929         }
930
931         if( strcasecmp( Var, "Ports" ) == 0 ) {
932                 ports_parse(&Conf_ListenPorts, Line, Arg);
933                 return;
934         }
935         if( strcasecmp( Var, "MotdFile" ) == 0 ) {
936                 len = strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile ));
937                 if (len >= sizeof( Conf_MotdFile ))
938                         Config_Error_TooLong( Line, Var );
939                 Read_Motd(Arg);
940                 return;
941         }
942         if( strcasecmp( Var, "MotdPhrase" ) == 0 ) {
943                 /* "Message of the day" phrase (instead of file) */
944                 len = strlen(Arg);
945                 if (len == 0)
946                         return;
947                 if (len >= LINE_LEN) {
948                         Config_Error_TooLong( Line, Var );
949                         return;
950                 }
951                 if (!array_copyb(&Conf_Motd, Arg, len + 1))
952                         Config_Error(LOG_WARNING, "%s, line %d: Could not append MotdPhrase: %s",
953                                                         NGIRCd_ConfFile, Line, strerror(errno));
954                 return;
955         }
956         if( strcasecmp( Var, "ChrootDir" ) == 0 ) {
957                 /* directory for chroot() */
958                 len = strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot ));
959                 if (len >= sizeof( Conf_Chroot ))
960                         Config_Error_TooLong( Line, Var );
961                 return;
962         }
963         if ( strcasecmp( Var, "PidFile" ) == 0 ) {
964                 /* name of pidfile */
965                 len = strlcpy( Conf_PidFile, Arg, sizeof( Conf_PidFile ));
966                 if (len >= sizeof( Conf_PidFile ))
967                         Config_Error_TooLong( Line, Var );
968                 return;
969         }
970         if( strcasecmp( Var, "ServerUID" ) == 0 ) {
971                 /* UID the daemon should switch to */
972                 pwd = getpwnam( Arg );
973                 if( pwd ) Conf_UID = pwd->pw_uid;
974                 else {
975 #ifdef HAVE_ISDIGIT
976                         if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
977                         else
978 #endif
979                         Conf_UID = (unsigned int)atoi( Arg );
980                 }
981                 return;
982         }
983         if( strcasecmp( Var, "ServerGID" ) == 0 ) {
984                 /* GID the daemon should use */
985                 grp = getgrnam( Arg );
986                 if( grp ) Conf_GID = grp->gr_gid;
987                 else {
988 #ifdef HAVE_ISDIGIT
989                         if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
990                         else
991 #endif
992                         Conf_GID = (unsigned int)atoi( Arg );
993                 }
994                 return;
995         }
996         if( strcasecmp( Var, "PingTimeout" ) == 0 ) {
997                 /* PING timeout */
998                 Conf_PingTimeout = atoi( Arg );
999                 if( Conf_PingTimeout < 5 ) {
1000                         Config_Error( LOG_WARNING, "%s, line %d: Value of \"PingTimeout\" too low!",
1001                                                                         NGIRCd_ConfFile, Line );
1002                         Conf_PingTimeout = 5;
1003                 }
1004                 return;
1005         }
1006         if( strcasecmp( Var, "PongTimeout" ) == 0 ) {
1007                 /* PONG timeout */
1008                 Conf_PongTimeout = atoi( Arg );
1009                 if( Conf_PongTimeout < 5 ) {
1010                         Config_Error( LOG_WARNING, "%s, line %d: Value of \"PongTimeout\" too low!",
1011                                                                         NGIRCd_ConfFile, Line );
1012                         Conf_PongTimeout = 5;
1013                 }
1014                 return;
1015         }
1016         if( strcasecmp( Var, "ConnectRetry" ) == 0 ) {
1017                 /* Seconds between connection attempts to other servers */
1018                 Conf_ConnectRetry = atoi( Arg );
1019                 if( Conf_ConnectRetry < 5 ) {
1020                         Config_Error( LOG_WARNING, "%s, line %d: Value of \"ConnectRetry\" too low!",
1021                                                                         NGIRCd_ConfFile, Line );
1022                         Conf_ConnectRetry = 5;
1023                 }
1024                 return;
1025         }
1026         if( strcasecmp( Var, "PredefChannelsOnly" ) == 0 ) {
1027                 /* Should we only allow pre-defined-channels? (i.e. users cannot create their own channels) */
1028                 Conf_PredefChannelsOnly = Check_ArgIsTrue( Arg );
1029                 return;
1030         }
1031         if( strcasecmp( Var, "NoDNS" ) == 0 ) {
1032                 /* don't do reverse dns lookups when clients connect? */
1033                 Conf_NoDNS = Check_ArgIsTrue( Arg );
1034                 return;
1035         }
1036         if (strcasecmp(Var, "NoIdent") == 0) {
1037                 /* don't do IDENT lookups when clients connect? */
1038                 Conf_NoIdent = Check_ArgIsTrue(Arg);
1039 #ifndef IDENTAUTH
1040                 if (!Conf_NoIdent) {
1041                         /* user has enabled ident lookups explicitly, but ... */
1042                         Config_Error(LOG_WARNING,
1043                                 "%s: line %d: NoIdent=False, but ngircd was built without IDENT support",
1044                                 NGIRCd_ConfFile, Line);
1045                 }
1046 #endif
1047                 return;
1048         }
1049         if(strcasecmp(Var, "NoPAM") == 0) {
1050                 /* don't use PAM library to authenticate users */
1051                 Conf_NoPAM = Check_ArgIsTrue(Arg);
1052                 return;
1053         }
1054         if(strcasecmp(Var, "NoZeroConf") == 0) {
1055                 /* don't register services using ZeroConf */
1056                 Conf_NoZeroConf = Check_ArgIsTrue(Arg);
1057                 return;
1058         }
1059 #ifdef WANT_IPV6
1060         /* the default setting for all the WANT_IPV6 special options is 'true' */
1061         if( strcasecmp( Var, "ConnectIPv6" ) == 0 ) {
1062                 /* connect to other hosts using ipv6, if they have an AAAA record? */
1063                 Conf_ConnectIPv6 = Check_ArgIsTrue( Arg );
1064                 return;
1065         }
1066         if( strcasecmp( Var, "ConnectIPv4" ) == 0 ) {
1067                 /* connect to other hosts using ipv4.
1068                  * again, this can be used for ipv6-only setups */
1069                 Conf_ConnectIPv4 = Check_ArgIsTrue( Arg );
1070                 return;
1071         }
1072 #endif
1073         if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
1074                 /* Are IRC operators allowed to use MODE in channels they aren't Op in? */
1075                 Conf_OperCanMode = Check_ArgIsTrue( Arg );
1076                 return;
1077         }
1078         if( strcasecmp( Var, "OperServerMode" ) == 0 ) {
1079                 /* Mask IRC operator as if coming from the server? (ircd-irc2 compat hack) */
1080                 Conf_OperServerMode = Check_ArgIsTrue( Arg );
1081                 return;
1082         }
1083         if(strcasecmp(Var, "AllowRemoteOper") == 0) {
1084                 /* Are remote IRC operators allowed to control this server? */
1085                 Conf_AllowRemoteOper = Check_ArgIsTrue(Arg);
1086                 return;
1087         }
1088         if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
1089                 /* Maximum number of connections. 0 -> "no limit". */
1090 #ifdef HAVE_ISDIGIT
1091                 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
1092                 else
1093 #endif
1094                 Conf_MaxConnections = atol( Arg );
1095                 return;
1096         }
1097         if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
1098                 /* Maximum number of simultaneous connections from one IP. 0 -> "no limit" */
1099 #ifdef HAVE_ISDIGIT
1100                 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
1101                 else
1102 #endif
1103                 Conf_MaxConnectionsIP = atoi( Arg );
1104                 return;
1105         }
1106         if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
1107                 /* Maximum number of channels a user can join. 0 -> "no limit". */
1108 #ifdef HAVE_ISDIGIT
1109                 if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
1110                 else
1111 #endif
1112                 Conf_MaxJoins = atoi( Arg );
1113                 return;
1114         }
1115         if( strcasecmp( Var, "MaxNickLength" ) == 0 ) {
1116                 /* Maximum length of a nick name; must be same on all servers
1117                  * within the IRC network! */
1118                 Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
1119                 return;
1120         }
1121
1122         if( strcasecmp( Var, "Listen" ) == 0 ) {
1123                 /* IP-Address to bind sockets */
1124                 if (Conf_ListenAddress) {
1125                         Config_Error(LOG_ERR, "Multiple Listen= options, ignoring: %s", Arg);
1126                         return;
1127                 }
1128                 Conf_ListenAddress = strdup_warn(Arg);
1129                 /*
1130                  * if allocation fails, we're in trouble:
1131                  * we cannot ignore the error -- otherwise ngircd
1132                  * would listen on all interfaces.
1133                  */
1134                 if (!Conf_ListenAddress) {
1135                         Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
1136                         exit(1);
1137                 }
1138                 return;
1139         }
1140
1141 #ifdef SSL_SUPPORT
1142         if( strcasecmp( Var, "SSLPorts" ) == 0 ) {
1143                 ports_parse(&Conf_SSLOptions.ListenPorts, Line, Arg);
1144                 return;
1145         }
1146
1147         if( strcasecmp( Var, "SSLKeyFile" ) == 0 ) {
1148                 assert(Conf_SSLOptions.KeyFile == NULL );
1149                 Conf_SSLOptions.KeyFile = strdup_warn(Arg);
1150                 return;
1151         }
1152         if( strcasecmp( Var, "SSLCertFile" ) == 0 ) {
1153                 assert(Conf_SSLOptions.CertFile == NULL );
1154                 Conf_SSLOptions.CertFile = strdup_warn(Arg);
1155                 return;
1156         }
1157
1158         if( strcasecmp( Var, "SSLKeyFilePassword" ) == 0 ) {
1159                 assert(array_bytes(&Conf_SSLOptions.KeyFilePassword) == 0);
1160                 if (!array_copys(&Conf_SSLOptions.KeyFilePassword, Arg))
1161                         Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Could not copy %s: %s!",
1162                                                                 NGIRCd_ConfFile, Line, Var, strerror(errno));
1163                 return;
1164         }
1165         if( strcasecmp( Var, "SSLDHFile" ) == 0 ) {
1166                 assert(Conf_SSLOptions.DHFile == NULL);
1167                 Conf_SSLOptions.DHFile = strdup_warn( Arg );
1168                 return;
1169         }
1170 #endif
1171 #ifdef SYSLOG
1172         if (strcasecmp(Var, "SyslogFacility") == 0) {
1173                 Conf_SyslogFacility = ngt_SyslogFacilityID(Arg,
1174                                                            Conf_SyslogFacility);
1175                 return;
1176         }
1177 #endif
1178         Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
1179                                                                 NGIRCd_ConfFile, Line, Var);
1180 } /* Handle_GLOBAL */
1181
1182
1183 static void
1184 Handle_OPERATOR( int Line, char *Var, char *Arg )
1185 {
1186         size_t len;
1187         struct Conf_Oper *op;
1188
1189         assert( Line > 0 );
1190         assert( Var != NULL );
1191         assert( Arg != NULL );
1192         assert( Conf_Oper_Count > 0 );
1193
1194         op = array_alloc(&Conf_Opers, sizeof(*op), Conf_Oper_Count - 1);
1195         if (!op) {
1196                 Config_Error(LOG_ERR, "Could not allocate memory for operator (%d:%s = %s)", Line, Var, Arg);
1197                 return;
1198         }
1199
1200         if (strcasecmp(Var, "Name") == 0) {
1201                 /* Name of IRC operator */
1202                 len = strlcpy(op->name, Arg, sizeof(op->name));
1203                 if (len >= sizeof(op->name))
1204                                 Config_Error_TooLong(Line, Var);
1205                 return;
1206         }
1207         if (strcasecmp(Var, "Password") == 0) {
1208                 /* Password of IRC operator */
1209                 len = strlcpy(op->pwd, Arg, sizeof(op->pwd));
1210                 if (len >= sizeof(op->pwd))
1211                                 Config_Error_TooLong(Line, Var);
1212                 return;
1213         }
1214         if (strcasecmp(Var, "Mask") == 0) {
1215                 if (op->mask)
1216                         return; /* Hostname already configured */
1217                 op->mask = strdup_warn( Arg );
1218                 return;
1219         }
1220         Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!",
1221                                                                 NGIRCd_ConfFile, Line, Var );
1222 } /* Handle_OPERATOR */
1223
1224
1225 static void
1226 Handle_SERVER( int Line, char *Var, char *Arg )
1227 {
1228         long port;
1229         size_t len;
1230         
1231         assert( Line > 0 );
1232         assert( Var != NULL );
1233         assert( Arg != NULL );
1234
1235         /* Ignore server block if no space is left in server configuration structure */
1236         if( New_Server_Idx <= NONE ) return;
1237
1238         if( strcasecmp( Var, "Host" ) == 0 ) {
1239                 /* Hostname of the server */
1240                 len = strlcpy( New_Server.host, Arg, sizeof( New_Server.host ));
1241                 if (len >= sizeof( New_Server.host ))
1242                         Config_Error_TooLong ( Line, Var );
1243                 return;
1244         }
1245         if( strcasecmp( Var, "Name" ) == 0 ) {
1246                 /* Name of the server ("Nick"/"ID") */
1247                 len = strlcpy( New_Server.name, Arg, sizeof( New_Server.name ));
1248                 if (len >= sizeof( New_Server.name ))
1249                         Config_Error_TooLong( Line, Var );
1250                 return;
1251         }
1252         if (strcasecmp(Var, "Bind") == 0) {
1253                 if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
1254                         return;
1255
1256                 Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
1257                                 NGIRCd_ConfFile, Line, Arg);
1258                 return;
1259         }
1260         if( strcasecmp( Var, "MyPassword" ) == 0 ) {
1261                 /* Password of this server which is sent to the peer */
1262                 if (*Arg == ':') {
1263                         Config_Error(LOG_ERR,
1264                                 "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
1265                                                                                 NGIRCd_ConfFile, Line);
1266                 }
1267                 len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
1268                 if (len >= sizeof( New_Server.pwd_in ))
1269                         Config_Error_TooLong( Line, Var );
1270                 return;
1271         }
1272         if( strcasecmp( Var, "PeerPassword" ) == 0 ) {
1273                 /* Passwort of the peer which must be received */
1274                 len = strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out ));
1275                 if (len >= sizeof( New_Server.pwd_out ))
1276                         Config_Error_TooLong( Line, Var );
1277                 return;
1278         }
1279         if( strcasecmp( Var, "Port" ) == 0 ) {
1280                 /* Port to which this server should connect */
1281                 port = atol( Arg );
1282                 if( port > 0 && port < 0xFFFF )
1283                         New_Server.port = (UINT16)port;
1284                 else
1285                         Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Illegal port number %ld!",
1286                                                                                 NGIRCd_ConfFile, Line, port );
1287                 return;
1288         }
1289 #ifdef SSL_SUPPORT
1290         if( strcasecmp( Var, "SSLConnect" ) == 0 ) {
1291                 New_Server.SSLConnect = Check_ArgIsTrue(Arg);
1292                 return;
1293         }
1294 #endif
1295         if( strcasecmp( Var, "Group" ) == 0 ) {
1296                 /* Server group */
1297 #ifdef HAVE_ISDIGIT
1298                 if( ! isdigit( (int)*Arg ))
1299                         Config_Error_NaN( Line, Var );
1300                 else
1301 #endif
1302                 New_Server.group = atoi( Arg );
1303                 return;
1304         }
1305         if( strcasecmp( Var, "Passive" ) == 0 ) {
1306                 if (Check_ArgIsTrue(Arg))
1307                         New_Server.flags |= CONF_SFLAG_DISABLED;
1308                 return;
1309         }
1310         if (strcasecmp(Var, "ServiceMask") == 0) {
1311                 len = strlcpy(New_Server.svs_mask, ngt_LowerStr(Arg),
1312                               sizeof(New_Server.svs_mask));
1313                 if (len >= sizeof(New_Server.svs_mask))
1314                         Config_Error_TooLong(Line, Var);
1315                 return;
1316         }
1317
1318         Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
1319                                                                 NGIRCd_ConfFile, Line, Var );
1320 } /* Handle_SERVER */
1321
1322
1323 static bool
1324 Handle_Channelname(struct Conf_Channel *new_chan, const char *name)
1325 {
1326         size_t size = sizeof(new_chan->name);
1327         char *dest = new_chan->name;
1328
1329         if (!Channel_IsValidName(name)) {
1330                 /*
1331                  * maybe user forgot to add a '#'.
1332                  * This is only here for user convenience.
1333                  */
1334                 *dest = '#';
1335                 --size;
1336                 ++dest;
1337         }
1338         return size > strlcpy(dest, name, size);
1339 }
1340
1341
1342 static void
1343 Handle_CHANNEL(int Line, char *Var, char *Arg)
1344 {
1345         size_t len;
1346         size_t chancount;
1347         struct Conf_Channel *chan;
1348
1349         assert( Line > 0 );
1350         assert( Var != NULL );
1351         assert( Arg != NULL );
1352         assert(Conf_Channel_Count > 0);
1353
1354         chancount = Conf_Channel_Count - 1;
1355
1356         chan = array_alloc(&Conf_Channels, sizeof(*chan), chancount);
1357         if (!chan) {
1358                 Config_Error(LOG_ERR, "Could not allocate memory for predefined channel (%d:%s = %s)", Line, Var, Arg);
1359                 return;
1360         }
1361         if (strcasecmp(Var, "Name") == 0) {
1362                 if (!Handle_Channelname(chan, Arg))
1363                         Config_Error_TooLong(Line, Var);
1364                 return;
1365         }
1366         if (strcasecmp(Var, "Modes") == 0) {
1367                 /* Initial modes */
1368                 len = strlcpy(chan->modes, Arg, sizeof(chan->modes));
1369                 if (len >= sizeof(chan->modes))
1370                         Config_Error_TooLong( Line, Var );
1371                 return;
1372         }
1373         if( strcasecmp( Var, "Topic" ) == 0 ) {
1374                 /* Initial topic */
1375                 len = strlcpy(chan->topic, Arg, sizeof(chan->topic));
1376                 if (len >= sizeof(chan->topic))
1377                         Config_Error_TooLong( Line, Var );
1378                 return;
1379         }
1380         if( strcasecmp( Var, "Key" ) == 0 ) {
1381                 /* Initial Channel Key (mode k) */
1382                 len = strlcpy(chan->key, Arg, sizeof(chan->key));
1383                 if (len >= sizeof(chan->key))
1384                         Config_Error_TooLong(Line, Var);
1385                 return;
1386         }
1387         if( strcasecmp( Var, "MaxUsers" ) == 0 ) {
1388                 /* maximum user limit, mode l */
1389                 chan->maxusers = (unsigned long) atol(Arg);
1390                 if (chan->maxusers == 0)
1391                         Config_Error_NaN(Line, Var);
1392                 return;
1393         }
1394         if (strcasecmp(Var, "KeyFile") == 0) {
1395                 /* channel keys */
1396                 len = strlcpy(chan->keyfile, Arg, sizeof(chan->keyfile));
1397                 if (len >= sizeof(chan->keyfile))
1398                         Config_Error_TooLong(Line, Var);
1399                 return;
1400         }
1401
1402         Config_Error( LOG_ERR, "%s, line %d (section \"Channel\"): Unknown variable \"%s\"!",
1403                                                                 NGIRCd_ConfFile, Line, Var );
1404 } /* Handle_CHANNEL */
1405
1406
1407 static bool
1408 Validate_Config(bool Configtest, bool Rehash)
1409 {
1410         /* Validate configuration settings. */
1411
1412 #ifdef DEBUG
1413         int i, servers, servers_once;
1414 #endif
1415         bool config_valid = true;
1416         char *ptr;
1417
1418         /* Validate configured server name, see RFC 2812 section 2.3.1 */
1419         ptr = Conf_ServerName;
1420         do {
1421                 if (*ptr >= 'a' && *ptr <= 'z') continue;
1422                 if (*ptr >= 'A' && *ptr <= 'Z') continue;
1423                 if (*ptr >= '0' && *ptr <= '9') continue;
1424                 if (ptr > Conf_ServerName) {
1425                         if (*ptr == '.' || *ptr == '-')
1426                                 continue;
1427                 }
1428                 Conf_ServerName[0] = '\0';
1429                 break;
1430         } while (*(++ptr));
1431
1432         if (!Conf_ServerName[0]) {
1433                 /* No server name configured! */
1434                 config_valid = false;
1435                 Config_Error(LOG_ALERT,
1436                              "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
1437                              NGIRCd_ConfFile);
1438                 if (!Configtest && !Rehash) {
1439                         Config_Error(LOG_ALERT,
1440                                      "%s exiting due to fatal errors!",
1441                                      PACKAGE_NAME);
1442                         exit(1);
1443                 }
1444         }
1445
1446         if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
1447                 /* No dot in server name! */
1448                 config_valid = false;
1449                 Config_Error(LOG_ALERT,
1450                              "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
1451                              NGIRCd_ConfFile);
1452                 if (!Configtest) {
1453                         Config_Error(LOG_ALERT,
1454                                      "%s exiting due to fatal errors!",
1455                                      PACKAGE_NAME);
1456                         exit(1);
1457                 }
1458         }
1459
1460 #ifdef STRICT_RFC
1461         if (!Conf_ServerAdminMail[0]) {
1462                 /* No administrative contact configured! */
1463                 config_valid = false;
1464                 Config_Error(LOG_ALERT,
1465                              "No administrator email address configured in \"%s\" ('AdminEMail')!",
1466                              NGIRCd_ConfFile);
1467                 if (!Configtest) {
1468                         Config_Error(LOG_ALERT,
1469                                      "%s exiting due to fatal errors!",
1470                                      PACKAGE_NAME);
1471                         exit(1);
1472                 }
1473         }
1474 #endif
1475
1476         if (!Conf_ServerAdmin1[0] && !Conf_ServerAdmin2[0]
1477             && !Conf_ServerAdminMail[0]) {
1478                 /* No administrative information configured! */
1479                 Config_Error(LOG_WARNING,
1480                              "No administrative information configured but required by RFC!");
1481         }
1482
1483 #ifdef PAM
1484         if (Conf_ServerPwd[0])
1485                 Config_Error(LOG_ERR,
1486                              "This server uses PAM, \"Password\" will be ignored!");
1487 #endif
1488
1489 #ifdef DEBUG
1490         servers = servers_once = 0;
1491         for (i = 0; i < MAX_SERVERS; i++) {
1492                 if (Conf_Server[i].name[0]) {
1493                         servers++;
1494                         if (Conf_Server[i].flags & CONF_SFLAG_ONCE)
1495                                 servers_once++;
1496                 }
1497         }
1498         Log(LOG_DEBUG,
1499             "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
1500             Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
1501 #endif
1502
1503         return config_valid;
1504 } /* Validate_Config */
1505
1506
1507 static void
1508 Config_Error_TooLong ( const int Line, const char *Item )
1509 {
1510         Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" too long!", NGIRCd_ConfFile, Line, Item );
1511 }
1512
1513
1514 static void
1515 Config_Error_NaN( const int Line, const char *Item )
1516 {
1517         Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!",
1518                                                 NGIRCd_ConfFile, Line, Item );
1519 }
1520
1521
1522 #ifdef PROTOTYPES
1523 static void Config_Error( const int Level, const char *Format, ... )
1524 #else
1525 static void Config_Error( Level, Format, va_alist )
1526 const int Level;
1527 const char *Format;
1528 va_dcl
1529 #endif
1530 {
1531         /* Error! Write to console and/or logfile. */
1532
1533         char msg[MAX_LOG_MSG_LEN];
1534         va_list ap;
1535
1536         assert( Format != NULL );
1537
1538 #ifdef PROTOTYPES
1539         va_start( ap, Format );
1540 #else
1541         va_start( ap );
1542 #endif
1543         vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap );
1544         va_end( ap );
1545         
1546         /* During "normal operations" the log functions of the daemon should
1547          * be used, but during testing of the configuration file, all messages
1548          * should go directly to the console: */
1549         if (Use_Log) Log( Level, "%s", msg );
1550         else puts( msg );
1551 } /* Config_Error */
1552
1553
1554 #ifdef DEBUG
1555
1556 GLOBAL void
1557 Conf_DebugDump(void)
1558 {
1559         int i;
1560
1561         Log(LOG_DEBUG, "Configured servers:");
1562         for (i = 0; i < MAX_SERVERS; i++) {
1563                 if (! Conf_Server[i].name[0])
1564                         continue;
1565                 Log(LOG_DEBUG,
1566                     " - %s: %s:%d, last=%ld, group=%d, flags=%d, conn=%d",
1567                     Conf_Server[i].name, Conf_Server[i].host,
1568                     Conf_Server[i].port, Conf_Server[i].lasttry,
1569                     Conf_Server[i].group, Conf_Server[i].flags,
1570                     Conf_Server[i].conn_id);
1571         }
1572 } /* Conf_DebugDump */
1573
1574 #endif
1575
1576
1577 static void
1578 Init_Server_Struct( CONF_SERVER *Server )
1579 {
1580         /* Initialize server configuration structur to default values */
1581
1582         assert( Server != NULL );
1583
1584         memset( Server, 0, sizeof (CONF_SERVER) );
1585
1586         Server->group = NONE;
1587         Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
1588
1589         if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
1590
1591         Proc_InitStruct(&Server->res_stat);
1592         Server->conn_id = NONE;
1593         memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
1594 } /* Init_Server_Struct */
1595
1596
1597 /* -eof- */