Annotation of ircnowd/src/ngircd/conf.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2019 Alexander Barton (alex@barton.de) and Contributors.
! 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:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * Configuration management (reading, parsing & validation)
! 17: */
! 18:
! 19: #include <assert.h>
! 20: #include <errno.h>
! 21: #ifdef PROTOTYPES
! 22: # include <stdarg.h>
! 23: #else
! 24: # include <varargs.h>
! 25: #endif
! 26: #include <stdio.h>
! 27: #include <stdlib.h>
! 28: #include <string.h>
! 29: #include <strings.h>
! 30: #include <time.h>
! 31: #include <unistd.h>
! 32: #include <pwd.h>
! 33: #include <grp.h>
! 34: #include <sys/types.h>
! 35: #include <dirent.h>
! 36:
! 37: #include "ngircd.h"
! 38: #include "conn.h"
! 39: #include "channel.h"
! 40: #include "log.h"
! 41: #include "match.h"
! 42:
! 43: #include "conf.h"
! 44:
! 45:
! 46: static bool Use_Log = true, Using_MotdFile = true;
! 47: static CONF_SERVER New_Server;
! 48: static int New_Server_Idx;
! 49:
! 50: static char Conf_MotdFile[FNAME_LEN];
! 51: static char Conf_HelpFile[FNAME_LEN];
! 52: static char Conf_IncludeDir[FNAME_LEN];
! 53:
! 54: static void Set_Defaults PARAMS(( bool InitServers ));
! 55: static bool Read_Config PARAMS(( bool TestOnly, bool IsStarting ));
! 56: static void Read_Config_File PARAMS(( const char *File, FILE *fd ));
! 57: static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
! 58:
! 59: static void Handle_GLOBAL PARAMS((const char *File, int Line,
! 60: char *Var, char *Arg ));
! 61: static void Handle_LIMITS PARAMS((const char *File, int Line,
! 62: char *Var, char *Arg ));
! 63: static void Handle_OPTIONS PARAMS((const char *File, int Line,
! 64: char *Var, char *Arg ));
! 65: static void Handle_OPERATOR PARAMS((const char *File, int Line,
! 66: char *Var, char *Arg ));
! 67: static void Handle_SERVER PARAMS((const char *File, int Line,
! 68: char *Var, char *Arg ));
! 69: static void Handle_CHANNEL PARAMS((const char *File, int Line,
! 70: char *Var, char *Arg ));
! 71:
! 72: static void Config_Error PARAMS((const int Level, const char *Format, ...));
! 73:
! 74: static void Config_Error_NaN PARAMS((const char *File, const int LINE,
! 75: const char *Value));
! 76: static void Config_Error_Section PARAMS((const char *File, const int Line,
! 77: const char *Item, const char *Section));
! 78: static void Config_Error_TooLong PARAMS((const char *File, const int LINE,
! 79: const char *Value));
! 80:
! 81: static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
! 82:
! 83:
! 84: #ifdef WANT_IPV6
! 85: #define DEFAULT_LISTEN_ADDRSTR "::,0.0.0.0"
! 86: #else
! 87: #define DEFAULT_LISTEN_ADDRSTR "0.0.0.0"
! 88: #endif
! 89:
! 90: #ifdef HAVE_LIBSSL
! 91: #define DEFAULT_CIPHERS "HIGH:!aNULL:@STRENGTH:!SSLv3"
! 92: #endif
! 93: #ifdef HAVE_LIBGNUTLS
! 94: #define DEFAULT_CIPHERS "SECURE128:-VERS-SSL3.0"
! 95: #endif
! 96:
! 97: #ifdef SSL_SUPPORT
! 98:
! 99: static void Handle_SSL PARAMS((const char *File, int Line, char *Var, char *Ark));
! 100:
! 101: struct SSLOptions Conf_SSLOptions;
! 102:
! 103: /**
! 104: * Initialize SSL configuration.
! 105: */
! 106: static void
! 107: ConfSSL_Init(void)
! 108: {
! 109: free(Conf_SSLOptions.KeyFile);
! 110: Conf_SSLOptions.KeyFile = NULL;
! 111:
! 112: free(Conf_SSLOptions.CertFile);
! 113: Conf_SSLOptions.CertFile = NULL;
! 114:
! 115: free(Conf_SSLOptions.DHFile);
! 116: Conf_SSLOptions.DHFile = NULL;
! 117: array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
! 118:
! 119: array_free(&Conf_SSLOptions.ListenPorts);
! 120:
! 121: free(Conf_SSLOptions.CipherList);
! 122: Conf_SSLOptions.CipherList = NULL;
! 123: }
! 124:
! 125: /**
! 126: * Check if the current configuration uses/requires SSL.
! 127: *
! 128: * @returns true if SSL is used and should be initialized.
! 129: */
! 130: GLOBAL bool
! 131: Conf_SSLInUse(void)
! 132: {
! 133: int i;
! 134:
! 135: /* SSL listen ports configured? */
! 136: if (array_bytes(&Conf_SSLOptions.ListenPorts))
! 137: return true;
! 138:
! 139: for (i = 0; i < MAX_SERVERS; i++) {
! 140: if (Conf_Server[i].port > 0
! 141: && Conf_Server[i].SSLConnect)
! 142: return true;
! 143: }
! 144: return false;
! 145: }
! 146:
! 147: /**
! 148: * Make sure that a configured file is readable.
! 149: *
! 150: * Currently, this function is only used for SSL-related options ...
! 151: *
! 152: * @param Var Configuration variable
! 153: * @param Filename Configured filename
! 154: */
! 155: static void
! 156: CheckFileReadable(const char *Var, const char *Filename)
! 157: {
! 158: FILE *fp;
! 159:
! 160: if (!Filename)
! 161: return;
! 162:
! 163: fp = fopen(Filename, "r");
! 164: if (fp)
! 165: fclose(fp);
! 166: else
! 167: Config_Error(LOG_ERR, "Can't read \"%s\" (\"%s\"): %s",
! 168: Filename, Var, strerror(errno));
! 169: }
! 170:
! 171: #endif
! 172:
! 173:
! 174: /**
! 175: * Duplicate string and warn on errors.
! 176: *
! 177: * @returns Pointer to string on success, NULL otherwise.
! 178: */
! 179: static char *
! 180: strdup_warn(const char *str)
! 181: {
! 182: char *ptr = strdup(str);
! 183: if (!ptr)
! 184: Config_Error(LOG_ERR,
! 185: "Could not allocate memory for string: %s", str);
! 186: return ptr;
! 187: }
! 188:
! 189: /**
! 190: * Output a comma separated list of ports (integer values).
! 191: */
! 192: static void
! 193: ports_puts(array *a)
! 194: {
! 195: size_t len;
! 196: UINT16 *ports;
! 197: len = array_length(a, sizeof(UINT16));
! 198: if (len--) {
! 199: ports = (UINT16*) array_start(a);
! 200: printf("%u", (unsigned int) *ports);
! 201: while (len--) {
! 202: ports++;
! 203: printf(", %u", (unsigned int) *ports);
! 204: }
! 205: }
! 206: putc('\n', stdout);
! 207: }
! 208:
! 209: /**
! 210: * Parse a comma separated string into an array of port numbers (integers).
! 211: */
! 212: static void
! 213: ports_parse(array *a, const char *File, int Line, char *Arg)
! 214: {
! 215: char *ptr;
! 216: int port;
! 217: UINT16 port16;
! 218:
! 219: array_trunc(a);
! 220:
! 221: ptr = strtok( Arg, "," );
! 222: while (ptr) {
! 223: ngt_TrimStr(ptr);
! 224: port = atoi(ptr);
! 225: if (port > 0 && port < 0xFFFF) {
! 226: port16 = (UINT16) port;
! 227: if (!array_catb(a, (char*)&port16, sizeof port16))
! 228: Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
! 229: File, Line, port, strerror(errno));
! 230: } else {
! 231: Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
! 232: File, Line, port );
! 233: }
! 234:
! 235: ptr = strtok( NULL, "," );
! 236: }
! 237: }
! 238:
! 239: /**
! 240: * Initialize configuration module.
! 241: */
! 242: GLOBAL void
! 243: Conf_Init( void )
! 244: {
! 245: Read_Config(false, true);
! 246: Validate_Config(false, false);
! 247: }
! 248:
! 249: /**
! 250: * "Rehash" (reload) server configuration.
! 251: *
! 252: * @returns true if configuration has been re-read, false on errors.
! 253: */
! 254: GLOBAL bool
! 255: Conf_Rehash( void )
! 256: {
! 257: if (!Read_Config(false, false))
! 258: return false;
! 259: Validate_Config(false, true);
! 260:
! 261: /* Update CLIENT structure of local server */
! 262: Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
! 263: return true;
! 264: }
! 265:
! 266: /**
! 267: * Output a boolean value as "yes/no" string.
! 268: */
! 269: static const char*
! 270: yesno_to_str(int boolean_value)
! 271: {
! 272: if (boolean_value)
! 273: return "yes";
! 274: return "no";
! 275: }
! 276:
! 277: /**
! 278: * Free all IRC operator configuration structures.
! 279: */
! 280: static void
! 281: opers_free(void)
! 282: {
! 283: struct Conf_Oper *op;
! 284: size_t len;
! 285:
! 286: len = array_length(&Conf_Opers, sizeof(*op));
! 287: op = array_start(&Conf_Opers);
! 288: while (len--) {
! 289: free(op->mask);
! 290: op++;
! 291: }
! 292: array_free(&Conf_Opers);
! 293: }
! 294:
! 295: /**
! 296: * Output all IRC operator configuration structures.
! 297: */
! 298: static void
! 299: opers_puts(void)
! 300: {
! 301: struct Conf_Oper *op;
! 302: size_t count, i;
! 303:
! 304: count = array_length(&Conf_Opers, sizeof(*op));
! 305: op = array_start(&Conf_Opers);
! 306: for (i = 0; i < count; i++, op++) {
! 307: if (!op->name[0])
! 308: continue;
! 309:
! 310: puts("[OPERATOR]");
! 311: printf(" Name = %s\n", op->name);
! 312: printf(" Password = %s\n", op->pwd);
! 313: printf(" Mask = %s\n\n", op->mask ? op->mask : "");
! 314: }
! 315: }
! 316:
! 317: /**
! 318: * Read configuration, validate and output it.
! 319: *
! 320: * This function waits for a keypress of the user when stdin/stdout are valid
! 321: * tty's ("you can read our nice message and we can read in your keypress").
! 322: *
! 323: * @return 0 on success, 1 on failure(s); therefore the result code can
! 324: * directly be used by exit() when running "ngircd --configtest".
! 325: */
! 326: GLOBAL int
! 327: Conf_Test( void )
! 328: {
! 329: struct passwd *pwd;
! 330: struct group *grp;
! 331: unsigned int i, j;
! 332: bool config_valid;
! 333: size_t predef_channel_count;
! 334: struct Conf_Channel *predef_chan;
! 335:
! 336: Use_Log = false;
! 337:
! 338: if (!Read_Config(true, true))
! 339: return 1;
! 340:
! 341: config_valid = Validate_Config(true, false);
! 342:
! 343: /* Valid tty? */
! 344: if(isatty(fileno(stdin)) && isatty(fileno(stdout))) {
! 345: puts("OK, press enter to see a dump of your server configuration ...");
! 346: getchar();
! 347: } else
! 348: puts("Ok, dump of your server configuration follows:\n");
! 349:
! 350: puts("[GLOBAL]");
! 351: printf(" Name = %s\n", Conf_ServerName);
! 352: printf(" AdminInfo1 = %s\n", Conf_ServerAdmin1);
! 353: printf(" AdminInfo2 = %s\n", Conf_ServerAdmin2);
! 354: printf(" AdminEMail = %s\n", Conf_ServerAdminMail);
! 355: printf(" HelpFile = %s\n", Conf_HelpFile);
! 356: printf(" Info = %s\n", Conf_ServerInfo);
! 357: printf(" Listen = %s\n", Conf_ListenAddress);
! 358: if (Using_MotdFile) {
! 359: printf(" MotdFile = %s\n", Conf_MotdFile);
! 360: printf(" MotdPhrase =\n");
! 361: } else {
! 362: printf(" MotdFile = \n");
! 363: printf(" MotdPhrase = %s\n", array_bytes(&Conf_Motd)
! 364: ? (const char*) array_start(&Conf_Motd) : "");
! 365: }
! 366: printf(" Network = %s\n", Conf_Network);
! 367: if (!Conf_PAM)
! 368: printf(" Password = %s\n", Conf_ServerPwd);
! 369: printf(" PidFile = %s\n", Conf_PidFile);
! 370: printf(" Ports = ");
! 371: ports_puts(&Conf_ListenPorts);
! 372: grp = getgrgid(Conf_GID);
! 373: if (grp)
! 374: printf(" ServerGID = %s\n", grp->gr_name);
! 375: else
! 376: printf(" ServerGID = %ld\n", (long)Conf_GID);
! 377: pwd = getpwuid(Conf_UID);
! 378: if (pwd)
! 379: printf(" ServerUID = %s\n", pwd->pw_name);
! 380: else
! 381: printf(" ServerUID = %ld\n", (long)Conf_UID);
! 382: puts("");
! 383:
! 384: puts("[LIMITS]");
! 385: printf(" ConnectRetry = %d\n", Conf_ConnectRetry);
! 386: printf(" IdleTimeout = %d\n", Conf_IdleTimeout);
! 387: printf(" MaxConnections = %d\n", Conf_MaxConnections);
! 388: printf(" MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
! 389: printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
! 390: printf(" MaxNickLength = %u\n", Conf_MaxNickLength - 1);
! 391: printf(" MaxPenaltyTime = %ld\n", (long)Conf_MaxPenaltyTime);
! 392: printf(" MaxListSize = %d\n", Conf_MaxListSize);
! 393: printf(" PingTimeout = %d\n", Conf_PingTimeout);
! 394: printf(" PongTimeout = %d\n", Conf_PongTimeout);
! 395: puts("");
! 396:
! 397: puts("[OPTIONS]");
! 398: printf(" AllowedChannelTypes = %s\n", Conf_AllowedChannelTypes);
! 399: printf(" AllowRemoteOper = %s\n", yesno_to_str(Conf_AllowRemoteOper));
! 400: printf(" ChrootDir = %s\n", Conf_Chroot);
! 401: printf(" CloakHost = %s\n", Conf_CloakHost);
! 402: printf(" CloakHostModeX = %s\n", Conf_CloakHostModeX);
! 403: printf(" CloakHostSalt = %s\n", Conf_CloakHostSalt);
! 404: printf(" CloakUserToNick = %s\n", yesno_to_str(Conf_CloakUserToNick));
! 405: #ifdef WANT_IPV6
! 406: printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
! 407: printf(" ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
! 408: #endif
! 409: printf(" DefaultUserModes = %s\n", Conf_DefaultUserModes);
! 410: printf(" DNS = %s\n", yesno_to_str(Conf_DNS));
! 411: #ifdef IDENT
! 412: printf(" Ident = %s\n", yesno_to_str(Conf_Ident));
! 413: #endif
! 414: printf(" IncludeDir = %s\n", Conf_IncludeDir);
! 415: printf(" MorePrivacy = %s\n", yesno_to_str(Conf_MorePrivacy));
! 416: printf(" NoticeBeforeRegistration = %s\n", yesno_to_str(Conf_NoticeBeforeRegistration));
! 417: printf(" OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
! 418: printf(" OperChanPAutoOp = %s\n", yesno_to_str(Conf_OperChanPAutoOp));
! 419: printf(" OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
! 420: #ifdef PAM
! 421: printf(" PAM = %s\n", yesno_to_str(Conf_PAM));
! 422: printf(" PAMIsOptional = %s\n", yesno_to_str(Conf_PAMIsOptional));
! 423: printf(" PAMServiceName = %s\n", Conf_PAMServiceName);
! 424: #endif
! 425: #ifndef STRICT_RFC
! 426: printf(" RequireAuthPing = %s\n", yesno_to_str(Conf_AuthPing));
! 427: #endif
! 428: printf(" ScrubCTCP = %s\n", yesno_to_str(Conf_ScrubCTCP));
! 429: #ifdef SYSLOG
! 430: printf(" SyslogFacility = %s\n",
! 431: ngt_SyslogFacilityName(Conf_SyslogFacility));
! 432: #endif
! 433: printf(" WebircPassword = %s\n", Conf_WebircPwd);
! 434: puts("");
! 435:
! 436: #ifdef SSL_SUPPORT
! 437: puts("[SSL]");
! 438: printf(" CertFile = %s\n", Conf_SSLOptions.CertFile
! 439: ? Conf_SSLOptions.CertFile : "");
! 440: printf(" CipherList = %s\n", Conf_SSLOptions.CipherList ?
! 441: Conf_SSLOptions.CipherList : DEFAULT_CIPHERS);
! 442: printf(" DHFile = %s\n", Conf_SSLOptions.DHFile
! 443: ? Conf_SSLOptions.DHFile : "");
! 444: printf(" KeyFile = %s\n", Conf_SSLOptions.KeyFile
! 445: ? Conf_SSLOptions.KeyFile : "");
! 446: if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
! 447: puts(" KeyFilePassword = <secret>");
! 448: else
! 449: puts(" KeyFilePassword = ");
! 450: array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
! 451: printf(" Ports = ");
! 452: ports_puts(&Conf_SSLOptions.ListenPorts);
! 453: puts("");
! 454: #endif
! 455:
! 456: opers_puts();
! 457:
! 458: for( i = 0; i < MAX_SERVERS; i++ ) {
! 459: if( ! Conf_Server[i].name[0] ) continue;
! 460:
! 461: /* Valid "Server" section */
! 462: puts( "[SERVER]" );
! 463: printf( " Name = %s\n", Conf_Server[i].name );
! 464: printf( " Host = %s\n", Conf_Server[i].host );
! 465: printf( " Port = %u\n", (unsigned int)Conf_Server[i].port );
! 466: #ifdef SSL_SUPPORT
! 467: printf( " SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
! 468: #endif
! 469: printf( " MyPassword = %s\n", Conf_Server[i].pwd_in );
! 470: printf( " PeerPassword = %s\n", Conf_Server[i].pwd_out );
! 471: printf( " ServiceMask = %s\n", Conf_Server[i].svs_mask);
! 472: printf( " Group = %d\n", Conf_Server[i].group );
! 473: printf( " Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
! 474: }
! 475:
! 476: predef_channel_count = array_length(&Conf_Channels, sizeof(*predef_chan));
! 477: predef_chan = array_start(&Conf_Channels);
! 478:
! 479: for (i = 0; i < predef_channel_count; i++, predef_chan++) {
! 480: if (!predef_chan->name[0])
! 481: continue;
! 482:
! 483: /* Valid "Channel" section */
! 484: puts( "[CHANNEL]" );
! 485: printf(" Name = %s\n", predef_chan->name);
! 486: for(j = 0; j < predef_chan->modes_num; j++)
! 487: printf(" Modes = %s\n", predef_chan->modes[j]);
! 488: printf(" Key = %s\n", predef_chan->key);
! 489: printf(" MaxUsers = %lu\n", predef_chan->maxusers);
! 490: printf(" Topic = %s\n", predef_chan->topic);
! 491: printf(" KeyFile = %s\n\n", predef_chan->keyfile);
! 492: }
! 493:
! 494: return (config_valid ? 0 : 1);
! 495: }
! 496:
! 497: /**
! 498: * Remove connection information from configured server.
! 499: *
! 500: * If the server is set as "once", delete it from our configuration;
! 501: * otherwise set the time for the next connection attempt.
! 502: *
! 503: * Non-server connections will be silently ignored.
! 504: */
! 505: GLOBAL void
! 506: Conf_UnsetServer( CONN_ID Idx )
! 507: {
! 508: int i;
! 509: time_t t;
! 510:
! 511: /* Check all our configured servers */
! 512: for( i = 0; i < MAX_SERVERS; i++ ) {
! 513: if( Conf_Server[i].conn_id != Idx ) continue;
! 514:
! 515: /* Gotcha! Mark server configuration as "unused": */
! 516: Conf_Server[i].conn_id = NONE;
! 517:
! 518: if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
! 519: /* Delete configuration here */
! 520: Init_Server_Struct( &Conf_Server[i] );
! 521: } else {
! 522: /* Set time for next connect attempt */
! 523: t = time(NULL);
! 524: if (Conf_Server[i].lasttry < t - Conf_ConnectRetry) {
! 525: /* The connection has been "long", so we don't
! 526: * require the next attempt to be delayed. */
! 527: Conf_Server[i].lasttry =
! 528: t - Conf_ConnectRetry + RECONNECT_DELAY;
! 529: } else {
! 530: /* "Short" connection, enforce "ConnectRetry"
! 531: * but randomize it a little bit: 15 seconds. */
! 532: Conf_Server[i].lasttry =
! 533: #ifdef HAVE_ARC4RANDOM
! 534: t + (arc4random() % 15);
! 535: #else
! 536: t + rand() / (RAND_MAX / 15);
! 537: #endif
! 538: }
! 539: }
! 540: }
! 541: }
! 542:
! 543: /**
! 544: * Set connection information for specified configured server.
! 545: */
! 546: GLOBAL bool
! 547: Conf_SetServer( int ConfServer, CONN_ID Idx )
! 548: {
! 549: assert( ConfServer > NONE );
! 550: assert( Idx > NONE );
! 551:
! 552: if (Conf_Server[ConfServer].conn_id > NONE &&
! 553: Conf_Server[ConfServer].conn_id != Idx) {
! 554: Log(LOG_ERR,
! 555: "Connection %d: Server configuration of \"%s\" already in use by connection %d!",
! 556: Idx, Conf_Server[ConfServer].name,
! 557: Conf_Server[ConfServer].conn_id);
! 558: Conn_Close(Idx, NULL, "Server configuration already in use", true);
! 559: return false;
! 560: }
! 561: Conf_Server[ConfServer].conn_id = Idx;
! 562: return true;
! 563: }
! 564:
! 565: /**
! 566: * Get index of server in configuration structure.
! 567: */
! 568: GLOBAL int
! 569: Conf_GetServer( CONN_ID Idx )
! 570: {
! 571: int i = 0;
! 572:
! 573: assert( Idx > NONE );
! 574:
! 575: for( i = 0; i < MAX_SERVERS; i++ ) {
! 576: if( Conf_Server[i].conn_id == Idx ) return i;
! 577: }
! 578: return NONE;
! 579: }
! 580:
! 581: /**
! 582: * Enable a server by name and adjust its port number.
! 583: *
! 584: * @returns true if a server has been enabled and now has a valid port
! 585: * number and host name for outgoing connections.
! 586: */
! 587: GLOBAL bool
! 588: Conf_EnableServer( const char *Name, UINT16 Port )
! 589: {
! 590: int i;
! 591:
! 592: assert( Name != NULL );
! 593: for( i = 0; i < MAX_SERVERS; i++ ) {
! 594: if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
! 595: /* Gotcha! Set port and enable server: */
! 596: Conf_Server[i].port = Port;
! 597: Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
! 598: return (Conf_Server[i].port && Conf_Server[i].host[0]);
! 599: }
! 600: }
! 601: return false;
! 602: }
! 603:
! 604: /**
! 605: * Enable a server by name.
! 606: *
! 607: * The server is only usable as outgoing server, if it has set a valid port
! 608: * number for outgoing connections!
! 609: * If not, you have to use Conf_EnableServer() function to make it available.
! 610: *
! 611: * @returns true if a server has been enabled; false otherwise.
! 612: */
! 613: GLOBAL bool
! 614: Conf_EnablePassiveServer(const char *Name)
! 615: {
! 616: int i;
! 617:
! 618: assert( Name != NULL );
! 619: for (i = 0; i < MAX_SERVERS; i++) {
! 620: if ((strcasecmp( Conf_Server[i].name, Name ) == 0)
! 621: && (Conf_Server[i].port > 0)) {
! 622: /* BINGO! Enable server */
! 623: Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
! 624: Conf_Server[i].lasttry = 0;
! 625: return true;
! 626: }
! 627: }
! 628: return false;
! 629: }
! 630:
! 631: /**
! 632: * Disable a server by name.
! 633: * An already established connection will be disconnected.
! 634: *
! 635: * @returns true if a server was found and has been disabled.
! 636: */
! 637: GLOBAL bool
! 638: Conf_DisableServer( const char *Name )
! 639: {
! 640: int i;
! 641:
! 642: assert( Name != NULL );
! 643: for( i = 0; i < MAX_SERVERS; i++ ) {
! 644: if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
! 645: /* Gotcha! Disable and disconnect server: */
! 646: Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
! 647: if( Conf_Server[i].conn_id > NONE )
! 648: Conn_Close(Conf_Server[i].conn_id, NULL,
! 649: "Server link terminated on operator request",
! 650: true);
! 651: return true;
! 652: }
! 653: }
! 654: return false;
! 655: }
! 656:
! 657: /**
! 658: * Add a new remote server to our configuration.
! 659: *
! 660: * @param Name Name of the new server.
! 661: * @param Port Port number to connect to or 0 for incoming connections.
! 662: * @param Host Host name to connect to.
! 663: * @param MyPwd Password that will be sent to the peer.
! 664: * @param PeerPwd Password that must be received from the peer.
! 665: * @returns true if the new server has been added; false otherwise.
! 666: */
! 667: GLOBAL bool
! 668: Conf_AddServer(const char *Name, UINT16 Port, const char *Host,
! 669: const char *MyPwd, const char *PeerPwd)
! 670: {
! 671: int i;
! 672:
! 673: assert( Name != NULL );
! 674: assert( Host != NULL );
! 675: assert( MyPwd != NULL );
! 676: assert( PeerPwd != NULL );
! 677:
! 678: /* Search unused item in server configuration structure */
! 679: for( i = 0; i < MAX_SERVERS; i++ ) {
! 680: /* Is this item used? */
! 681: if( ! Conf_Server[i].name[0] ) break;
! 682: }
! 683: if( i >= MAX_SERVERS ) return false;
! 684:
! 685: Init_Server_Struct( &Conf_Server[i] );
! 686: strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
! 687: strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
! 688: strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
! 689: strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
! 690: Conf_Server[i].port = Port;
! 691: Conf_Server[i].flags = CONF_SFLAG_ONCE;
! 692:
! 693: return true;
! 694: }
! 695:
! 696: /**
! 697: * Check if the given nickname is reserved for services on a particular server.
! 698: *
! 699: * @param ConfServer The server index to check.
! 700: * @param Nick The nickname to check.
! 701: * @returns true if the given nickname belongs to an "IRC service".
! 702: */
! 703: GLOBAL bool
! 704: Conf_NickIsService(int ConfServer, const char *Nick)
! 705: {
! 706: assert (ConfServer >= 0);
! 707: assert (ConfServer < MAX_SERVERS);
! 708:
! 709: return MatchCaseInsensitiveList(Conf_Server[ConfServer].svs_mask,
! 710: Nick, ",");
! 711: }
! 712:
! 713: /**
! 714: * Check if the given nickname is blocked for "normal client" use.
! 715: *
! 716: * @param Nick The nickname to check.
! 717: * @returns true if the given nickname belongs to an "IRC service".
! 718: */
! 719: GLOBAL bool
! 720: Conf_NickIsBlocked(const char *Nick)
! 721: {
! 722: int i;
! 723:
! 724: for(i = 0; i < MAX_SERVERS; i++) {
! 725: if (!Conf_Server[i].name[0])
! 726: continue;
! 727: if (Conf_NickIsService(i, Nick))
! 728: return true;
! 729: }
! 730: return false;
! 731: }
! 732:
! 733: /**
! 734: * Initialize configuration settings with their default values.
! 735: */
! 736: static void
! 737: Set_Defaults(bool InitServers)
! 738: {
! 739: int i;
! 740: char random[RANDOM_SALT_LEN + 1];
! 741:
! 742: /* Global */
! 743: strcpy(Conf_ServerName, "");
! 744: strcpy(Conf_ServerAdmin1, "");
! 745: strcpy(Conf_ServerAdmin2, "");
! 746: strcpy(Conf_ServerAdminMail, "");
! 747: snprintf(Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s",
! 748: PACKAGE_NAME, PACKAGE_VERSION);
! 749: strcpy(Conf_Network, "");
! 750: free(Conf_ListenAddress);
! 751: Conf_ListenAddress = NULL;
! 752: array_free(&Conf_ListenPorts);
! 753: array_free(&Conf_Motd);
! 754: array_free(&Conf_Helptext);
! 755: strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile));
! 756: strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile));
! 757: strlcpy(Conf_HelpFile, DOCDIR, sizeof(Conf_HelpFile));
! 758: strlcat(Conf_HelpFile, HELP_FILE, sizeof(Conf_HelpFile));
! 759: strcpy(Conf_ServerPwd, "");
! 760: strlcpy(Conf_PidFile, PID_FILE, sizeof(Conf_PidFile));
! 761: Conf_UID = Conf_GID = 0;
! 762:
! 763: /* Limits */
! 764: Conf_ConnectRetry = 60;
! 765: Conf_IdleTimeout = 0;
! 766: Conf_MaxConnections = 0;
! 767: Conf_MaxConnectionsIP = 5;
! 768: Conf_MaxJoins = 10;
! 769: Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
! 770: Conf_MaxPenaltyTime = -1;
! 771: Conf_MaxListSize = 100;
! 772: Conf_PingTimeout = 120;
! 773: Conf_PongTimeout = 20;
! 774:
! 775: /* Options */
! 776: strlcpy(Conf_AllowedChannelTypes, CHANTYPES,
! 777: sizeof(Conf_AllowedChannelTypes));
! 778: Conf_AllowRemoteOper = false;
! 779: #ifndef STRICT_RFC
! 780: Conf_AuthPing = false;
! 781: #endif
! 782: strlcpy(Conf_Chroot, CHROOT_DIR, sizeof(Conf_Chroot));
! 783: strcpy(Conf_CloakHost, "");
! 784: strcpy(Conf_CloakHostModeX, "");
! 785: strlcpy(Conf_CloakHostSalt, ngt_RandomStr(random, RANDOM_SALT_LEN),
! 786: sizeof(Conf_CloakHostSalt));
! 787: Conf_CloakUserToNick = false;
! 788: Conf_ConnectIPv4 = true;
! 789: #ifdef WANT_IPV6
! 790: Conf_ConnectIPv6 = true;
! 791: #else
! 792: Conf_ConnectIPv6 = false;
! 793: #endif
! 794: strcpy(Conf_DefaultUserModes, "");
! 795: Conf_DNS = true;
! 796: #ifdef IDENTAUTH
! 797: Conf_Ident = true;
! 798: #else
! 799: Conf_Ident = false;
! 800: #endif
! 801: strcpy(Conf_IncludeDir, "");
! 802: Conf_MorePrivacy = false;
! 803: Conf_NoticeBeforeRegistration = false;
! 804: Conf_OperCanMode = false;
! 805: Conf_OperChanPAutoOp = true;
! 806: Conf_OperServerMode = false;
! 807: #ifdef PAM
! 808: Conf_PAM = true;
! 809: #else
! 810: Conf_PAM = false;
! 811: #endif
! 812: Conf_PAMIsOptional = false;
! 813: strcpy(Conf_PAMServiceName, "ngircd");
! 814: Conf_ScrubCTCP = false;
! 815: #ifdef SYSLOG
! 816: #ifdef LOG_LOCAL5
! 817: Conf_SyslogFacility = LOG_LOCAL5;
! 818: #else
! 819: Conf_SyslogFacility = 0;
! 820: #endif
! 821: #endif
! 822:
! 823: /* Initialize server configuration structures */
! 824: if (InitServers) {
! 825: for (i = 0; i < MAX_SERVERS;
! 826: Init_Server_Struct(&Conf_Server[i++]));
! 827: }
! 828: }
! 829:
! 830: /**
! 831: * Get number of configured listening ports.
! 832: *
! 833: * @returns The number of ports (IPv4+IPv6) on which the server should listen.
! 834: */
! 835: static bool
! 836: no_listenports(void)
! 837: {
! 838: size_t cnt = array_bytes(&Conf_ListenPorts);
! 839: #ifdef SSL_SUPPORT
! 840: cnt += array_bytes(&Conf_SSLOptions.ListenPorts);
! 841: #endif
! 842: return cnt == 0;
! 843: }
! 844:
! 845: /**
! 846: * Read contents of a text file into an array.
! 847: *
! 848: * This function is used to read the MOTD and help text file, for example.
! 849: *
! 850: * @param Filename Name of the file to read.
! 851: * @return true, when the file has been read in.
! 852: */
! 853: static bool
! 854: Read_TextFile(const char *Filename, const char *Name, array *Destination)
! 855: {
! 856: char line[COMMAND_LEN];
! 857: FILE *fp;
! 858: int line_no = 1;
! 859:
! 860: if (*Filename == '\0')
! 861: return false;
! 862:
! 863: fp = fopen(Filename, "r");
! 864: if (!fp) {
! 865: Config_Error(LOG_ERR, "Can't read %s file \"%s\": %s",
! 866: Name, Filename, strerror(errno));
! 867: return false;
! 868: }
! 869:
! 870: array_free(Destination);
! 871: while (fgets(line, (int)sizeof line, fp)) {
! 872: ngt_TrimLastChr(line, '\n');
! 873:
! 874: /* add text including \0 */
! 875: if (!array_catb(Destination, line, strlen(line) + 1)) {
! 876: Log(LOG_ERR, "Cannot read/add \"%s\", line %d: %s",
! 877: Filename, line_no, strerror(errno));
! 878: break;
! 879: }
! 880: line_no++;
! 881: }
! 882: fclose(fp);
! 883: return true;
! 884: }
! 885:
! 886: /**
! 887: * Read ngIRCd configuration file.
! 888: *
! 889: * Please note that this function uses exit(1) on fatal errors and therefore
! 890: * can result in ngIRCd terminating!
! 891: *
! 892: * @param IsStarting Flag indicating if ngIRCd is starting or not.
! 893: * @returns true when the configuration file has been read
! 894: * successfully; false otherwise.
! 895: */
! 896: static bool
! 897: Read_Config(bool TestOnly, bool IsStarting)
! 898: {
! 899: const UINT16 defaultport = 6667;
! 900: char *ptr, file[FNAME_LEN];
! 901: struct dirent *entry;
! 902: int i, n;
! 903: FILE *fd;
! 904: DIR *dh;
! 905:
! 906: Config_Error(LOG_INFO, "Using configuration file \"%s\" ...", NGIRCd_ConfFile);
! 907:
! 908: /* Open configuration file */
! 909: fd = fopen( NGIRCd_ConfFile, "r" );
! 910: if( ! fd ) {
! 911: /* No configuration file found! */
! 912: Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
! 913: NGIRCd_ConfFile, strerror( errno ));
! 914: if (!IsStarting)
! 915: return false;
! 916: Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
! 917: exit( 1 );
! 918: }
! 919:
! 920: opers_free();
! 921: Set_Defaults(IsStarting);
! 922:
! 923: if (TestOnly)
! 924: Config_Error(LOG_INFO,
! 925: "Reading configuration from \"%s\" ...",
! 926: NGIRCd_ConfFile );
! 927:
! 928: /* Clean up server configuration structure: mark all already
! 929: * configured servers as "once" so that they are deleted
! 930: * after the next disconnect and delete all unused servers.
! 931: * And delete all servers which are "duplicates" of servers
! 932: * that are already marked as "once" (such servers have been
! 933: * created by the last rehash but are now useless). */
! 934: for( i = 0; i < MAX_SERVERS; i++ ) {
! 935: if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
! 936: else {
! 937: /* This structure is in use ... */
! 938: if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
! 939: /* Check for duplicates */
! 940: for( n = 0; n < MAX_SERVERS; n++ ) {
! 941: if( n == i ) continue;
! 942:
! 943: if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
! 944: Init_Server_Struct( &Conf_Server[n] );
! 945: #ifdef DEBUG
! 946: Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
! 947: n, i );
! 948: #endif
! 949: }
! 950: }
! 951: } else {
! 952: /* Mark server as "once" */
! 953: Conf_Server[i].flags |= CONF_SFLAG_ONCE;
! 954: Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
! 955: }
! 956: }
! 957: }
! 958:
! 959: /* Initialize variables */
! 960: Init_Server_Struct( &New_Server );
! 961: New_Server_Idx = NONE;
! 962: #ifdef SSL_SUPPORT
! 963: ConfSSL_Init();
! 964: #endif
! 965:
! 966: Read_Config_File(NGIRCd_ConfFile, fd);
! 967: fclose(fd);
! 968:
! 969: if (Conf_IncludeDir[0]) {
! 970: dh = opendir(Conf_IncludeDir);
! 971: if (!dh)
! 972: Config_Error(LOG_ALERT,
! 973: "Can't open include directory \"%s\": %s",
! 974: Conf_IncludeDir, strerror(errno));
! 975: } else {
! 976: strlcpy(Conf_IncludeDir, SYSCONFDIR, sizeof(Conf_IncludeDir));
! 977: strlcat(Conf_IncludeDir, CONFIG_DIR, sizeof(Conf_IncludeDir));
! 978: dh = opendir(Conf_IncludeDir);
! 979: }
! 980:
! 981: /* Include further configuration files, if IncludeDir is available */
! 982: if (dh) {
! 983: while ((entry = readdir(dh)) != NULL) {
! 984: ptr = strrchr(entry->d_name, '.');
! 985: if (!ptr || strcasecmp(ptr, ".conf") != 0)
! 986: continue;
! 987: snprintf(file, sizeof(file), "%s/%s",
! 988: Conf_IncludeDir, entry->d_name);
! 989: if (TestOnly)
! 990: Config_Error(LOG_INFO,
! 991: "Reading configuration from \"%s\" ...",
! 992: file);
! 993: fd = fopen(file, "r");
! 994: if (fd) {
! 995: Read_Config_File(file, fd);
! 996: fclose(fd);
! 997: } else
! 998: Config_Error(LOG_ALERT,
! 999: "Can't read configuration \"%s\": %s",
! 1000: file, strerror(errno));
! 1001: }
! 1002: closedir(dh);
! 1003: }
! 1004:
! 1005: /* Check if there is still a server to add */
! 1006: if( New_Server.name[0] ) {
! 1007: /* Copy data to "real" server structure */
! 1008: assert( New_Server_Idx > NONE );
! 1009: Conf_Server[New_Server_Idx] = New_Server;
! 1010: }
! 1011:
! 1012: /* not a single listening port? Add default. */
! 1013: if (no_listenports() &&
! 1014: !array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport))
! 1015: {
! 1016: Config_Error(LOG_ALERT, "Could not add default listening Port %u: %s",
! 1017: (unsigned int) defaultport, strerror(errno));
! 1018:
! 1019: exit(1);
! 1020: }
! 1021:
! 1022: if (!Conf_ListenAddress)
! 1023: Conf_ListenAddress = strdup_warn(DEFAULT_LISTEN_ADDRSTR);
! 1024:
! 1025: if (!Conf_ListenAddress) {
! 1026: Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
! 1027: exit(1);
! 1028: }
! 1029:
! 1030: /* No MOTD phrase configured? (re)try motd file. */
! 1031: if (array_bytes(&Conf_Motd) == 0) {
! 1032: if (Read_TextFile(Conf_MotdFile, "MOTD", &Conf_Motd))
! 1033: Using_MotdFile = true;
! 1034: }
! 1035:
! 1036: /* Try to read ngIRCd help text file. */
! 1037: (void)Read_TextFile(Conf_HelpFile, "help text", &Conf_Helptext);
! 1038: if (!array_bytes(&Conf_Helptext))
! 1039: Config_Error(LOG_WARNING,
! 1040: "No help text available, HELP command will be of limited use.");
! 1041:
! 1042: #ifdef SSL_SUPPORT
! 1043: /* Make sure that all SSL-related files are readable */
! 1044: CheckFileReadable("CertFile", Conf_SSLOptions.CertFile);
! 1045: CheckFileReadable("DHFile", Conf_SSLOptions.DHFile);
! 1046: CheckFileReadable("KeyFile", Conf_SSLOptions.KeyFile);
! 1047:
! 1048: /* Set the default ciphers if none were configured */
! 1049: if (!Conf_SSLOptions.CipherList)
! 1050: Conf_SSLOptions.CipherList = strdup_warn(DEFAULT_CIPHERS);
! 1051: #endif
! 1052:
! 1053: return true;
! 1054: }
! 1055:
! 1056: /**
! 1057: * Read in and handle a configuration file.
! 1058: *
! 1059: * @param File Name of the configuration file.
! 1060: * @param fd File descriptor already opened for reading.
! 1061: */
! 1062: static void
! 1063: Read_Config_File(const char *File, FILE *fd)
! 1064: {
! 1065: char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
! 1066: int i, line = 0;
! 1067: size_t count;
! 1068:
! 1069: /* Read configuration file */
! 1070: section[0] = '\0';
! 1071: while (true) {
! 1072: if (!fgets(str, sizeof(str), fd))
! 1073: break;
! 1074: ngt_TrimStr(str);
! 1075: line++;
! 1076:
! 1077: /* Skip comments and empty lines */
! 1078: if (str[0] == ';' || str[0] == '#' || str[0] == '\0')
! 1079: continue;
! 1080:
! 1081: if (strlen(str) >= sizeof(str) - 1) {
! 1082: Config_Error(LOG_WARNING, "%s, line %d too long!",
! 1083: File, line);
! 1084: continue;
! 1085: }
! 1086:
! 1087: /* Is this the beginning of a new section? */
! 1088: if ((str[0] == '[') && (str[strlen(str) - 1] == ']')) {
! 1089: strlcpy(section, str, sizeof(section));
! 1090: if (strcasecmp(section, "[GLOBAL]") == 0
! 1091: || strcasecmp(section, "[LIMITS]") == 0
! 1092: || strcasecmp(section, "[OPTIONS]") == 0
! 1093: #ifdef SSL_SUPPORT
! 1094: || strcasecmp(section, "[SSL]") == 0
! 1095: #endif
! 1096: )
! 1097: continue;
! 1098:
! 1099: if (strcasecmp(section, "[SERVER]") == 0) {
! 1100: /* Check if there is already a server to add */
! 1101: if (New_Server.name[0]) {
! 1102: /* Copy data to "real" server structure */
! 1103: assert(New_Server_Idx > NONE);
! 1104: Conf_Server[New_Server_Idx] =
! 1105: New_Server;
! 1106: }
! 1107:
! 1108: /* Re-init structure for new server */
! 1109: Init_Server_Struct(&New_Server);
! 1110:
! 1111: /* Search unused item in server configuration structure */
! 1112: for (i = 0; i < MAX_SERVERS; i++) {
! 1113: /* Is this item used? */
! 1114: if (!Conf_Server[i].name[0])
! 1115: break;
! 1116: }
! 1117: if (i >= MAX_SERVERS) {
! 1118: /* Oops, no free item found! */
! 1119: Config_Error(LOG_ERR,
! 1120: "Too many servers configured.");
! 1121: New_Server_Idx = NONE;
! 1122: } else
! 1123: New_Server_Idx = i;
! 1124: continue;
! 1125: }
! 1126:
! 1127: if (strcasecmp(section, "[CHANNEL]") == 0) {
! 1128: count = array_length(&Conf_Channels,
! 1129: sizeof(struct
! 1130: Conf_Channel));
! 1131: if (!array_alloc
! 1132: (&Conf_Channels,
! 1133: sizeof(struct Conf_Channel), count)) {
! 1134: Config_Error(LOG_ERR,
! 1135: "Could not allocate memory for new operator (line %d)",
! 1136: line);
! 1137: }
! 1138: continue;
! 1139: }
! 1140:
! 1141: if (strcasecmp(section, "[OPERATOR]") == 0) {
! 1142: count = array_length(&Conf_Opers,
! 1143: sizeof(struct Conf_Oper));
! 1144: if (!array_alloc(&Conf_Opers,
! 1145: sizeof(struct Conf_Oper),
! 1146: count)) {
! 1147: Config_Error(LOG_ERR,
! 1148: "Could not allocate memory for new channel (line &d)",
! 1149: line);
! 1150: }
! 1151: continue;
! 1152: }
! 1153:
! 1154: Config_Error(LOG_ERR,
! 1155: "%s, line %d: Unknown section \"%s\"!",
! 1156: File, line, section);
! 1157: section[0] = 0x1;
! 1158: }
! 1159: if (section[0] == 0x1)
! 1160: continue;
! 1161:
! 1162: /* Split line into variable name and parameters */
! 1163: ptr = strchr(str, '=');
! 1164: if (!ptr) {
! 1165: Config_Error(LOG_ERR, "%s, line %d: Syntax error!",
! 1166: File, line);
! 1167: continue;
! 1168: }
! 1169: *ptr = '\0';
! 1170: var = str;
! 1171: ngt_TrimStr(var);
! 1172: arg = ptr + 1;
! 1173: ngt_TrimStr(arg);
! 1174:
! 1175: if (strcasecmp(section, "[GLOBAL]") == 0)
! 1176: Handle_GLOBAL(File, line, var, arg);
! 1177: else if (strcasecmp(section, "[LIMITS]") == 0)
! 1178: Handle_LIMITS(File, line, var, arg);
! 1179: else if (strcasecmp(section, "[OPTIONS]") == 0)
! 1180: Handle_OPTIONS(File, line, var, arg);
! 1181: #ifdef SSL_SUPPORT
! 1182: else if (strcasecmp(section, "[SSL]") == 0)
! 1183: Handle_SSL(File, line, var, arg);
! 1184: #endif
! 1185: else if (strcasecmp(section, "[OPERATOR]") == 0)
! 1186: Handle_OPERATOR(File, line, var, arg);
! 1187: else if (strcasecmp(section, "[SERVER]") == 0)
! 1188: Handle_SERVER(File, line, var, arg);
! 1189: else if (strcasecmp(section, "[CHANNEL]") == 0)
! 1190: Handle_CHANNEL(File, line, var, arg);
! 1191: else
! 1192: Config_Error(LOG_ERR,
! 1193: "%s, line %d: Variable \"%s\" outside section!",
! 1194: File, line, var);
! 1195: }
! 1196: }
! 1197:
! 1198: /**
! 1199: * Check whether a string argument is "true" or "false".
! 1200: *
! 1201: * @param Arg Input string.
! 1202: * @returns true if the input string has been parsed as "yes", "true"
! 1203: * (case insensitive) or a non-zero integer value.
! 1204: */
! 1205: static bool
! 1206: Check_ArgIsTrue(const char *Arg)
! 1207: {
! 1208: if (strcasecmp(Arg, "yes") == 0)
! 1209: return true;
! 1210: if (strcasecmp(Arg, "true") == 0)
! 1211: return true;
! 1212: if (atoi(Arg) != 0)
! 1213: return true;
! 1214:
! 1215: return false;
! 1216: }
! 1217:
! 1218: /**
! 1219: * Handle setting of "MaxNickLength".
! 1220: *
! 1221: * @param Line Line number in configuration file.
! 1222: * @raram Arg Input string.
! 1223: * @returns New configured maximum nickname length.
! 1224: */
! 1225: static unsigned int
! 1226: Handle_MaxNickLength(const char *File, int Line, const char *Arg)
! 1227: {
! 1228: unsigned new;
! 1229:
! 1230: new = (unsigned) atoi(Arg) + 1;
! 1231: if (new > CLIENT_NICK_LEN) {
! 1232: Config_Error(LOG_WARNING,
! 1233: "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
! 1234: File, Line, CLIENT_NICK_LEN - 1);
! 1235: return CLIENT_NICK_LEN;
! 1236: }
! 1237: if (new < 2) {
! 1238: Config_Error(LOG_WARNING,
! 1239: "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
! 1240: File, Line);
! 1241: return 2;
! 1242: }
! 1243: return new;
! 1244: }
! 1245:
! 1246: /**
! 1247: * Output a warning messages if IDENT is configured but not compiled in.
! 1248: */
! 1249: static void
! 1250: WarnIdent(const char UNUSED *File, int UNUSED Line)
! 1251: {
! 1252: #ifndef IDENTAUTH
! 1253: if (Conf_Ident) {
! 1254: /* user has enabled ident lookups explicitly, but ... */
! 1255: Config_Error(LOG_WARNING,
! 1256: "%s: line %d: \"Ident = yes\", but ngircd was built without IDENT support!",
! 1257: File, Line);
! 1258: }
! 1259: #endif
! 1260: }
! 1261:
! 1262: /**
! 1263: * Output a warning messages if IPv6 is configured but not compiled in.
! 1264: */
! 1265: static void
! 1266: WarnIPv6(const char UNUSED *File, int UNUSED Line)
! 1267: {
! 1268: #ifndef WANT_IPV6
! 1269: if (Conf_ConnectIPv6) {
! 1270: /* user has enabled IPv6 explicitly, but ... */
! 1271: Config_Error(LOG_WARNING,
! 1272: "%s: line %d: \"ConnectIPv6 = yes\", but ngircd was built without IPv6 support!",
! 1273: File, Line);
! 1274: }
! 1275: #endif
! 1276: }
! 1277:
! 1278: /**
! 1279: * Output a warning messages if PAM is configured but not compiled in.
! 1280: */
! 1281: static void
! 1282: WarnPAM(const char UNUSED *File, int UNUSED Line)
! 1283: {
! 1284: #ifndef PAM
! 1285: if (Conf_PAM) {
! 1286: Config_Error(LOG_WARNING,
! 1287: "%s: line %d: \"PAM = yes\", but ngircd was built without PAM support!",
! 1288: File, Line);
! 1289: }
! 1290: #endif
! 1291: }
! 1292:
! 1293:
! 1294: /**
! 1295: * Handle variable in [Global] configuration section.
! 1296: *
! 1297: * @param Line Line numer in configuration file.
! 1298: * @param Var Variable name.
! 1299: * @param Arg Variable argument.
! 1300: */
! 1301: static void
! 1302: Handle_GLOBAL(const char *File, int Line, char *Var, char *Arg )
! 1303: {
! 1304: struct passwd *pwd;
! 1305: struct group *grp;
! 1306: size_t len;
! 1307: char *ptr;
! 1308:
! 1309: assert(File != NULL);
! 1310: assert(Line > 0);
! 1311: assert(Var != NULL);
! 1312: assert(Arg != NULL);
! 1313:
! 1314: if (strcasecmp(Var, "Name") == 0) {
! 1315: len = strlcpy(Conf_ServerName, Arg, sizeof(Conf_ServerName));
! 1316: if (len >= sizeof(Conf_ServerName))
! 1317: Config_Error_TooLong(File, Line, Var);
! 1318: return;
! 1319: }
! 1320: if (strcasecmp(Var, "AdminInfo1") == 0) {
! 1321: len = strlcpy(Conf_ServerAdmin1, Arg, sizeof(Conf_ServerAdmin1));
! 1322: if (len >= sizeof(Conf_ServerAdmin1))
! 1323: Config_Error_TooLong(File, Line, Var);
! 1324: return;
! 1325: }
! 1326: if (strcasecmp(Var, "AdminInfo2") == 0) {
! 1327: len = strlcpy(Conf_ServerAdmin2, Arg, sizeof(Conf_ServerAdmin2));
! 1328: if (len >= sizeof(Conf_ServerAdmin2))
! 1329: Config_Error_TooLong(File, Line, Var);
! 1330: return;
! 1331: }
! 1332: if (strcasecmp(Var, "AdminEMail") == 0) {
! 1333: len = strlcpy(Conf_ServerAdminMail, Arg,
! 1334: sizeof(Conf_ServerAdminMail));
! 1335: if (len >= sizeof(Conf_ServerAdminMail))
! 1336: Config_Error_TooLong(File, Line, Var);
! 1337: return;
! 1338: }
! 1339: if (strcasecmp(Var, "Info") == 0) {
! 1340: len = strlcpy(Conf_ServerInfo, Arg, sizeof(Conf_ServerInfo));
! 1341: if (len >= sizeof(Conf_ServerInfo))
! 1342: Config_Error_TooLong(File, Line, Var);
! 1343: return;
! 1344: }
! 1345: if (strcasecmp(Var, "HelpFile") == 0) {
! 1346: len = strlcpy(Conf_HelpFile, Arg, sizeof(Conf_HelpFile));
! 1347: if (len >= sizeof(Conf_HelpFile))
! 1348: Config_Error_TooLong(File, Line, Var);
! 1349: return;
! 1350: }
! 1351: if (strcasecmp(Var, "Listen") == 0) {
! 1352: if (Conf_ListenAddress) {
! 1353: Config_Error(LOG_ERR,
! 1354: "Multiple Listen= options, ignoring: %s",
! 1355: Arg);
! 1356: return;
! 1357: }
! 1358: Conf_ListenAddress = strdup_warn(Arg);
! 1359: /* If allocation fails, we're in trouble: we cannot ignore the
! 1360: * error -- otherwise ngircd would listen on all interfaces. */
! 1361: if (!Conf_ListenAddress) {
! 1362: Config_Error(LOG_ALERT,
! 1363: "%s exiting due to fatal errors!",
! 1364: PACKAGE_NAME);
! 1365: exit(1);
! 1366: }
! 1367: return;
! 1368: }
! 1369: if (strcasecmp(Var, "MotdFile") == 0) {
! 1370: len = strlcpy(Conf_MotdFile, Arg, sizeof(Conf_MotdFile));
! 1371: if (len >= sizeof(Conf_MotdFile))
! 1372: Config_Error_TooLong(File, Line, Var);
! 1373: return;
! 1374: }
! 1375: if (strcasecmp(Var, "MotdPhrase") == 0) {
! 1376: len = strlen(Arg);
! 1377: if (len == 0)
! 1378: return;
! 1379: if (len >= 127) {
! 1380: Config_Error_TooLong(File, Line, Var);
! 1381: return;
! 1382: }
! 1383: if (!array_copyb(&Conf_Motd, Arg, len + 1))
! 1384: Config_Error(LOG_WARNING,
! 1385: "%s, line %d: Could not append MotdPhrase: %s",
! 1386: File, Line, strerror(errno));
! 1387: Using_MotdFile = false;
! 1388: return;
! 1389: }
! 1390: if (strcasecmp(Var, "Network") == 0) {
! 1391: len = strlcpy(Conf_Network, Arg, sizeof(Conf_Network));
! 1392: if (len >= sizeof(Conf_Network))
! 1393: Config_Error_TooLong(File, Line, Var);
! 1394: ptr = strchr(Conf_Network, ' ');
! 1395: if (ptr) {
! 1396: Config_Error(LOG_WARNING,
! 1397: "%s, line %d: \"Network\" can't contain spaces!",
! 1398: File, Line);
! 1399: *ptr = '\0';
! 1400: }
! 1401: return;
! 1402: }
! 1403: if(strcasecmp(Var, "Password") == 0) {
! 1404: len = strlcpy(Conf_ServerPwd, Arg, sizeof(Conf_ServerPwd));
! 1405: if (len >= sizeof(Conf_ServerPwd))
! 1406: Config_Error_TooLong(File, Line, Var);
! 1407: return;
! 1408: }
! 1409: if (strcasecmp(Var, "PidFile") == 0) {
! 1410: len = strlcpy(Conf_PidFile, Arg, sizeof(Conf_PidFile));
! 1411: if (len >= sizeof(Conf_PidFile))
! 1412: Config_Error_TooLong(File, Line, Var);
! 1413: return;
! 1414: }
! 1415: if (strcasecmp(Var, "Ports") == 0) {
! 1416: ports_parse(&Conf_ListenPorts, File, Line, Arg);
! 1417: return;
! 1418: }
! 1419: if (strcasecmp(Var, "ServerGID") == 0) {
! 1420: grp = getgrnam(Arg);
! 1421: if (grp)
! 1422: Conf_GID = grp->gr_gid;
! 1423: else {
! 1424: Conf_GID = (unsigned int)atoi(Arg);
! 1425: if (!Conf_GID && strcmp(Arg, "0"))
! 1426: Config_Error(LOG_WARNING,
! 1427: "%s, line %d: Value of \"%s\" is not a valid group name or ID!",
! 1428: File, Line, Var);
! 1429: }
! 1430: return;
! 1431: }
! 1432: if (strcasecmp(Var, "ServerUID") == 0) {
! 1433: pwd = getpwnam(Arg);
! 1434: if (pwd)
! 1435: Conf_UID = pwd->pw_uid;
! 1436: else {
! 1437: Conf_UID = (unsigned int)atoi(Arg);
! 1438: if (!Conf_UID && strcmp(Arg, "0"))
! 1439: Config_Error(LOG_WARNING,
! 1440: "%s, line %d: Value of \"%s\" is not a valid user name or ID!",
! 1441: File, Line, Var);
! 1442: }
! 1443: return;
! 1444: }
! 1445:
! 1446: Config_Error_Section(File, Line, Var, "Global");
! 1447: }
! 1448:
! 1449: /**
! 1450: * Handle variable in [Limits] configuration section.
! 1451: *
! 1452: * @param Line Line numer in configuration file.
! 1453: * @param Var Variable name.
! 1454: * @param Arg Variable argument.
! 1455: */
! 1456: static void
! 1457: Handle_LIMITS(const char *File, int Line, char *Var, char *Arg)
! 1458: {
! 1459: assert(File != NULL);
! 1460: assert(Line > 0);
! 1461: assert(Var != NULL);
! 1462: assert(Arg != NULL);
! 1463:
! 1464: if (strcasecmp(Var, "ConnectRetry") == 0) {
! 1465: Conf_ConnectRetry = atoi(Arg);
! 1466: if (Conf_ConnectRetry < 5) {
! 1467: Config_Error(LOG_WARNING,
! 1468: "%s, line %d: Value of \"ConnectRetry\" too low!",
! 1469: File, Line);
! 1470: Conf_ConnectRetry = 5;
! 1471: }
! 1472: return;
! 1473: }
! 1474: if (strcasecmp(Var, "IdleTimeout") == 0) {
! 1475: Conf_IdleTimeout = atoi(Arg);
! 1476: if (!Conf_IdleTimeout && strcmp(Arg, "0"))
! 1477: Config_Error_NaN(File, Line, Var);
! 1478: return;
! 1479: }
! 1480: if (strcasecmp(Var, "MaxConnections") == 0) {
! 1481: Conf_MaxConnections = atoi(Arg);
! 1482: if (!Conf_MaxConnections && strcmp(Arg, "0"))
! 1483: Config_Error_NaN(File, Line, Var);
! 1484: return;
! 1485: }
! 1486: if (strcasecmp(Var, "MaxConnectionsIP") == 0) {
! 1487: Conf_MaxConnectionsIP = atoi(Arg);
! 1488: if (!Conf_MaxConnectionsIP && strcmp(Arg, "0"))
! 1489: Config_Error_NaN(File, Line, Var);
! 1490: return;
! 1491: }
! 1492: if (strcasecmp(Var, "MaxJoins") == 0) {
! 1493: Conf_MaxJoins = atoi(Arg);
! 1494: if (!Conf_MaxJoins && strcmp(Arg, "0"))
! 1495: Config_Error_NaN(File, Line, Var);
! 1496: return;
! 1497: }
! 1498: if (strcasecmp(Var, "MaxNickLength") == 0) {
! 1499: Conf_MaxNickLength = Handle_MaxNickLength(File, Line, Arg);
! 1500: return;
! 1501: }
! 1502: if (strcasecmp(Var, "MaxListSize") == 0) {
! 1503: Conf_MaxListSize = atoi(Arg);
! 1504: if (!Conf_MaxListSize && strcmp(Arg, "0"))
! 1505: Config_Error_NaN(File, Line, Var);
! 1506: return;
! 1507: }
! 1508: if (strcasecmp(Var, "MaxPenaltyTime") == 0) {
! 1509: Conf_MaxPenaltyTime = atol(Arg);
! 1510: if (Conf_MaxPenaltyTime < -1)
! 1511: Conf_MaxPenaltyTime = -1; /* "unlimited" */
! 1512: return;
! 1513: }
! 1514: if (strcasecmp(Var, "PingTimeout") == 0) {
! 1515: Conf_PingTimeout = atoi(Arg);
! 1516: if (Conf_PingTimeout < 5) {
! 1517: Config_Error(LOG_WARNING,
! 1518: "%s, line %d: Value of \"PingTimeout\" too low!",
! 1519: File, Line);
! 1520: Conf_PingTimeout = 5;
! 1521: }
! 1522: return;
! 1523: }
! 1524: if (strcasecmp(Var, "PongTimeout") == 0) {
! 1525: Conf_PongTimeout = atoi(Arg);
! 1526: if (Conf_PongTimeout < 5) {
! 1527: Config_Error(LOG_WARNING,
! 1528: "%s, line %d: Value of \"PongTimeout\" too low!",
! 1529: File, Line);
! 1530: Conf_PongTimeout = 5;
! 1531: }
! 1532: return;
! 1533: }
! 1534:
! 1535: Config_Error_Section(File, Line, Var, "Limits");
! 1536: }
! 1537:
! 1538: /**
! 1539: * Handle variable in [Options] configuration section.
! 1540: *
! 1541: * @param Line Line numer in configuration file.
! 1542: * @param Var Variable name.
! 1543: * @param Arg Variable argument.
! 1544: */
! 1545: static void
! 1546: Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
! 1547: {
! 1548: size_t len;
! 1549: char *p;
! 1550:
! 1551: assert(File != NULL);
! 1552: assert(Line > 0);
! 1553: assert(Var != NULL);
! 1554: assert(Arg != NULL);
! 1555:
! 1556: if (strcasecmp(Var, "AllowedChannelTypes") == 0) {
! 1557: p = Arg;
! 1558: Conf_AllowedChannelTypes[0] = '\0';
! 1559: while (*p) {
! 1560: if (strchr(Conf_AllowedChannelTypes, *p)) {
! 1561: /* Prefix is already included; ignore it */
! 1562: p++;
! 1563: continue;
! 1564: }
! 1565:
! 1566: if (strchr(CHANTYPES, *p)) {
! 1567: len = strlen(Conf_AllowedChannelTypes) + 1;
! 1568: assert(len < sizeof(Conf_AllowedChannelTypes));
! 1569: Conf_AllowedChannelTypes[len - 1] = *p;
! 1570: Conf_AllowedChannelTypes[len] = '\0';
! 1571: } else {
! 1572: Config_Error(LOG_WARNING,
! 1573: "%s, line %d: Unknown channel prefix \"%c\" in \"AllowedChannelTypes\"!",
! 1574: File, Line, *p);
! 1575: }
! 1576: p++;
! 1577: }
! 1578: return;
! 1579: }
! 1580: if (strcasecmp(Var, "AllowRemoteOper") == 0) {
! 1581: Conf_AllowRemoteOper = Check_ArgIsTrue(Arg);
! 1582: return;
! 1583: }
! 1584: if (strcasecmp(Var, "ChrootDir") == 0) {
! 1585: len = strlcpy(Conf_Chroot, Arg, sizeof(Conf_Chroot));
! 1586: if (len >= sizeof(Conf_Chroot))
! 1587: Config_Error_TooLong(File, Line, Var);
! 1588: return;
! 1589: }
! 1590: if (strcasecmp(Var, "CloakHost") == 0) {
! 1591: len = strlcpy(Conf_CloakHost, Arg, sizeof(Conf_CloakHost));
! 1592: if (len >= sizeof(Conf_CloakHost))
! 1593: Config_Error_TooLong(File, Line, Var);
! 1594: return;
! 1595: }
! 1596: if (strcasecmp(Var, "CloakHostModeX") == 0) {
! 1597: len = strlcpy(Conf_CloakHostModeX, Arg, sizeof(Conf_CloakHostModeX));
! 1598: if (len >= sizeof(Conf_CloakHostModeX))
! 1599: Config_Error_TooLong(File, Line, Var);
! 1600: return;
! 1601: }
! 1602: if (strcasecmp(Var, "CloakHostSalt") == 0) {
! 1603: len = strlcpy(Conf_CloakHostSalt, Arg, sizeof(Conf_CloakHostSalt));
! 1604: if (len >= sizeof(Conf_CloakHostSalt))
! 1605: Config_Error_TooLong(File, Line, Var);
! 1606: return;
! 1607: }
! 1608: if (strcasecmp(Var, "CloakUserToNick") == 0) {
! 1609: Conf_CloakUserToNick = Check_ArgIsTrue(Arg);
! 1610: return;
! 1611: }
! 1612: if (strcasecmp(Var, "ConnectIPv6") == 0) {
! 1613: Conf_ConnectIPv6 = Check_ArgIsTrue(Arg);
! 1614: WarnIPv6(File, Line);
! 1615: return;
! 1616: }
! 1617: if (strcasecmp(Var, "ConnectIPv4") == 0) {
! 1618: Conf_ConnectIPv4 = Check_ArgIsTrue(Arg);
! 1619: return;
! 1620: }
! 1621: if (strcasecmp(Var, "DefaultUserModes") == 0) {
! 1622: p = Arg;
! 1623: Conf_DefaultUserModes[0] = '\0';
! 1624: while (*p) {
! 1625: if (strchr(Conf_DefaultUserModes, *p)) {
! 1626: /* Mode is already included; ignore it */
! 1627: p++;
! 1628: continue;
! 1629: }
! 1630:
! 1631: if (strchr(USERMODES, *p)) {
! 1632: len = strlen(Conf_DefaultUserModes) + 1;
! 1633: assert(len < sizeof(Conf_DefaultUserModes));
! 1634: Conf_DefaultUserModes[len - 1] = *p;
! 1635: Conf_DefaultUserModes[len] = '\0';
! 1636: } else {
! 1637: Config_Error(LOG_WARNING,
! 1638: "%s, line %d: Unknown user mode \"%c\" in \"DefaultUserModes\"!",
! 1639: File, Line, *p);
! 1640: }
! 1641: p++;
! 1642: }
! 1643: return;
! 1644: }
! 1645: if (strcasecmp(Var, "DNS") == 0) {
! 1646: Conf_DNS = Check_ArgIsTrue(Arg);
! 1647: return;
! 1648: }
! 1649: if (strcasecmp(Var, "Ident") == 0) {
! 1650: Conf_Ident = Check_ArgIsTrue(Arg);
! 1651: WarnIdent(File, Line);
! 1652: return;
! 1653: }
! 1654: if (strcasecmp(Var, "IncludeDir") == 0) {
! 1655: if (Conf_IncludeDir[0]) {
! 1656: Config_Error(LOG_ERR,
! 1657: "%s, line %d: Can't overwrite value of \"IncludeDir\" variable!",
! 1658: File, Line);
! 1659: return;
! 1660: }
! 1661: len = strlcpy(Conf_IncludeDir, Arg, sizeof(Conf_IncludeDir));
! 1662: if (len >= sizeof(Conf_IncludeDir))
! 1663: Config_Error_TooLong(File, Line, Var);
! 1664: return;
! 1665: }
! 1666: if (strcasecmp(Var, "MorePrivacy") == 0) {
! 1667: Conf_MorePrivacy = Check_ArgIsTrue(Arg);
! 1668: return;
! 1669: }
! 1670: if (strcasecmp(Var, "NoticeBeforeRegistration") == 0) {
! 1671: Conf_NoticeBeforeRegistration = Check_ArgIsTrue(Arg);
! 1672: return;
! 1673: }
! 1674: if (strcasecmp(Var, "OperCanUseMode") == 0) {
! 1675: Conf_OperCanMode = Check_ArgIsTrue(Arg);
! 1676: return;
! 1677: }
! 1678: if (strcasecmp(Var, "OperChanPAutoOp") == 0) {
! 1679: Conf_OperChanPAutoOp = Check_ArgIsTrue(Arg);
! 1680: return;
! 1681: }
! 1682: if (strcasecmp(Var, "OperServerMode") == 0) {
! 1683: Conf_OperServerMode = Check_ArgIsTrue(Arg);
! 1684: return;
! 1685: }
! 1686: if (strcasecmp(Var, "PAM") == 0) {
! 1687: Conf_PAM = Check_ArgIsTrue(Arg);
! 1688: WarnPAM(File, Line);
! 1689: return;
! 1690: }
! 1691: if (strcasecmp(Var, "PAMIsOptional") == 0 ) {
! 1692: Conf_PAMIsOptional = Check_ArgIsTrue(Arg);
! 1693: return;
! 1694: }
! 1695: if (strcasecmp(Var, "PAMServiceName") == 0) {
! 1696: len = strlcpy(Conf_PAMServiceName, Arg, sizeof(Conf_PAMServiceName));
! 1697: if (len >= sizeof(Conf_PAMServiceName))
! 1698: Config_Error_TooLong(File, Line, Var);
! 1699: return;
! 1700: }
! 1701: #ifndef STRICT_RFC
! 1702: if (strcasecmp(Var, "RequireAuthPing") == 0) {
! 1703: Conf_AuthPing = Check_ArgIsTrue(Arg);
! 1704: return;
! 1705: }
! 1706: #endif
! 1707: if (strcasecmp(Var, "ScrubCTCP") == 0) {
! 1708: Conf_ScrubCTCP = Check_ArgIsTrue(Arg);
! 1709: return;
! 1710: }
! 1711: #ifdef SYSLOG
! 1712: if (strcasecmp(Var, "SyslogFacility") == 0) {
! 1713: Conf_SyslogFacility = ngt_SyslogFacilityID(Arg,
! 1714: Conf_SyslogFacility);
! 1715: return;
! 1716: }
! 1717: #endif
! 1718: if (strcasecmp(Var, "WebircPassword") == 0) {
! 1719: len = strlcpy(Conf_WebircPwd, Arg, sizeof(Conf_WebircPwd));
! 1720: if (len >= sizeof(Conf_WebircPwd))
! 1721: Config_Error_TooLong(File, Line, Var);
! 1722: return;
! 1723: }
! 1724:
! 1725: Config_Error_Section(File, Line, Var, "Options");
! 1726: }
! 1727:
! 1728: #ifdef SSL_SUPPORT
! 1729:
! 1730: /**
! 1731: * Handle variable in [SSL] configuration section.
! 1732: *
! 1733: * @param Line Line numer in configuration file.
! 1734: * @param Var Variable name.
! 1735: * @param Arg Variable argument.
! 1736: */
! 1737: static void
! 1738: Handle_SSL(const char *File, int Line, char *Var, char *Arg)
! 1739: {
! 1740: assert(File != NULL);
! 1741: assert(Line > 0);
! 1742: assert(Var != NULL);
! 1743: assert(Arg != NULL);
! 1744:
! 1745: if (strcasecmp(Var, "CertFile") == 0) {
! 1746: assert(Conf_SSLOptions.CertFile == NULL);
! 1747: Conf_SSLOptions.CertFile = strdup_warn(Arg);
! 1748: return;
! 1749: }
! 1750: if (strcasecmp(Var, "DHFile") == 0) {
! 1751: assert(Conf_SSLOptions.DHFile == NULL);
! 1752: Conf_SSLOptions.DHFile = strdup_warn(Arg);
! 1753: return;
! 1754: }
! 1755: if (strcasecmp(Var, "KeyFile") == 0) {
! 1756: assert(Conf_SSLOptions.KeyFile == NULL);
! 1757: Conf_SSLOptions.KeyFile = strdup_warn(Arg);
! 1758: return;
! 1759: }
! 1760: if (strcasecmp(Var, "KeyFilePassword") == 0) {
! 1761: assert(array_bytes(&Conf_SSLOptions.KeyFilePassword) == 0);
! 1762: if (!array_copys(&Conf_SSLOptions.KeyFilePassword, Arg))
! 1763: Config_Error(LOG_ERR,
! 1764: "%s, line %d (section \"SSL\"): Could not copy %s: %s!",
! 1765: File, Line, Var, strerror(errno));
! 1766: return;
! 1767: }
! 1768: if (strcasecmp(Var, "Ports") == 0) {
! 1769: ports_parse(&Conf_SSLOptions.ListenPorts, File, Line, Arg);
! 1770: return;
! 1771: }
! 1772: if (strcasecmp(Var, "CipherList") == 0) {
! 1773: assert(Conf_SSLOptions.CipherList == NULL);
! 1774: Conf_SSLOptions.CipherList = strdup_warn(Arg);
! 1775: return;
! 1776: }
! 1777:
! 1778: Config_Error_Section(File, Line, Var, "SSL");
! 1779: }
! 1780:
! 1781: #endif
! 1782:
! 1783: /**
! 1784: * Handle variable in [Operator] configuration section.
! 1785: *
! 1786: * @param Line Line numer in configuration file.
! 1787: * @param Var Variable name.
! 1788: * @param Arg Variable argument.
! 1789: */
! 1790: static void
! 1791: Handle_OPERATOR(const char *File, int Line, char *Var, char *Arg )
! 1792: {
! 1793: size_t len;
! 1794: struct Conf_Oper *op;
! 1795:
! 1796: assert( File != NULL );
! 1797: assert( Line > 0 );
! 1798: assert( Var != NULL );
! 1799: assert( Arg != NULL );
! 1800:
! 1801: op = array_get(&Conf_Opers, sizeof(*op),
! 1802: array_length(&Conf_Opers, sizeof(*op)) - 1);
! 1803: if (!op)
! 1804: return;
! 1805:
! 1806: if (strcasecmp(Var, "Name") == 0) {
! 1807: /* Name of IRC operator */
! 1808: len = strlcpy(op->name, Arg, sizeof(op->name));
! 1809: if (len >= sizeof(op->name))
! 1810: Config_Error_TooLong(File, Line, Var);
! 1811: return;
! 1812: }
! 1813: if (strcasecmp(Var, "Password") == 0) {
! 1814: /* Password of IRC operator */
! 1815: len = strlcpy(op->pwd, Arg, sizeof(op->pwd));
! 1816: if (len >= sizeof(op->pwd))
! 1817: Config_Error_TooLong(File, Line, Var);
! 1818: return;
! 1819: }
! 1820: if (strcasecmp(Var, "Mask") == 0) {
! 1821: if (op->mask)
! 1822: return; /* Hostname already configured */
! 1823: op->mask = strdup_warn( Arg );
! 1824: return;
! 1825: }
! 1826:
! 1827: Config_Error_Section(File, Line, Var, "Operator");
! 1828: }
! 1829:
! 1830: /**
! 1831: * Handle variable in [Server] configuration section.
! 1832: *
! 1833: * @param Line Line numer in configuration file.
! 1834: * @param Var Variable name.
! 1835: * @param Arg Variable argument.
! 1836: */
! 1837: static void
! 1838: Handle_SERVER(const char *File, int Line, char *Var, char *Arg )
! 1839: {
! 1840: long port;
! 1841: size_t len;
! 1842:
! 1843: assert( File != NULL );
! 1844: assert( Line > 0 );
! 1845: assert( Var != NULL );
! 1846: assert( Arg != NULL );
! 1847:
! 1848: /* Ignore server block if no space is left in server configuration structure */
! 1849: if( New_Server_Idx <= NONE ) return;
! 1850:
! 1851: if( strcasecmp( Var, "Host" ) == 0 ) {
! 1852: /* Hostname of the server */
! 1853: len = strlcpy( New_Server.host, Arg, sizeof( New_Server.host ));
! 1854: if (len >= sizeof( New_Server.host ))
! 1855: Config_Error_TooLong(File, Line, Var);
! 1856: return;
! 1857: }
! 1858: if( strcasecmp( Var, "Name" ) == 0 ) {
! 1859: /* Name of the server ("Nick"/"ID") */
! 1860: len = strlcpy( New_Server.name, Arg, sizeof( New_Server.name ));
! 1861: if (len >= sizeof( New_Server.name ))
! 1862: Config_Error_TooLong(File, Line, Var);
! 1863: return;
! 1864: }
! 1865: if (strcasecmp(Var, "Bind") == 0) {
! 1866: if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
! 1867: return;
! 1868:
! 1869: Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
! 1870: File, Line, Arg);
! 1871: return;
! 1872: }
! 1873: if( strcasecmp( Var, "MyPassword" ) == 0 ) {
! 1874: /* Password of this server which is sent to the peer */
! 1875: if (*Arg == ':') {
! 1876: Config_Error(LOG_ERR,
! 1877: "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
! 1878: File, Line);
! 1879: }
! 1880: len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
! 1881: if (len >= sizeof( New_Server.pwd_in ))
! 1882: Config_Error_TooLong(File, Line, Var);
! 1883: return;
! 1884: }
! 1885: if( strcasecmp( Var, "PeerPassword" ) == 0 ) {
! 1886: /* Passwort of the peer which must be received */
! 1887: len = strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out ));
! 1888: if (len >= sizeof( New_Server.pwd_out ))
! 1889: Config_Error_TooLong(File, Line, Var);
! 1890: return;
! 1891: }
! 1892: if( strcasecmp( Var, "Port" ) == 0 ) {
! 1893: /* Port to which this server should connect */
! 1894: port = atol( Arg );
! 1895: if (port >= 0 && port < 0xFFFF)
! 1896: New_Server.port = (UINT16)port;
! 1897: else
! 1898: Config_Error(LOG_ERR,
! 1899: "%s, line %d (section \"Server\"): Illegal port number %ld!",
! 1900: File, Line, port );
! 1901: return;
! 1902: }
! 1903: #ifdef SSL_SUPPORT
! 1904: if( strcasecmp( Var, "SSLConnect" ) == 0 ) {
! 1905: New_Server.SSLConnect = Check_ArgIsTrue(Arg);
! 1906: return;
! 1907: }
! 1908: #endif
! 1909: if( strcasecmp( Var, "Group" ) == 0 ) {
! 1910: /* Server group */
! 1911: New_Server.group = atoi( Arg );
! 1912: if (!New_Server.group && strcmp(Arg, "0"))
! 1913: Config_Error_NaN(File, Line, Var);
! 1914: return;
! 1915: }
! 1916: if( strcasecmp( Var, "Passive" ) == 0 ) {
! 1917: if (Check_ArgIsTrue(Arg))
! 1918: New_Server.flags |= CONF_SFLAG_DISABLED;
! 1919: return;
! 1920: }
! 1921: if (strcasecmp(Var, "ServiceMask") == 0) {
! 1922: len = strlcpy(New_Server.svs_mask, ngt_LowerStr(Arg),
! 1923: sizeof(New_Server.svs_mask));
! 1924: if (len >= sizeof(New_Server.svs_mask))
! 1925: Config_Error_TooLong(File, Line, Var);
! 1926: return;
! 1927: }
! 1928:
! 1929: Config_Error_Section(File, Line, Var, "Server");
! 1930: }
! 1931:
! 1932: /**
! 1933: * Copy channel name into channel structure.
! 1934: *
! 1935: * If the channel name is not valid because of a missing prefix ('#', '&'),
! 1936: * a default prefix of '#' will be added.
! 1937: *
! 1938: * @param new_chan New already allocated channel structure.
! 1939: * @param name Name of the new channel.
! 1940: * @returns true on success, false otherwise.
! 1941: */
! 1942: static bool
! 1943: Handle_Channelname(struct Conf_Channel *new_chan, const char *name)
! 1944: {
! 1945: size_t size = sizeof(new_chan->name);
! 1946: char *dest = new_chan->name;
! 1947:
! 1948: if (!Channel_IsValidName(name)) {
! 1949: /*
! 1950: * maybe user forgot to add a '#'.
! 1951: * This is only here for user convenience.
! 1952: */
! 1953: *dest = '#';
! 1954: --size;
! 1955: ++dest;
! 1956: }
! 1957: return size > strlcpy(dest, name, size);
! 1958: }
! 1959:
! 1960: /**
! 1961: * Handle variable in [Channel] configuration section.
! 1962: *
! 1963: * @param Line Line numer in configuration file.
! 1964: * @param Var Variable name.
! 1965: * @param Arg Variable argument.
! 1966: */
! 1967: static void
! 1968: Handle_CHANNEL(const char *File, int Line, char *Var, char *Arg)
! 1969: {
! 1970: size_t len;
! 1971: struct Conf_Channel *chan;
! 1972:
! 1973: assert( File != NULL );
! 1974: assert( Line > 0 );
! 1975: assert( Var != NULL );
! 1976: assert( Arg != NULL );
! 1977:
! 1978: chan = array_get(&Conf_Channels, sizeof(*chan),
! 1979: array_length(&Conf_Channels, sizeof(*chan)) - 1);
! 1980: if (!chan)
! 1981: return;
! 1982:
! 1983: if (strcasecmp(Var, "Name") == 0) {
! 1984: if (!Handle_Channelname(chan, Arg))
! 1985: Config_Error_TooLong(File, Line, Var);
! 1986: return;
! 1987: }
! 1988: if (strcasecmp(Var, "Modes") == 0) {
! 1989: /* Initial modes */
! 1990: if(chan->modes_num >= sizeof(chan->modes)) {
! 1991: Config_Error(LOG_ERR, "Too many Modes, option ignored.");
! 1992: return;
! 1993: }
! 1994: chan->modes[chan->modes_num++] = strndup(Arg, COMMAND_LEN);
! 1995: if(strlen(Arg) >= COMMAND_LEN)
! 1996: Config_Error_TooLong(File, Line, Var);
! 1997: return;
! 1998: }
! 1999: if( strcasecmp( Var, "Topic" ) == 0 ) {
! 2000: /* Initial topic */
! 2001: len = strlcpy(chan->topic, Arg, sizeof(chan->topic));
! 2002: if (len >= sizeof(chan->topic))
! 2003: Config_Error_TooLong(File, Line, Var);
! 2004: return;
! 2005: }
! 2006: if( strcasecmp( Var, "Key" ) == 0 ) {
! 2007: /* Initial Channel Key (mode k) */
! 2008: len = strlcpy(chan->key, Arg, sizeof(chan->key));
! 2009: if (len >= sizeof(chan->key))
! 2010: Config_Error_TooLong(File, Line, Var);
! 2011: Config_Error(LOG_WARNING,
! 2012: "%s, line %d (section \"Channel\"): \"%s\" is deprecated here, use \"Modes = +k <key>\"!",
! 2013: File, Line, Var);
! 2014: return;
! 2015: }
! 2016: if( strcasecmp( Var, "MaxUsers" ) == 0 ) {
! 2017: /* maximum user limit, mode l */
! 2018: chan->maxusers = (unsigned long) atol(Arg);
! 2019: if (!chan->maxusers && strcmp(Arg, "0"))
! 2020: Config_Error_NaN(File, Line, Var);
! 2021: Config_Error(LOG_WARNING,
! 2022: "%s, line %d (section \"Channel\"): \"%s\" is deprecated here, use \"Modes = +l <limit>\"!",
! 2023: File, Line, Var);
! 2024: return;
! 2025: }
! 2026: if (strcasecmp(Var, "KeyFile") == 0) {
! 2027: /* channel keys */
! 2028: len = strlcpy(chan->keyfile, Arg, sizeof(chan->keyfile));
! 2029: if (len >= sizeof(chan->keyfile))
! 2030: Config_Error_TooLong(File, Line, Var);
! 2031: return;
! 2032: }
! 2033:
! 2034: Config_Error_Section(File, Line, Var, "Channel");
! 2035: }
! 2036:
! 2037: /**
! 2038: * Validate server configuration.
! 2039: *
! 2040: * Please note that this function uses exit(1) on fatal errors and therefore
! 2041: * can result in ngIRCd terminating!
! 2042: *
! 2043: * @param Configtest true if the daemon has been called with "--configtest".
! 2044: * @param Rehash true if re-reading configuration on runtime.
! 2045: * @returns true if configuration is valid.
! 2046: */
! 2047: static bool
! 2048: Validate_Config(bool Configtest, bool Rehash)
! 2049: {
! 2050: /* Validate configuration settings. */
! 2051:
! 2052: #ifdef DEBUG
! 2053: int i, servers, servers_once;
! 2054: #endif
! 2055: bool config_valid = true;
! 2056: char *ptr;
! 2057:
! 2058: /* Emit a warning when the config file is not a full path name */
! 2059: if (NGIRCd_ConfFile[0] && NGIRCd_ConfFile[0] != '/') {
! 2060: Config_Error(LOG_WARNING,
! 2061: "Not specifying a full path name to \"%s\" can cause problems when rehashing the server!",
! 2062: NGIRCd_ConfFile);
! 2063: }
! 2064:
! 2065: /* Validate configured server name, see RFC 2812 section 2.3.1 */
! 2066: ptr = Conf_ServerName;
! 2067: do {
! 2068: if (*ptr >= 'a' && *ptr <= 'z') continue;
! 2069: if (*ptr >= 'A' && *ptr <= 'Z') continue;
! 2070: if (*ptr >= '0' && *ptr <= '9') continue;
! 2071: if (ptr > Conf_ServerName) {
! 2072: if (*ptr == '.' || *ptr == '-')
! 2073: continue;
! 2074: }
! 2075: Conf_ServerName[0] = '\0';
! 2076: break;
! 2077: } while (*(++ptr));
! 2078:
! 2079: if (!Conf_ServerName[0] || !strchr(Conf_ServerName, '.'))
! 2080: {
! 2081: /* No server name configured! */
! 2082: config_valid = false;
! 2083: Config_Error(LOG_ALERT,
! 2084: "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
! 2085: NGIRCd_ConfFile);
! 2086: if (!Configtest && !Rehash) {
! 2087: Config_Error(LOG_ALERT,
! 2088: "%s exiting due to fatal errors!",
! 2089: PACKAGE_NAME);
! 2090: exit(1);
! 2091: }
! 2092: }
! 2093:
! 2094: #ifdef STRICT_RFC
! 2095: if (!Conf_ServerAdminMail[0]) {
! 2096: /* No administrative contact configured! */
! 2097: config_valid = false;
! 2098: Config_Error(LOG_ALERT,
! 2099: "No administrator email address configured in \"%s\" ('AdminEMail')!",
! 2100: NGIRCd_ConfFile);
! 2101: if (!Configtest) {
! 2102: Config_Error(LOG_ALERT,
! 2103: "%s exiting due to fatal errors!",
! 2104: PACKAGE_NAME);
! 2105: exit(1);
! 2106: }
! 2107: }
! 2108: #endif
! 2109:
! 2110: if (!Conf_ServerAdmin1[0] && !Conf_ServerAdmin2[0]
! 2111: && !Conf_ServerAdminMail[0]) {
! 2112: /* No administrative information configured! */
! 2113: Config_Error(LOG_WARNING,
! 2114: "No administrative information configured but required by RFC!");
! 2115: }
! 2116:
! 2117: #ifdef PAM
! 2118: if (Conf_PAM && Conf_ServerPwd[0])
! 2119: Config_Error(LOG_ERR,
! 2120: "This server uses PAM, \"Password\" in [Global] section will be ignored!");
! 2121: #endif
! 2122:
! 2123: if (Conf_MaxPenaltyTime != -1)
! 2124: Config_Error(LOG_WARNING,
! 2125: "Maximum penalty increase ('MaxPenaltyTime') is set to %ld, this is not recommended!",
! 2126: Conf_MaxPenaltyTime);
! 2127:
! 2128: #ifdef DEBUG
! 2129: servers = servers_once = 0;
! 2130: for (i = 0; i < MAX_SERVERS; i++) {
! 2131: if (Conf_Server[i].name[0]) {
! 2132: servers++;
! 2133: if (Conf_Server[i].flags & CONF_SFLAG_ONCE)
! 2134: servers_once++;
! 2135: }
! 2136: }
! 2137: Log(LOG_DEBUG,
! 2138: "Configuration: Operators=%ld, Servers=%d[%d], Channels=%ld",
! 2139: array_length(&Conf_Opers, sizeof(struct Conf_Oper)),
! 2140: servers, servers_once,
! 2141: array_length(&Conf_Channels, sizeof(struct Conf_Channel)));
! 2142: #endif
! 2143:
! 2144: return config_valid;
! 2145: }
! 2146:
! 2147: /**
! 2148: * Output "line too long" warning.
! 2149: *
! 2150: * @param Line Line number in configuration file.
! 2151: * @param Item Affected variable name.
! 2152: */
! 2153: static void
! 2154: Config_Error_TooLong(const char *File, const int Line, const char *Item)
! 2155: {
! 2156: Config_Error(LOG_WARNING, "%s, line %d: Value of \"%s\" too long!",
! 2157: File, Line, Item );
! 2158: }
! 2159:
! 2160: /**
! 2161: * Output "unknown variable" warning.
! 2162: *
! 2163: * @param Line Line number in configuration file.
! 2164: * @param Item Affected variable name.
! 2165: * @param Section Section name.
! 2166: */
! 2167: static void
! 2168: Config_Error_Section(const char *File, const int Line, const char *Item,
! 2169: const char *Section)
! 2170: {
! 2171: Config_Error(LOG_ERR, "%s, line %d (section \"%s\"): Unknown variable \"%s\"!",
! 2172: File, Line, Section, Item);
! 2173: }
! 2174:
! 2175: /**
! 2176: * Output "not a number" warning.
! 2177: *
! 2178: * @param Line Line number in configuration file.
! 2179: * @param Item Affected variable name.
! 2180: */
! 2181: static void
! 2182: Config_Error_NaN(const char *File, const int Line, const char *Item )
! 2183: {
! 2184: Config_Error(LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!",
! 2185: File, Line, Item );
! 2186: }
! 2187:
! 2188: /**
! 2189: * Output configuration error to console and/or logfile.
! 2190: *
! 2191: * On runtime, the normal log functions of the daemon are used. But when
! 2192: * testing the configuration ("--configtest"), all messages go directly
! 2193: * to the console.
! 2194: *
! 2195: * @param Level Severity level of the message.
! 2196: * @param Format Format string; see printf() function.
! 2197: */
! 2198: #ifdef PROTOTYPES
! 2199: static void Config_Error( const int Level, const char *Format, ... )
! 2200: #else
! 2201: static void Config_Error( Level, Format, va_alist )
! 2202: const int Level;
! 2203: const char *Format;
! 2204: va_dcl
! 2205: #endif
! 2206: {
! 2207: char msg[MAX_LOG_MSG_LEN];
! 2208: va_list ap;
! 2209:
! 2210: assert( Format != NULL );
! 2211:
! 2212: #ifdef PROTOTYPES
! 2213: va_start( ap, Format );
! 2214: #else
! 2215: va_start( ap );
! 2216: #endif
! 2217: vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap );
! 2218: va_end( ap );
! 2219:
! 2220: if (!Use_Log) {
! 2221: if (Level <= LOG_WARNING)
! 2222: printf(" - %s\n", msg);
! 2223: else
! 2224: puts(msg);
! 2225: } else
! 2226: Log(Level, "%s", msg);
! 2227: }
! 2228:
! 2229: #ifdef DEBUG
! 2230:
! 2231: /**
! 2232: * Dump internal state of the "configuration module".
! 2233: */
! 2234: GLOBAL void
! 2235: Conf_DebugDump(void)
! 2236: {
! 2237: int i;
! 2238:
! 2239: Log(LOG_DEBUG, "Configured servers:");
! 2240: for (i = 0; i < MAX_SERVERS; i++) {
! 2241: if (! Conf_Server[i].name[0])
! 2242: continue;
! 2243: Log(LOG_DEBUG,
! 2244: " - %s: %s:%d, last=%ld, group=%d, flags=%d, conn=%d",
! 2245: Conf_Server[i].name, Conf_Server[i].host,
! 2246: Conf_Server[i].port, Conf_Server[i].lasttry,
! 2247: Conf_Server[i].group, Conf_Server[i].flags,
! 2248: Conf_Server[i].conn_id);
! 2249: }
! 2250: }
! 2251:
! 2252: #endif
! 2253:
! 2254: /**
! 2255: * Initialize server configuration structure to default values.
! 2256: *
! 2257: * @param Server Pointer to server structure to initialize.
! 2258: */
! 2259: static void
! 2260: Init_Server_Struct( CONF_SERVER *Server )
! 2261: {
! 2262: assert( Server != NULL );
! 2263:
! 2264: memset( Server, 0, sizeof (CONF_SERVER) );
! 2265:
! 2266: Server->group = NONE;
! 2267: Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
! 2268:
! 2269: if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
! 2270:
! 2271: Proc_InitStruct(&Server->res_stat);
! 2272: Server->conn_id = NONE;
! 2273: memset(&Server->bind_addr, 0, sizeof(Server->bind_addr));
! 2274: }
! 2275:
! 2276: /* -eof- */
CVSweb