conf.c 29 KB

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