conf.c 31 KB

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