conf.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001,2002 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. #include "portab.h"
  14. static char UNUSED id[] = "$Id: conf.c,v 1.92 2006/07/23 16:42:45 alex Exp $";
  15. #include "imp.h"
  16. #include <assert.h>
  17. #include <errno.h>
  18. #ifdef PROTOTYPES
  19. # include <stdarg.h>
  20. #else
  21. # include <varargs.h>
  22. #endif
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <strings.h>
  27. #include <unistd.h>
  28. #include <pwd.h>
  29. #include <grp.h>
  30. #include <sys/types.h>
  31. #include <unistd.h>
  32. #ifdef HAVE_CTYPE_H
  33. # include <ctype.h>
  34. #endif
  35. #include "array.h"
  36. #include "ngircd.h"
  37. #include "conn.h"
  38. #include "client.h"
  39. #include "defines.h"
  40. #include "log.h"
  41. #include "resolve.h"
  42. #include "tool.h"
  43. #include "exp.h"
  44. #include "conf.h"
  45. static bool Use_Log = true;
  46. static CONF_SERVER New_Server;
  47. static int New_Server_Idx;
  48. static void Set_Defaults PARAMS(( bool InitServers ));
  49. static void Read_Config PARAMS(( void ));
  50. static void Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
  51. static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
  52. static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
  53. static void Handle_SERVER PARAMS(( int Line, char *Var, char *Arg ));
  54. static void Handle_CHANNEL PARAMS(( int Line, char *Var, char *Arg ));
  55. static void Config_Error PARAMS(( const int Level, const char *Format, ... ));
  56. static void Config_Error_NaN PARAMS(( const int LINE, const char *Value ));
  57. static void Config_Error_TooLong PARAMS(( const int LINE, const char *Value ));
  58. static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
  59. static char *
  60. strdup_warn(const char *str)
  61. {
  62. char *ptr = strdup(str);
  63. if (!ptr)
  64. Config_Error(LOG_ERR, "Could not allocate mem for string: %s", str);
  65. return ptr;
  66. }
  67. static void
  68. ports_puts(array *a)
  69. {
  70. size_t len;
  71. UINT16 *ports;
  72. len = array_length(a, sizeof(UINT16));
  73. if (len--) {
  74. ports = (UINT16*) array_start(a);
  75. printf("%u", (unsigned int) *ports);
  76. while (len--) {
  77. ports++;
  78. printf(", %u", (unsigned int) *ports);
  79. }
  80. }
  81. putc('\n', stdout);
  82. }
  83. static void
  84. ports_parse(array *a, int Line, char *Arg)
  85. {
  86. char *ptr;
  87. int port;
  88. UINT16 port16;
  89. array_trunc(a);
  90. /* Ports on that the server should listen. More port numbers
  91. * must be separated by "," */
  92. ptr = strtok( Arg, "," );
  93. while (ptr) {
  94. ngt_TrimStr( ptr );
  95. port = atol( ptr );
  96. if (port > 0 && port < 0xFFFF) {
  97. port16 = (UINT16) port;
  98. if (!array_catb(a, (char*)&port16, sizeof port16))
  99. Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
  100. NGIRCd_ConfFile, Line, port, strerror(errno));
  101. } else {
  102. Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
  103. NGIRCd_ConfFile, Line, port );
  104. }
  105. ptr = strtok( NULL, "," );
  106. }
  107. }
  108. GLOBAL void
  109. Conf_Init( void )
  110. {
  111. Set_Defaults( true );
  112. Read_Config( );
  113. Validate_Config(false, false);
  114. } /* Config_Init */
  115. GLOBAL void
  116. Conf_Rehash( void )
  117. {
  118. Set_Defaults( false );
  119. Read_Config( );
  120. Validate_Config(false, true);
  121. } /* Config_Rehash */
  122. GLOBAL int
  123. Conf_Test( void )
  124. {
  125. /* Read configuration, validate and output it. */
  126. struct passwd *pwd;
  127. struct group *grp;
  128. unsigned int i;
  129. char *topic;
  130. Use_Log = false;
  131. Set_Defaults( true );
  132. Read_Config( );
  133. Validate_Config(true, false);
  134. /* If stdin and stdout ("you can read our nice message and we can
  135. * read in your keypress") are valid tty's, wait for a key: */
  136. if( isatty( fileno( stdin )) && isatty( fileno( stdout ))) {
  137. puts( "OK, press enter to see a dump of your service configuration ..." );
  138. getchar( );
  139. } else {
  140. puts( "Ok, dump of your server configuration follows:\n" );
  141. }
  142. puts( "[GLOBAL]" );
  143. printf( " Name = %s\n", Conf_ServerName );
  144. printf( " Info = %s\n", Conf_ServerInfo );
  145. printf( " Password = %s\n", Conf_ServerPwd );
  146. printf( " AdminInfo1 = %s\n", Conf_ServerAdmin1 );
  147. printf( " AdminInfo2 = %s\n", Conf_ServerAdmin2 );
  148. printf( " AdminEMail = %s\n", Conf_ServerAdminMail );
  149. printf( " MotdFile = %s\n", Conf_MotdFile );
  150. printf( " MotdPhrase = %s\n", Conf_MotdPhrase );
  151. printf( " ChrootDir = %s\n", Conf_Chroot );
  152. printf( " PidFile = %s\n", Conf_PidFile);
  153. fputs(" Ports = ", stdout);
  154. ports_puts(&Conf_ListenPorts);
  155. printf( " Listen = %s\n", Conf_ListenAddress );
  156. pwd = getpwuid( Conf_UID );
  157. if( pwd ) printf( " ServerUID = %s\n", pwd->pw_name );
  158. else printf( " ServerUID = %ld\n", (long)Conf_UID );
  159. grp = getgrgid( Conf_GID );
  160. if( grp ) printf( " ServerGID = %s\n", grp->gr_name );
  161. else printf( " ServerGID = %ld\n", (long)Conf_GID );
  162. printf( " PingTimeout = %d\n", Conf_PingTimeout );
  163. printf( " PongTimeout = %d\n", Conf_PongTimeout );
  164. printf( " ConnectRetry = %d\n", Conf_ConnectRetry );
  165. printf( " OperCanUseMode = %s\n", Conf_OperCanMode == true? "yes" : "no" );
  166. printf( " OperServerMode = %s\n", Conf_OperServerMode == true? "yes" : "no" );
  167. printf( " MaxConnections = %ld\n", Conf_MaxConnections>0 ? Conf_MaxConnections : -1);
  168. printf( " MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP>0 ? Conf_MaxConnectionsIP : -1);
  169. printf( " MaxJoins = %d\n\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
  170. for( i = 0; i < Conf_Oper_Count; i++ ) {
  171. if( ! Conf_Oper[i].name[0] ) continue;
  172. /* Valid "Operator" section */
  173. puts( "[OPERATOR]" );
  174. printf( " Name = %s\n", Conf_Oper[i].name );
  175. printf( " Password = %s\n", Conf_Oper[i].pwd );
  176. if ( Conf_Oper[i].mask ) printf( " Mask = %s\n", Conf_Oper[i].mask );
  177. puts( "" );
  178. }
  179. for( i = 0; i < MAX_SERVERS; i++ ) {
  180. if( ! Conf_Server[i].name[0] ) continue;
  181. /* Valid "Server" section */
  182. puts( "[SERVER]" );
  183. printf( " Name = %s\n", Conf_Server[i].name );
  184. printf( " Host = %s\n", Conf_Server[i].host );
  185. printf( " Port = %u\n", (unsigned int)Conf_Server[i].port );
  186. printf( " MyPassword = %s\n", Conf_Server[i].pwd_in );
  187. printf( " PeerPassword = %s\n", Conf_Server[i].pwd_out );
  188. printf( " Group = %d\n\n", Conf_Server[i].group );
  189. }
  190. for( i = 0; i < Conf_Channel_Count; i++ ) {
  191. if( ! Conf_Channel[i].name[0] ) continue;
  192. /* Valid "Channel" section */
  193. puts( "[CHANNEL]" );
  194. printf( " Name = %s\n", Conf_Channel[i].name );
  195. printf( " Modes = %s\n", Conf_Channel[i].modes );
  196. topic = (char*)array_start(&Conf_Channel[i].topic);
  197. printf( " Topic = %s\n\n", topic ? topic : "");
  198. }
  199. return 0;
  200. } /* Conf_Test */
  201. GLOBAL void
  202. Conf_UnsetServer( CONN_ID Idx )
  203. {
  204. /* Set next time for next connection attempt, if this is a server
  205. * link that is (still) configured here. If the server is set as
  206. * "once", delete it from our configuration.
  207. * Non-Server-Connections will be silently ignored. */
  208. int i;
  209. time_t t;
  210. /* Check all our configured servers */
  211. for( i = 0; i < MAX_SERVERS; i++ ) {
  212. if( Conf_Server[i].conn_id != Idx ) continue;
  213. /* Gotcha! Mark server configuration as "unused": */
  214. Conf_Server[i].conn_id = NONE;
  215. if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
  216. /* Delete configuration here */
  217. Init_Server_Struct( &Conf_Server[i] );
  218. } else {
  219. /* Set time for next connect attempt */
  220. t = time(NULL);
  221. if (Conf_Server[i].lasttry < t - Conf_ConnectRetry) {
  222. /* The connection has been "long", so we don't
  223. * require the next attempt to be delayed. */
  224. Conf_Server[i].lasttry =
  225. t - Conf_ConnectRetry + RECONNECT_DELAY;
  226. } else
  227. Conf_Server[i].lasttry = t;
  228. }
  229. }
  230. } /* Conf_UnsetServer */
  231. GLOBAL void
  232. Conf_SetServer( int ConfServer, CONN_ID Idx )
  233. {
  234. /* Set connection for specified configured server */
  235. assert( ConfServer > NONE );
  236. assert( Idx > NONE );
  237. Conf_Server[ConfServer].conn_id = Idx;
  238. } /* Conf_SetServer */
  239. GLOBAL int
  240. Conf_GetServer( CONN_ID Idx )
  241. {
  242. /* Get index of server in configuration structure */
  243. int i = 0;
  244. assert( Idx > NONE );
  245. for( i = 0; i < MAX_SERVERS; i++ ) {
  246. if( Conf_Server[i].conn_id == Idx ) return i;
  247. }
  248. return NONE;
  249. } /* Conf_GetServer */
  250. GLOBAL bool
  251. Conf_EnableServer( char *Name, UINT16 Port )
  252. {
  253. /* Enable specified server and adjust port */
  254. int i;
  255. assert( Name != NULL );
  256. for( i = 0; i < MAX_SERVERS; i++ ) {
  257. if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
  258. /* Gotcha! Set port and enable server: */
  259. Conf_Server[i].port = Port;
  260. Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
  261. return true;
  262. }
  263. }
  264. return false;
  265. } /* Conf_EnableServer */
  266. GLOBAL bool
  267. Conf_DisableServer( char *Name )
  268. {
  269. /* Enable specified server and adjust port */
  270. int i;
  271. assert( Name != NULL );
  272. for( i = 0; i < MAX_SERVERS; i++ ) {
  273. if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
  274. /* Gotcha! Disable and disconnect server: */
  275. Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
  276. if( Conf_Server[i].conn_id > NONE ) Conn_Close( Conf_Server[i].conn_id, NULL, "Server link terminated on operator request", true);
  277. return true;
  278. }
  279. }
  280. return false;
  281. } /* Conf_DisableServer */
  282. GLOBAL bool
  283. Conf_AddServer( char *Name, UINT16 Port, char *Host, char *MyPwd, char *PeerPwd )
  284. {
  285. /* Add new server to configuration */
  286. int i;
  287. assert( Name != NULL );
  288. assert( Host != NULL );
  289. assert( MyPwd != NULL );
  290. assert( PeerPwd != NULL );
  291. /* Search unused item in server configuration structure */
  292. for( i = 0; i < MAX_SERVERS; i++ ) {
  293. /* Is this item used? */
  294. if( ! Conf_Server[i].name[0] ) break;
  295. }
  296. if( i >= MAX_SERVERS ) return false;
  297. Init_Server_Struct( &Conf_Server[i] );
  298. strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
  299. strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
  300. strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
  301. strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
  302. Conf_Server[i].port = Port;
  303. Conf_Server[i].flags = CONF_SFLAG_ONCE;
  304. return true;
  305. } /* Conf_AddServer */
  306. static void
  307. Set_Defaults( bool InitServers )
  308. {
  309. /* Initialize configuration variables with default values. */
  310. int i;
  311. strcpy( Conf_ServerName, "" );
  312. snprintf( Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION );
  313. strcpy( Conf_ServerPwd, "" );
  314. strcpy( Conf_ServerAdmin1, "" );
  315. strcpy( Conf_ServerAdmin2, "" );
  316. strcpy( Conf_ServerAdminMail, "" );
  317. strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile ));
  318. strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile ));
  319. strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase ));
  320. strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot ));
  321. strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile ));
  322. strcpy( Conf_ListenAddress, "" );
  323. Conf_UID = Conf_GID = 0;
  324. Conf_PingTimeout = 120;
  325. Conf_PongTimeout = 20;
  326. Conf_ConnectRetry = 60;
  327. Conf_Oper_Count = 0;
  328. Conf_Channel_Count = 0;
  329. Conf_OperCanMode = false;
  330. Conf_OperServerMode = false;
  331. Conf_MaxConnections = -1;
  332. Conf_MaxConnectionsIP = 5;
  333. Conf_MaxJoins = 10;
  334. /* Initialize server configuration structures */
  335. if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
  336. } /* Set_Defaults */
  337. static void
  338. Read_Config( void )
  339. {
  340. /* Read configuration file. */
  341. char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
  342. const UINT16 defaultport = 6667;
  343. int line, i, n;
  344. FILE *fd;
  345. /* Open configuration file */
  346. fd = fopen( NGIRCd_ConfFile, "r" );
  347. if( ! fd ) {
  348. /* No configuration file found! */
  349. Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
  350. NGIRCd_ConfFile, strerror( errno ));
  351. Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  352. exit( 1 );
  353. }
  354. Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
  355. /* Clean up server configuration structure: mark all already
  356. * configured servers as "once" so that they are deleted
  357. * after the next disconnect and delete all unused servers.
  358. * And delete all servers which are "duplicates" of servers
  359. * that are already marked as "once" (such servers have been
  360. * created by the last rehash but are now useless). */
  361. for( i = 0; i < MAX_SERVERS; i++ ) {
  362. if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
  363. else {
  364. /* This structure is in use ... */
  365. if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
  366. /* Check for duplicates */
  367. for( n = 0; n < MAX_SERVERS; n++ ) {
  368. if( n == i ) continue;
  369. if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
  370. Init_Server_Struct( &Conf_Server[n] );
  371. #ifdef DEBUG
  372. Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
  373. n, i );
  374. #endif
  375. }
  376. }
  377. } else {
  378. /* Mark server as "once" */
  379. Conf_Server[i].flags |= CONF_SFLAG_ONCE;
  380. Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
  381. }
  382. }
  383. }
  384. /* Initialize variables */
  385. line = 0;
  386. strcpy( section, "" );
  387. Init_Server_Struct( &New_Server );
  388. New_Server_Idx = NONE;
  389. /* Read configuration file */
  390. while( true ) {
  391. if( ! fgets( str, LINE_LEN, fd )) break;
  392. ngt_TrimStr( str );
  393. line++;
  394. /* Skip comments and empty lines */
  395. if( str[0] == ';' || str[0] == '#' || str[0] == '\0' ) continue;
  396. /* Is this the beginning of a new section? */
  397. if(( str[0] == '[' ) && ( str[strlen( str ) - 1] == ']' )) {
  398. strlcpy( section, str, sizeof( section ));
  399. if( strcasecmp( section, "[GLOBAL]" ) == 0 )
  400. continue;
  401. if( strcasecmp( section, "[OPERATOR]" ) == 0 ) {
  402. if( Conf_Oper_Count + 1 > MAX_OPERATORS )
  403. Config_Error( LOG_ERR, "Too many operators configured.");
  404. else {
  405. /* Initialize new operator structure */
  406. Conf_Oper[Conf_Oper_Count].name[0] = '\0';
  407. Conf_Oper[Conf_Oper_Count].pwd[0] = '\0';
  408. if (Conf_Oper[Conf_Oper_Count].mask) {
  409. free(Conf_Oper[Conf_Oper_Count].mask );
  410. Conf_Oper[Conf_Oper_Count].mask = NULL;
  411. }
  412. Conf_Oper_Count++;
  413. }
  414. continue;
  415. }
  416. if( strcasecmp( section, "[SERVER]" ) == 0 ) {
  417. /* Check if there is already a server to add */
  418. if( New_Server.name[0] ) {
  419. /* Copy data to "real" server structure */
  420. assert( New_Server_Idx > NONE );
  421. Conf_Server[New_Server_Idx] = New_Server;
  422. }
  423. /* Re-init structure for new server */
  424. Init_Server_Struct( &New_Server );
  425. /* Search unused item in server configuration structure */
  426. for( i = 0; i < MAX_SERVERS; i++ ) {
  427. /* Is this item used? */
  428. if( ! Conf_Server[i].name[0] ) break;
  429. }
  430. if( i >= MAX_SERVERS ) {
  431. /* Oops, no free item found! */
  432. Config_Error( LOG_ERR, "Too many servers configured." );
  433. New_Server_Idx = NONE;
  434. }
  435. else New_Server_Idx = i;
  436. continue;
  437. }
  438. if( strcasecmp( section, "[CHANNEL]" ) == 0 ) {
  439. if( Conf_Channel_Count + 1 > MAX_DEFCHANNELS ) {
  440. Config_Error( LOG_ERR, "Too many pre-defined channels configured." );
  441. } else {
  442. /* Initialize new channel structure */
  443. strcpy( Conf_Channel[Conf_Channel_Count].name, "" );
  444. strcpy( Conf_Channel[Conf_Channel_Count].modes, "" );
  445. array_free(&Conf_Channel[Conf_Channel_Count].topic);
  446. Conf_Channel_Count++;
  447. }
  448. continue;
  449. }
  450. Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section );
  451. section[0] = 0x1;
  452. }
  453. if( section[0] == 0x1 ) continue;
  454. /* Split line into variable name and parameters */
  455. ptr = strchr( str, '=' );
  456. if( ! ptr ) {
  457. Config_Error( LOG_ERR, "%s, line %d: Syntax error!", NGIRCd_ConfFile, line );
  458. continue;
  459. }
  460. *ptr = '\0';
  461. var = str; ngt_TrimStr( var );
  462. arg = ptr + 1; ngt_TrimStr( arg );
  463. if( strcasecmp( section, "[GLOBAL]" ) == 0 ) Handle_GLOBAL( line, var, arg );
  464. else if( strcasecmp( section, "[OPERATOR]" ) == 0 ) Handle_OPERATOR( line, var, arg );
  465. else if( strcasecmp( section, "[SERVER]" ) == 0 ) Handle_SERVER( line, var, arg );
  466. else if( strcasecmp( section, "[CHANNEL]" ) == 0 ) Handle_CHANNEL( line, var, arg );
  467. else Config_Error( LOG_ERR, "%s, line %d: Variable \"%s\" outside section!", NGIRCd_ConfFile, line, var );
  468. }
  469. /* Close configuration file */
  470. fclose( fd );
  471. /* Check if there is still a server to add */
  472. if( New_Server.name[0] ) {
  473. /* Copy data to "real" server structure */
  474. assert( New_Server_Idx > NONE );
  475. Conf_Server[New_Server_Idx] = New_Server;
  476. }
  477. if (0 == array_length(&Conf_ListenPorts, sizeof(UINT16))) {
  478. if (!array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport)) {
  479. Config_Error( LOG_ALERT, "Could not add default listening Port %u: %s",
  480. (unsigned int) defaultport, strerror(errno));
  481. exit( 1 );
  482. }
  483. }
  484. } /* Read_Config */
  485. static bool
  486. Check_ArgIsTrue( const char *Arg )
  487. {
  488. if( strcasecmp( Arg, "yes" ) == 0 ) return true;
  489. if( strcasecmp( Arg, "true" ) == 0 ) return true;
  490. if( atoi( Arg ) != 0 ) return true;
  491. return false;
  492. } /* Check_ArgIsTrue */
  493. static void
  494. Handle_GLOBAL( int Line, char *Var, char *Arg )
  495. {
  496. struct passwd *pwd;
  497. struct group *grp;
  498. size_t len;
  499. assert( Line > 0 );
  500. assert( Var != NULL );
  501. assert( Arg != NULL );
  502. if( strcasecmp( Var, "Name" ) == 0 ) {
  503. /* Server name */
  504. len = strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName ));
  505. if (len >= sizeof( Conf_ServerName ))
  506. Config_Error_TooLong( Line, Var );
  507. return;
  508. }
  509. if( strcasecmp( Var, "Info" ) == 0 ) {
  510. /* Info text of server */
  511. len = strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo ));
  512. if (len >= sizeof( Conf_ServerInfo ))
  513. Config_Error_TooLong ( Line, Var );
  514. return;
  515. }
  516. if( strcasecmp( Var, "Password" ) == 0 ) {
  517. /* Global server password */
  518. len = strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd ));
  519. if (len >= sizeof( Conf_ServerPwd ))
  520. Config_Error_TooLong( Line, Var );
  521. return;
  522. }
  523. if( strcasecmp( Var, "AdminInfo1" ) == 0 ) {
  524. /* Administrative info #1 */
  525. len = strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 ));
  526. if (len >= sizeof( Conf_ServerAdmin1 ))
  527. Config_Error_TooLong ( Line, Var );
  528. return;
  529. }
  530. if( strcasecmp( Var, "AdminInfo2" ) == 0 ) {
  531. /* Administrative info #2 */
  532. len = strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 ));
  533. if (len >= sizeof( Conf_ServerAdmin2 ))
  534. Config_Error_TooLong ( Line, Var );
  535. return;
  536. }
  537. if( strcasecmp( Var, "AdminEMail" ) == 0 ) {
  538. /* Administrative email contact */
  539. len = strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail ));
  540. if (len >= sizeof( Conf_ServerAdminMail ))
  541. Config_Error_TooLong( Line, Var );
  542. return;
  543. }
  544. if( strcasecmp( Var, "Ports" ) == 0 ) {
  545. ports_parse(&Conf_ListenPorts, Line, Arg);
  546. return;
  547. }
  548. if( strcasecmp( Var, "MotdFile" ) == 0 ) {
  549. /* "Message of the day" (MOTD) file */
  550. len = strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile ));
  551. if (len >= sizeof( Conf_MotdFile ))
  552. Config_Error_TooLong( Line, Var );
  553. return;
  554. }
  555. if( strcasecmp( Var, "MotdPhrase" ) == 0 ) {
  556. /* "Message of the day" phrase (instead of file) */
  557. len = strlcpy( Conf_MotdPhrase, Arg, sizeof( Conf_MotdPhrase ));
  558. if (len >= sizeof( Conf_MotdPhrase ))
  559. Config_Error_TooLong( Line, Var );
  560. return;
  561. }
  562. if( strcasecmp( Var, "ChrootDir" ) == 0 ) {
  563. /* directory for chroot() */
  564. len = strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot ));
  565. if (len >= sizeof( Conf_Chroot ))
  566. Config_Error_TooLong( Line, Var );
  567. return;
  568. }
  569. if ( strcasecmp( Var, "PidFile" ) == 0 ) {
  570. /* name of pidfile */
  571. len = strlcpy( Conf_PidFile, Arg, sizeof( Conf_PidFile ));
  572. if (len >= sizeof( Conf_PidFile ))
  573. Config_Error_TooLong( Line, Var );
  574. return;
  575. }
  576. if( strcasecmp( Var, "ServerUID" ) == 0 ) {
  577. /* UID the daemon should switch to */
  578. pwd = getpwnam( Arg );
  579. if( pwd ) Conf_UID = pwd->pw_uid;
  580. else {
  581. #ifdef HAVE_ISDIGIT
  582. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  583. else
  584. #endif
  585. Conf_UID = (unsigned int)atoi( Arg );
  586. }
  587. return;
  588. }
  589. if( strcasecmp( Var, "ServerGID" ) == 0 ) {
  590. /* GID the daemon should use */
  591. grp = getgrnam( Arg );
  592. if( grp ) Conf_GID = grp->gr_gid;
  593. else {
  594. #ifdef HAVE_ISDIGIT
  595. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  596. else
  597. #endif
  598. Conf_GID = (unsigned int)atoi( Arg );
  599. }
  600. return;
  601. }
  602. if( strcasecmp( Var, "PingTimeout" ) == 0 ) {
  603. /* PING timeout */
  604. Conf_PingTimeout = atoi( Arg );
  605. if( Conf_PingTimeout < 5 ) {
  606. Config_Error( LOG_WARNING, "%s, line %d: Value of \"PingTimeout\" too low!",
  607. NGIRCd_ConfFile, Line );
  608. Conf_PingTimeout = 5;
  609. }
  610. return;
  611. }
  612. if( strcasecmp( Var, "PongTimeout" ) == 0 ) {
  613. /* PONG timeout */
  614. Conf_PongTimeout = atoi( Arg );
  615. if( Conf_PongTimeout < 5 ) {
  616. Config_Error( LOG_WARNING, "%s, line %d: Value of \"PongTimeout\" too low!",
  617. NGIRCd_ConfFile, Line );
  618. Conf_PongTimeout = 5;
  619. }
  620. return;
  621. }
  622. if( strcasecmp( Var, "ConnectRetry" ) == 0 ) {
  623. /* Seconds between connection attempts to other servers */
  624. Conf_ConnectRetry = atoi( Arg );
  625. if( Conf_ConnectRetry < 5 ) {
  626. Config_Error( LOG_WARNING, "%s, line %d: Value of \"ConnectRetry\" too low!",
  627. NGIRCd_ConfFile, Line );
  628. Conf_ConnectRetry = 5;
  629. }
  630. return;
  631. }
  632. if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
  633. /* Are IRC operators allowed to use MODE in channels they aren't Op in? */
  634. Conf_OperCanMode = Check_ArgIsTrue( Arg );
  635. return;
  636. }
  637. if( strcasecmp( Var, "OperServerMode" ) == 0 ) {
  638. /* Mask IRC operator as if coming from the server? (ircd-irc2 compat hack) */
  639. Conf_OperServerMode = Check_ArgIsTrue( Arg );
  640. return;
  641. }
  642. if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
  643. /* Maximum number of connections. Values <= 0 are equal to "no limit". */
  644. #ifdef HAVE_ISDIGIT
  645. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
  646. else
  647. #endif
  648. Conf_MaxConnections = atol( Arg );
  649. return;
  650. }
  651. if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
  652. /* Maximum number of simultaneous connections from one IP. Values <= 0 -> "no limit" */
  653. #ifdef HAVE_ISDIGIT
  654. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  655. else
  656. #endif
  657. Conf_MaxConnectionsIP = atoi( Arg );
  658. return;
  659. }
  660. if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
  661. /* Maximum number of channels a user can join. Values <= 0 are equal to "no limit". */
  662. #ifdef HAVE_ISDIGIT
  663. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  664. else
  665. #endif
  666. Conf_MaxJoins = atoi( Arg );
  667. return;
  668. }
  669. if( strcasecmp( Var, "Listen" ) == 0 ) {
  670. /* IP-Address to bind sockets */
  671. len = strlcpy( Conf_ListenAddress, Arg, sizeof( Conf_ListenAddress ));
  672. if (len >= sizeof( Conf_ListenAddress ))
  673. Config_Error_TooLong( Line, Var );
  674. return;
  675. }
  676. Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
  677. NGIRCd_ConfFile, Line, Var );
  678. } /* Handle_GLOBAL */
  679. static void
  680. Handle_OPERATOR( int Line, char *Var, char *Arg )
  681. {
  682. unsigned int opercount;
  683. size_t len;
  684. assert( Line > 0 );
  685. assert( Var != NULL );
  686. assert( Arg != NULL );
  687. assert( Conf_Oper_Count > 0 );
  688. if ( Conf_Oper_Count == 0 )
  689. return;
  690. opercount = Conf_Oper_Count - 1;
  691. if( strcasecmp( Var, "Name" ) == 0 ) {
  692. /* Name of IRC operator */
  693. len = strlcpy( Conf_Oper[opercount].name, Arg, sizeof( Conf_Oper[opercount].name ));
  694. if (len >= sizeof( Conf_Oper[opercount].name ))
  695. Config_Error_TooLong( Line, Var );
  696. return;
  697. }
  698. if( strcasecmp( Var, "Password" ) == 0 ) {
  699. /* Password of IRC operator */
  700. len = strlcpy( Conf_Oper[opercount].pwd, Arg, sizeof( Conf_Oper[opercount].pwd ));
  701. if (len >= sizeof( Conf_Oper[opercount].pwd ))
  702. Config_Error_TooLong( Line, Var );
  703. return;
  704. }
  705. if( strcasecmp( Var, "Mask" ) == 0 ) {
  706. if (Conf_Oper[opercount].mask) return; /* Hostname already configured */
  707. Conf_Oper[opercount].mask = strdup_warn( Arg );
  708. return;
  709. }
  710. Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!",
  711. NGIRCd_ConfFile, Line, Var );
  712. } /* Handle_OPERATOR */
  713. static void
  714. Handle_SERVER( int Line, char *Var, char *Arg )
  715. {
  716. long port;
  717. size_t len;
  718. assert( Line > 0 );
  719. assert( Var != NULL );
  720. assert( Arg != NULL );
  721. /* Ignore server block if no space is left in server configuration structure */
  722. if( New_Server_Idx <= NONE ) return;
  723. if( strcasecmp( Var, "Host" ) == 0 ) {
  724. /* Hostname of the server */
  725. len = strlcpy( New_Server.host, Arg, sizeof( New_Server.host ));
  726. if (len >= sizeof( New_Server.host ))
  727. Config_Error_TooLong ( Line, Var );
  728. return;
  729. }
  730. if( strcasecmp( Var, "Name" ) == 0 ) {
  731. /* Name of the server ("Nick"/"ID") */
  732. len = strlcpy( New_Server.name, Arg, sizeof( New_Server.name ));
  733. if (len >= sizeof( New_Server.name ))
  734. Config_Error_TooLong( Line, Var );
  735. return;
  736. }
  737. if( strcasecmp( Var, "MyPassword" ) == 0 ) {
  738. /* Password of this server which is sent to the peer */
  739. if (*Arg == ':') {
  740. Config_Error(LOG_ERR,
  741. "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
  742. NGIRCd_ConfFile, Line);
  743. }
  744. len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
  745. if (len >= sizeof( New_Server.pwd_in ))
  746. Config_Error_TooLong( Line, Var );
  747. return;
  748. }
  749. if( strcasecmp( Var, "PeerPassword" ) == 0 ) {
  750. /* Passwort of the peer which must be received */
  751. len = strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out ));
  752. if (len >= sizeof( New_Server.pwd_out ))
  753. Config_Error_TooLong( Line, Var );
  754. return;
  755. }
  756. if( strcasecmp( Var, "Port" ) == 0 ) {
  757. /* Port to which this server should connect */
  758. port = atol( Arg );
  759. if( port > 0 && port < 0xFFFF )
  760. New_Server.port = (UINT16)port;
  761. else
  762. Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Illegal port number %ld!",
  763. NGIRCd_ConfFile, Line, port );
  764. return;
  765. }
  766. if( strcasecmp( Var, "Group" ) == 0 ) {
  767. /* Server group */
  768. #ifdef HAVE_ISDIGIT
  769. if( ! isdigit( (int)*Arg ))
  770. Config_Error_NaN( Line, Var );
  771. else
  772. #endif
  773. New_Server.group = atoi( Arg );
  774. return;
  775. }
  776. Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
  777. NGIRCd_ConfFile, Line, Var );
  778. } /* Handle_SERVER */
  779. static void
  780. Handle_CHANNEL( int Line, char *Var, char *Arg )
  781. {
  782. size_t len;
  783. size_t chancount = 0;
  784. assert( Line > 0 );
  785. assert( Var != NULL );
  786. assert( Arg != NULL );
  787. if (Conf_Channel_Count > 0)
  788. chancount = Conf_Channel_Count - 1;
  789. if( strcasecmp( Var, "Name" ) == 0 ) {
  790. /* Name of the channel */
  791. len = strlcpy( Conf_Channel[chancount].name, Arg, sizeof( Conf_Channel[chancount].name ));
  792. if (len >= sizeof( Conf_Channel[chancount].name ))
  793. Config_Error_TooLong( Line, Var );
  794. return;
  795. }
  796. if( strcasecmp( Var, "Modes" ) == 0 ) {
  797. /* Initial modes */
  798. len = strlcpy( Conf_Channel[chancount].modes, Arg, sizeof( Conf_Channel[chancount].modes ));
  799. if (len >= sizeof( Conf_Channel[chancount].modes ))
  800. Config_Error_TooLong( Line, Var );
  801. return;
  802. }
  803. if( strcasecmp( Var, "Topic" ) == 0 ) {
  804. /* Initial topic */
  805. if (!array_copys( &Conf_Channel[chancount].topic, Arg))
  806. Config_Error_TooLong( Line, Var );
  807. return;
  808. }
  809. Config_Error( LOG_ERR, "%s, line %d (section \"Channel\"): Unknown variable \"%s\"!",
  810. NGIRCd_ConfFile, Line, Var );
  811. } /* Handle_CHANNEL */
  812. static void
  813. Validate_Config(bool Configtest, bool Rehash)
  814. {
  815. /* Validate configuration settings. */
  816. #ifdef DEBUG
  817. int i, servers, servers_once;
  818. #endif
  819. char *ptr;
  820. /* Validate configured server name, see RFC 2812 section 2.3.1 */
  821. ptr = Conf_ServerName;
  822. do {
  823. if (*ptr >= 'a' && *ptr <= 'z') continue;
  824. if (*ptr >= 'A' && *ptr <= 'Z') continue;
  825. if (*ptr >= '1' && *ptr <= '0') continue;
  826. if (ptr > Conf_ServerName) {
  827. if (*ptr == '.' || *ptr == '-')
  828. continue;
  829. }
  830. Conf_ServerName[0] = '\0';
  831. break;
  832. } while (*(++ptr));
  833. if (!Conf_ServerName[0]) {
  834. /* No server name configured! */
  835. Config_Error(LOG_ALERT,
  836. "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
  837. NGIRCd_ConfFile);
  838. if (!Configtest && !Rehash) {
  839. Config_Error(LOG_ALERT,
  840. "%s exiting due to fatal errors!",
  841. PACKAGE_NAME);
  842. exit(1);
  843. }
  844. }
  845. if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
  846. /* No dot in server name! */
  847. Config_Error(LOG_ALERT,
  848. "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
  849. NGIRCd_ConfFile);
  850. if (!Configtest) {
  851. Config_Error(LOG_ALERT,
  852. "%s exiting due to fatal errors!",
  853. PACKAGE_NAME);
  854. exit(1);
  855. }
  856. }
  857. #ifdef STRICT_RFC
  858. if (!Conf_ServerAdminMail[0]) {
  859. /* No administrative contact configured! */
  860. Config_Error(LOG_ALERT,
  861. "No administrator email address configured in \"%s\" ('AdminEMail')!",
  862. NGIRCd_ConfFile);
  863. if (!Configtest) {
  864. Config_Error(LOG_ALERT,
  865. "%s exiting due to fatal errors!",
  866. PACKAGE_NAME);
  867. exit(1);
  868. }
  869. }
  870. #endif
  871. if (!Conf_ServerAdmin1[0] && !Conf_ServerAdmin2[0]
  872. && !Conf_ServerAdminMail[0]) {
  873. /* No administrative information configured! */
  874. Config_Error(LOG_WARNING,
  875. "No administrative information configured but required by RFC!");
  876. }
  877. #ifdef DEBUG
  878. servers = servers_once = 0;
  879. for (i = 0; i < MAX_SERVERS; i++) {
  880. if (Conf_Server[i].name[0]) {
  881. servers++;
  882. if (Conf_Server[i].flags & CONF_SFLAG_ONCE)
  883. servers_once++;
  884. }
  885. }
  886. Log(LOG_DEBUG,
  887. "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
  888. Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
  889. #endif
  890. } /* Validate_Config */
  891. static void
  892. Config_Error_TooLong ( const int Line, const char *Item )
  893. {
  894. Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" too long!", NGIRCd_ConfFile, Line, Item );
  895. }
  896. static void
  897. Config_Error_NaN( const int Line, const char *Item )
  898. {
  899. Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!",
  900. NGIRCd_ConfFile, Line, Item );
  901. }
  902. #ifdef PROTOTYPES
  903. static void Config_Error( const int Level, const char *Format, ... )
  904. #else
  905. static void Config_Error( Level, Format, va_alist )
  906. const int Level;
  907. const char *Format;
  908. va_dcl
  909. #endif
  910. {
  911. /* Error! Write to console and/or logfile. */
  912. char msg[MAX_LOG_MSG_LEN];
  913. va_list ap;
  914. assert( Format != NULL );
  915. #ifdef PROTOTYPES
  916. va_start( ap, Format );
  917. #else
  918. va_start( ap );
  919. #endif
  920. vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap );
  921. va_end( ap );
  922. /* During "normal operations" the log functions of the daemon should
  923. * be used, but during testing of the configuration file, all messages
  924. * should go directly to the console: */
  925. if (Use_Log) Log( Level, "%s", msg );
  926. else puts( msg );
  927. } /* Config_Error */
  928. static void
  929. Init_Server_Struct( CONF_SERVER *Server )
  930. {
  931. /* Initialize server configuration structur to default values */
  932. assert( Server != NULL );
  933. memset( Server, 0, sizeof (CONF_SERVER) );
  934. Server->group = NONE;
  935. Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
  936. if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
  937. Resolve_Init(&Server->res_stat);
  938. Server->conn_id = NONE;
  939. } /* Init_Server_Struct */
  940. /* -eof- */