conf.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331
  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.105 2008/03/18 20:12:47 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. #ifdef WANT_IPV6
  49. /*
  50. * these options appeared in ngircd 0.12; they are here
  51. * for backwards compatibility. They should be removed
  52. * in the future. Instead of setting these options,
  53. * the "Listen" option should be set accordingly.
  54. */
  55. static bool Conf_ListenIPv6;
  56. static bool Conf_ListenIPv4;
  57. #endif
  58. static void Set_Defaults PARAMS(( bool InitServers ));
  59. static bool Read_Config PARAMS(( bool ngircd_starting ));
  60. static bool Validate_Config PARAMS(( bool TestOnly, bool Rehash ));
  61. static void Handle_GLOBAL PARAMS(( int Line, char *Var, char *Arg ));
  62. static void Handle_OPERATOR PARAMS(( int Line, char *Var, char *Arg ));
  63. static void Handle_SERVER PARAMS(( int Line, char *Var, char *Arg ));
  64. static void Handle_CHANNEL PARAMS(( int Line, char *Var, char *Arg ));
  65. static void Config_Error PARAMS(( const int Level, const char *Format, ... ));
  66. static void Config_Error_NaN PARAMS(( const int LINE, const char *Value ));
  67. static void Config_Error_TooLong PARAMS(( const int LINE, const char *Value ));
  68. static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
  69. static char *
  70. strdup_warn(const char *str)
  71. {
  72. char *ptr = strdup(str);
  73. if (!ptr)
  74. Config_Error(LOG_ERR, "Could not allocate mem for string: %s", str);
  75. return ptr;
  76. }
  77. static void
  78. ports_puts(array *a)
  79. {
  80. size_t len;
  81. UINT16 *ports;
  82. len = array_length(a, sizeof(UINT16));
  83. if (len--) {
  84. ports = (UINT16*) array_start(a);
  85. printf("%u", (unsigned int) *ports);
  86. while (len--) {
  87. ports++;
  88. printf(", %u", (unsigned int) *ports);
  89. }
  90. }
  91. putc('\n', stdout);
  92. }
  93. static void
  94. ports_parse(array *a, int Line, char *Arg)
  95. {
  96. char *ptr;
  97. int port;
  98. UINT16 port16;
  99. array_trunc(a);
  100. /* Ports on that the server should listen. More port numbers
  101. * must be separated by "," */
  102. ptr = strtok( Arg, "," );
  103. while (ptr) {
  104. ngt_TrimStr( ptr );
  105. port = atol( ptr );
  106. if (port > 0 && port < 0xFFFF) {
  107. port16 = (UINT16) port;
  108. if (!array_catb(a, (char*)&port16, sizeof port16))
  109. Config_Error(LOG_ERR, "%s, line %d Could not add port number %ld: %s",
  110. NGIRCd_ConfFile, Line, port, strerror(errno));
  111. } else {
  112. Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Illegal port number %ld!",
  113. NGIRCd_ConfFile, Line, port );
  114. }
  115. ptr = strtok( NULL, "," );
  116. }
  117. }
  118. GLOBAL void
  119. Conf_Init( void )
  120. {
  121. Read_Config( true );
  122. Validate_Config(false, false);
  123. } /* Config_Init */
  124. GLOBAL bool
  125. Conf_Rehash( void )
  126. {
  127. if (!Read_Config(false))
  128. return false;
  129. Validate_Config(false, true);
  130. /* Update CLIENT structure of local server */
  131. Client_SetInfo(Client_ThisServer(), Conf_ServerInfo);
  132. return true;
  133. } /* Config_Rehash */
  134. static const char*
  135. yesno_to_str(int boolean_value)
  136. {
  137. if (boolean_value)
  138. return "yes";
  139. return "no";
  140. }
  141. GLOBAL int
  142. Conf_Test( void )
  143. {
  144. /* Read configuration, validate and output it. */
  145. struct passwd *pwd;
  146. struct group *grp;
  147. unsigned int i;
  148. char *topic;
  149. bool config_valid;
  150. Use_Log = false;
  151. if (! Read_Config(true))
  152. return 1;
  153. config_valid = Validate_Config(true, false);
  154. /* If stdin and stdout ("you can read our nice message and we can
  155. * read in your keypress") are valid tty's, wait for a key: */
  156. if( isatty( fileno( stdin )) && isatty( fileno( stdout ))) {
  157. puts( "OK, press enter to see a dump of your service configuration ..." );
  158. getchar( );
  159. } else {
  160. puts( "Ok, dump of your server configuration follows:\n" );
  161. }
  162. puts( "[GLOBAL]" );
  163. printf( " Name = %s\n", Conf_ServerName );
  164. printf( " Info = %s\n", Conf_ServerInfo );
  165. printf( " Password = %s\n", Conf_ServerPwd );
  166. printf( " AdminInfo1 = %s\n", Conf_ServerAdmin1 );
  167. printf( " AdminInfo2 = %s\n", Conf_ServerAdmin2 );
  168. printf( " AdminEMail = %s\n", Conf_ServerAdminMail );
  169. printf( " MotdFile = %s\n", Conf_MotdFile );
  170. printf( " MotdPhrase = %s\n", Conf_MotdPhrase );
  171. printf( " ChrootDir = %s\n", Conf_Chroot );
  172. printf( " PidFile = %s\n", Conf_PidFile);
  173. fputs(" Ports = ", stdout);
  174. ports_puts(&Conf_ListenPorts);
  175. printf(" Listen = %s\n", Conf_ListenAddress);
  176. pwd = getpwuid( Conf_UID );
  177. if( pwd ) printf( " ServerUID = %s\n", pwd->pw_name );
  178. else printf( " ServerUID = %ld\n", (long)Conf_UID );
  179. grp = getgrgid( Conf_GID );
  180. if( grp ) printf( " ServerGID = %s\n", grp->gr_name );
  181. else printf( " ServerGID = %ld\n", (long)Conf_GID );
  182. printf( " PingTimeout = %d\n", Conf_PingTimeout );
  183. printf( " PongTimeout = %d\n", Conf_PongTimeout );
  184. printf( " ConnectRetry = %d\n", Conf_ConnectRetry );
  185. printf( " OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
  186. printf( " OperServerMode = %s\n", yesno_to_str(Conf_OperServerMode));
  187. printf( " PredefChannelsOnly = %s\n", yesno_to_str(Conf_PredefChannelsOnly));
  188. printf( " NoDNS = %s\n", yesno_to_str(Conf_NoDNS));
  189. #ifdef WANT_IPV6
  190. /* both are deprecated, only mention them if their default value changed. */
  191. if (!Conf_ListenIPv6)
  192. puts(" ListenIPv6 = no");
  193. if (!Conf_ListenIPv4)
  194. puts(" ListenIPv4 = no");
  195. printf(" ConnectIPv4 = %s\n", yesno_to_str(Conf_ConnectIPv6));
  196. printf(" ConnectIPv6 = %s\n", yesno_to_str(Conf_ConnectIPv4));
  197. #endif
  198. printf( " MaxConnections = %ld\n", Conf_MaxConnections);
  199. printf( " MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
  200. printf( " MaxJoins = %d\n", Conf_MaxJoins>0 ? Conf_MaxJoins : -1);
  201. printf( " MaxNickLength = %u\n\n", Conf_MaxNickLength - 1);
  202. for( i = 0; i < Conf_Oper_Count; i++ ) {
  203. if( ! Conf_Oper[i].name[0] ) continue;
  204. /* Valid "Operator" section */
  205. puts( "[OPERATOR]" );
  206. printf( " Name = %s\n", Conf_Oper[i].name );
  207. printf( " Password = %s\n", Conf_Oper[i].pwd );
  208. if ( Conf_Oper[i].mask ) printf( " Mask = %s\n", Conf_Oper[i].mask );
  209. puts( "" );
  210. }
  211. for( i = 0; i < MAX_SERVERS; i++ ) {
  212. if( ! Conf_Server[i].name[0] ) continue;
  213. /* Valid "Server" section */
  214. puts( "[SERVER]" );
  215. printf( " Name = %s\n", Conf_Server[i].name );
  216. printf( " Host = %s\n", Conf_Server[i].host );
  217. printf( " Port = %u\n", (unsigned int)Conf_Server[i].port );
  218. printf( " MyPassword = %s\n", Conf_Server[i].pwd_in );
  219. printf( " PeerPassword = %s\n", Conf_Server[i].pwd_out );
  220. printf( " Group = %d\n", Conf_Server[i].group );
  221. printf( " Passive = %s\n\n", Conf_Server[i].flags & CONF_SFLAG_DISABLED ? "yes" : "no");
  222. }
  223. for( i = 0; i < Conf_Channel_Count; i++ ) {
  224. if( ! Conf_Channel[i].name[0] ) continue;
  225. /* Valid "Channel" section */
  226. puts( "[CHANNEL]" );
  227. printf( " Name = %s\n", Conf_Channel[i].name );
  228. printf( " Modes = %s\n", Conf_Channel[i].modes );
  229. printf( " Key = %s\n", Conf_Channel[i].key );
  230. printf( " MaxUsers = %lu\n", Conf_Channel[i].maxusers );
  231. topic = (char*)array_start(&Conf_Channel[i].topic);
  232. printf( " Topic = %s\n\n", topic ? topic : "");
  233. }
  234. return (config_valid ? 0 : 1);
  235. } /* Conf_Test */
  236. GLOBAL void
  237. Conf_UnsetServer( CONN_ID Idx )
  238. {
  239. /* Set next time for next connection attempt, if this is a server
  240. * link that is (still) configured here. If the server is set as
  241. * "once", delete it from our configuration.
  242. * Non-Server-Connections will be silently ignored. */
  243. int i;
  244. time_t t;
  245. /* Check all our configured servers */
  246. for( i = 0; i < MAX_SERVERS; i++ ) {
  247. if( Conf_Server[i].conn_id != Idx ) continue;
  248. /* Gotcha! Mark server configuration as "unused": */
  249. Conf_Server[i].conn_id = NONE;
  250. if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
  251. /* Delete configuration here */
  252. Init_Server_Struct( &Conf_Server[i] );
  253. } else {
  254. /* Set time for next connect attempt */
  255. t = time(NULL);
  256. if (Conf_Server[i].lasttry < t - Conf_ConnectRetry) {
  257. /* The connection has been "long", so we don't
  258. * require the next attempt to be delayed. */
  259. Conf_Server[i].lasttry =
  260. t - Conf_ConnectRetry + RECONNECT_DELAY;
  261. } else
  262. Conf_Server[i].lasttry = t;
  263. }
  264. }
  265. } /* Conf_UnsetServer */
  266. GLOBAL void
  267. Conf_SetServer( int ConfServer, CONN_ID Idx )
  268. {
  269. /* Set connection for specified configured server */
  270. assert( ConfServer > NONE );
  271. assert( Idx > NONE );
  272. Conf_Server[ConfServer].conn_id = Idx;
  273. } /* Conf_SetServer */
  274. GLOBAL int
  275. Conf_GetServer( CONN_ID Idx )
  276. {
  277. /* Get index of server in configuration structure */
  278. int i = 0;
  279. assert( Idx > NONE );
  280. for( i = 0; i < MAX_SERVERS; i++ ) {
  281. if( Conf_Server[i].conn_id == Idx ) return i;
  282. }
  283. return NONE;
  284. } /* Conf_GetServer */
  285. GLOBAL bool
  286. Conf_EnableServer( char *Name, UINT16 Port )
  287. {
  288. /* Enable specified server and adjust port */
  289. int i;
  290. assert( Name != NULL );
  291. for( i = 0; i < MAX_SERVERS; i++ ) {
  292. if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
  293. /* Gotcha! Set port and enable server: */
  294. Conf_Server[i].port = Port;
  295. Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
  296. return true;
  297. }
  298. }
  299. return false;
  300. } /* Conf_EnableServer */
  301. GLOBAL bool
  302. Conf_EnablePassiveServer(const char *Name)
  303. {
  304. /* Enable specified server */
  305. int i;
  306. assert( Name != NULL );
  307. for (i = 0; i < MAX_SERVERS; i++) {
  308. if ((strcasecmp( Conf_Server[i].name, Name ) == 0) && (Conf_Server[i].port > 0)) {
  309. /* BINGO! Enable server */
  310. Conf_Server[i].flags &= ~CONF_SFLAG_DISABLED;
  311. return true;
  312. }
  313. }
  314. return false;
  315. } /* Conf_EnablePassiveServer */
  316. GLOBAL bool
  317. Conf_DisableServer( char *Name )
  318. {
  319. /* Enable specified server and adjust port */
  320. int i;
  321. assert( Name != NULL );
  322. for( i = 0; i < MAX_SERVERS; i++ ) {
  323. if( strcasecmp( Conf_Server[i].name, Name ) == 0 ) {
  324. /* Gotcha! Disable and disconnect server: */
  325. Conf_Server[i].flags |= CONF_SFLAG_DISABLED;
  326. if( Conf_Server[i].conn_id > NONE ) Conn_Close( Conf_Server[i].conn_id, NULL, "Server link terminated on operator request", true);
  327. return true;
  328. }
  329. }
  330. return false;
  331. } /* Conf_DisableServer */
  332. GLOBAL bool
  333. Conf_AddServer( char *Name, UINT16 Port, char *Host, char *MyPwd, char *PeerPwd )
  334. {
  335. /* Add new server to configuration */
  336. int i;
  337. assert( Name != NULL );
  338. assert( Host != NULL );
  339. assert( MyPwd != NULL );
  340. assert( PeerPwd != NULL );
  341. /* Search unused item in server configuration structure */
  342. for( i = 0; i < MAX_SERVERS; i++ ) {
  343. /* Is this item used? */
  344. if( ! Conf_Server[i].name[0] ) break;
  345. }
  346. if( i >= MAX_SERVERS ) return false;
  347. Init_Server_Struct( &Conf_Server[i] );
  348. strlcpy( Conf_Server[i].name, Name, sizeof( Conf_Server[i].name ));
  349. strlcpy( Conf_Server[i].host, Host, sizeof( Conf_Server[i].host ));
  350. strlcpy( Conf_Server[i].pwd_out, MyPwd, sizeof( Conf_Server[i].pwd_out ));
  351. strlcpy( Conf_Server[i].pwd_in, PeerPwd, sizeof( Conf_Server[i].pwd_in ));
  352. Conf_Server[i].port = Port;
  353. Conf_Server[i].flags = CONF_SFLAG_ONCE;
  354. return true;
  355. } /* Conf_AddServer */
  356. static void
  357. Set_Defaults( bool InitServers )
  358. {
  359. /* Initialize configuration variables with default values. */
  360. int i;
  361. strcpy( Conf_ServerName, "" );
  362. snprintf( Conf_ServerInfo, sizeof Conf_ServerInfo, "%s %s", PACKAGE_NAME, PACKAGE_VERSION );
  363. strcpy( Conf_ServerPwd, "" );
  364. strcpy( Conf_ServerAdmin1, "" );
  365. strcpy( Conf_ServerAdmin2, "" );
  366. strcpy( Conf_ServerAdminMail, "" );
  367. strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile ));
  368. strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile ));
  369. strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase ));
  370. strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot ));
  371. strlcpy( Conf_PidFile, PID_FILE, sizeof( Conf_PidFile ));
  372. free(Conf_ListenAddress);
  373. Conf_ListenAddress = NULL;
  374. Conf_UID = Conf_GID = 0;
  375. Conf_PingTimeout = 120;
  376. Conf_PongTimeout = 20;
  377. Conf_ConnectRetry = 60;
  378. Conf_Oper_Count = 0;
  379. Conf_Channel_Count = 0;
  380. Conf_OperCanMode = false;
  381. Conf_NoDNS = false;
  382. Conf_PredefChannelsOnly = false;
  383. Conf_OperServerMode = false;
  384. Conf_ConnectIPv4 = true;
  385. Conf_ConnectIPv6 = true;
  386. #ifdef WANT_IPV6
  387. Conf_ListenIPv4 = true;
  388. Conf_ListenIPv6 = true;
  389. #endif
  390. Conf_MaxConnections = 0;
  391. Conf_MaxConnectionsIP = 5;
  392. Conf_MaxJoins = 10;
  393. Conf_MaxNickLength = CLIENT_NICK_LEN_DEFAULT;
  394. /* Initialize server configuration structures */
  395. if( InitServers ) for( i = 0; i < MAX_SERVERS; Init_Server_Struct( &Conf_Server[i++] ));
  396. } /* Set_Defaults */
  397. static bool
  398. Read_Config( bool ngircd_starting )
  399. {
  400. /* Read configuration file. */
  401. char section[LINE_LEN], str[LINE_LEN], *var, *arg, *ptr;
  402. const UINT16 defaultport = 6667;
  403. int line, i, n;
  404. FILE *fd;
  405. /* Open configuration file */
  406. fd = fopen( NGIRCd_ConfFile, "r" );
  407. if( ! fd ) {
  408. /* No configuration file found! */
  409. Config_Error( LOG_ALERT, "Can't read configuration \"%s\": %s",
  410. NGIRCd_ConfFile, strerror( errno ));
  411. if (!ngircd_starting)
  412. return false;
  413. Config_Error( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  414. exit( 1 );
  415. }
  416. Set_Defaults( ngircd_starting );
  417. Config_Error( LOG_INFO, "Reading configuration from \"%s\" ...", NGIRCd_ConfFile );
  418. /* Clean up server configuration structure: mark all already
  419. * configured servers as "once" so that they are deleted
  420. * after the next disconnect and delete all unused servers.
  421. * And delete all servers which are "duplicates" of servers
  422. * that are already marked as "once" (such servers have been
  423. * created by the last rehash but are now useless). */
  424. for( i = 0; i < MAX_SERVERS; i++ ) {
  425. if( Conf_Server[i].conn_id == NONE ) Init_Server_Struct( &Conf_Server[i] );
  426. else {
  427. /* This structure is in use ... */
  428. if( Conf_Server[i].flags & CONF_SFLAG_ONCE ) {
  429. /* Check for duplicates */
  430. for( n = 0; n < MAX_SERVERS; n++ ) {
  431. if( n == i ) continue;
  432. if( Conf_Server[i].conn_id == Conf_Server[n].conn_id ) {
  433. Init_Server_Struct( &Conf_Server[n] );
  434. #ifdef DEBUG
  435. Log(LOG_DEBUG,"Deleted unused duplicate server %d (kept %d).",
  436. n, i );
  437. #endif
  438. }
  439. }
  440. } else {
  441. /* Mark server as "once" */
  442. Conf_Server[i].flags |= CONF_SFLAG_ONCE;
  443. Log( LOG_DEBUG, "Marked server %d as \"once\"", i );
  444. }
  445. }
  446. }
  447. /* Initialize variables */
  448. line = 0;
  449. strcpy( section, "" );
  450. Init_Server_Struct( &New_Server );
  451. New_Server_Idx = NONE;
  452. /* Read configuration file */
  453. while( true ) {
  454. if( ! fgets( str, LINE_LEN, fd )) break;
  455. ngt_TrimStr( str );
  456. line++;
  457. /* Skip comments and empty lines */
  458. if( str[0] == ';' || str[0] == '#' || str[0] == '\0' ) continue;
  459. /* Is this the beginning of a new section? */
  460. if(( str[0] == '[' ) && ( str[strlen( str ) - 1] == ']' )) {
  461. strlcpy( section, str, sizeof( section ));
  462. if( strcasecmp( section, "[GLOBAL]" ) == 0 )
  463. continue;
  464. if( strcasecmp( section, "[OPERATOR]" ) == 0 ) {
  465. if( Conf_Oper_Count + 1 > MAX_OPERATORS )
  466. Config_Error( LOG_ERR, "Too many operators configured.");
  467. else {
  468. /* Initialize new operator structure */
  469. Conf_Oper[Conf_Oper_Count].name[0] = '\0';
  470. Conf_Oper[Conf_Oper_Count].pwd[0] = '\0';
  471. if (Conf_Oper[Conf_Oper_Count].mask) {
  472. free(Conf_Oper[Conf_Oper_Count].mask );
  473. Conf_Oper[Conf_Oper_Count].mask = NULL;
  474. }
  475. Conf_Oper_Count++;
  476. }
  477. continue;
  478. }
  479. if( strcasecmp( section, "[SERVER]" ) == 0 ) {
  480. /* Check if there is already a server to add */
  481. if( New_Server.name[0] ) {
  482. /* Copy data to "real" server structure */
  483. assert( New_Server_Idx > NONE );
  484. Conf_Server[New_Server_Idx] = New_Server;
  485. }
  486. /* Re-init structure for new server */
  487. Init_Server_Struct( &New_Server );
  488. /* Search unused item in server configuration structure */
  489. for( i = 0; i < MAX_SERVERS; i++ ) {
  490. /* Is this item used? */
  491. if( ! Conf_Server[i].name[0] ) break;
  492. }
  493. if( i >= MAX_SERVERS ) {
  494. /* Oops, no free item found! */
  495. Config_Error( LOG_ERR, "Too many servers configured." );
  496. New_Server_Idx = NONE;
  497. }
  498. else New_Server_Idx = i;
  499. continue;
  500. }
  501. if( strcasecmp( section, "[CHANNEL]" ) == 0 ) {
  502. if( Conf_Channel_Count + 1 > MAX_DEFCHANNELS ) {
  503. Config_Error( LOG_ERR, "Too many pre-defined channels configured." );
  504. } else {
  505. /* Initialize new channel structure */
  506. strcpy( Conf_Channel[Conf_Channel_Count].name, "" );
  507. strcpy( Conf_Channel[Conf_Channel_Count].modes, "" );
  508. strcpy( Conf_Channel[Conf_Channel_Count].key, "" );
  509. Conf_Channel[Conf_Channel_Count].maxusers = 0;
  510. array_free(&Conf_Channel[Conf_Channel_Count].topic);
  511. Conf_Channel_Count++;
  512. }
  513. continue;
  514. }
  515. Config_Error( LOG_ERR, "%s, line %d: Unknown section \"%s\"!", NGIRCd_ConfFile, line, section );
  516. section[0] = 0x1;
  517. }
  518. if( section[0] == 0x1 ) continue;
  519. /* Split line into variable name and parameters */
  520. ptr = strchr( str, '=' );
  521. if( ! ptr ) {
  522. Config_Error( LOG_ERR, "%s, line %d: Syntax error!", NGIRCd_ConfFile, line );
  523. continue;
  524. }
  525. *ptr = '\0';
  526. var = str; ngt_TrimStr( var );
  527. arg = ptr + 1; ngt_TrimStr( arg );
  528. if( strcasecmp( section, "[GLOBAL]" ) == 0 ) Handle_GLOBAL( line, var, arg );
  529. else if( strcasecmp( section, "[OPERATOR]" ) == 0 ) Handle_OPERATOR( line, var, arg );
  530. else if( strcasecmp( section, "[SERVER]" ) == 0 ) Handle_SERVER( line, var, arg );
  531. else if( strcasecmp( section, "[CHANNEL]" ) == 0 ) Handle_CHANNEL( line, var, arg );
  532. else Config_Error( LOG_ERR, "%s, line %d: Variable \"%s\" outside section!", NGIRCd_ConfFile, line, var );
  533. }
  534. /* Close configuration file */
  535. fclose( fd );
  536. /* Check if there is still a server to add */
  537. if( New_Server.name[0] ) {
  538. /* Copy data to "real" server structure */
  539. assert( New_Server_Idx > NONE );
  540. Conf_Server[New_Server_Idx] = New_Server;
  541. }
  542. if (0 == array_length(&Conf_ListenPorts, sizeof(UINT16))) {
  543. if (!array_copyb(&Conf_ListenPorts, (char*) &defaultport, sizeof defaultport)) {
  544. Config_Error( LOG_ALERT, "Could not add default listening Port %u: %s",
  545. (unsigned int) defaultport, strerror(errno));
  546. exit( 1 );
  547. }
  548. }
  549. if (!Conf_ListenAddress) {
  550. /* no Listen addresses configured, use default */
  551. #ifdef WANT_IPV6
  552. /* Conf_ListenIPv6/4 should no longer be used */
  553. if (Conf_ListenIPv6 && Conf_ListenIPv4)
  554. Conf_ListenAddress = strdup_warn("::,0.0.0.0");
  555. else if (Conf_ListenIPv6)
  556. Conf_ListenAddress = strdup_warn("::");
  557. else
  558. #endif
  559. Conf_ListenAddress = strdup_warn("0.0.0.0");
  560. }
  561. if (!Conf_ListenAddress) {
  562. Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
  563. exit(1);
  564. }
  565. return true;
  566. } /* Read_Config */
  567. static bool
  568. Check_ArgIsTrue( const char *Arg )
  569. {
  570. if( strcasecmp( Arg, "yes" ) == 0 ) return true;
  571. if( strcasecmp( Arg, "true" ) == 0 ) return true;
  572. if( atoi( Arg ) != 0 ) return true;
  573. return false;
  574. } /* Check_ArgIsTrue */
  575. static unsigned int Handle_MaxNickLength(int Line, const char *Arg)
  576. {
  577. unsigned new;
  578. new = (unsigned) atoi(Arg) + 1;
  579. if (new > CLIENT_NICK_LEN) {
  580. Config_Error(LOG_WARNING,
  581. "%s, line %d: Value of \"MaxNickLength\" exceeds %u!",
  582. NGIRCd_ConfFile, Line, CLIENT_NICK_LEN - 1);
  583. return CLIENT_NICK_LEN;
  584. }
  585. if (new < 2) {
  586. Config_Error(LOG_WARNING,
  587. "%s, line %d: Value of \"MaxNickLength\" must be at least 1!",
  588. NGIRCd_ConfFile, Line);
  589. return 2;
  590. }
  591. return new;
  592. } /* Handle_MaxNickLength */
  593. static void
  594. Handle_GLOBAL( int Line, char *Var, char *Arg )
  595. {
  596. struct passwd *pwd;
  597. struct group *grp;
  598. size_t len;
  599. assert( Line > 0 );
  600. assert( Var != NULL );
  601. assert( Arg != NULL );
  602. if( strcasecmp( Var, "Name" ) == 0 ) {
  603. /* Server name */
  604. len = strlcpy( Conf_ServerName, Arg, sizeof( Conf_ServerName ));
  605. if (len >= sizeof( Conf_ServerName ))
  606. Config_Error_TooLong( Line, Var );
  607. return;
  608. }
  609. if( strcasecmp( Var, "Info" ) == 0 ) {
  610. /* Info text of server */
  611. len = strlcpy( Conf_ServerInfo, Arg, sizeof( Conf_ServerInfo ));
  612. if (len >= sizeof( Conf_ServerInfo ))
  613. Config_Error_TooLong ( Line, Var );
  614. return;
  615. }
  616. if( strcasecmp( Var, "Password" ) == 0 ) {
  617. /* Global server password */
  618. len = strlcpy( Conf_ServerPwd, Arg, sizeof( Conf_ServerPwd ));
  619. if (len >= sizeof( Conf_ServerPwd ))
  620. Config_Error_TooLong( Line, Var );
  621. return;
  622. }
  623. if( strcasecmp( Var, "AdminInfo1" ) == 0 ) {
  624. /* Administrative info #1 */
  625. len = strlcpy( Conf_ServerAdmin1, Arg, sizeof( Conf_ServerAdmin1 ));
  626. if (len >= sizeof( Conf_ServerAdmin1 ))
  627. Config_Error_TooLong ( Line, Var );
  628. return;
  629. }
  630. if( strcasecmp( Var, "AdminInfo2" ) == 0 ) {
  631. /* Administrative info #2 */
  632. len = strlcpy( Conf_ServerAdmin2, Arg, sizeof( Conf_ServerAdmin2 ));
  633. if (len >= sizeof( Conf_ServerAdmin2 ))
  634. Config_Error_TooLong ( Line, Var );
  635. return;
  636. }
  637. if( strcasecmp( Var, "AdminEMail" ) == 0 ) {
  638. /* Administrative email contact */
  639. len = strlcpy( Conf_ServerAdminMail, Arg, sizeof( Conf_ServerAdminMail ));
  640. if (len >= sizeof( Conf_ServerAdminMail ))
  641. Config_Error_TooLong( Line, Var );
  642. return;
  643. }
  644. if( strcasecmp( Var, "Ports" ) == 0 ) {
  645. ports_parse(&Conf_ListenPorts, Line, Arg);
  646. return;
  647. }
  648. if( strcasecmp( Var, "MotdFile" ) == 0 ) {
  649. /* "Message of the day" (MOTD) file */
  650. len = strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile ));
  651. if (len >= sizeof( Conf_MotdFile ))
  652. Config_Error_TooLong( Line, Var );
  653. return;
  654. }
  655. if( strcasecmp( Var, "MotdPhrase" ) == 0 ) {
  656. /* "Message of the day" phrase (instead of file) */
  657. len = strlcpy( Conf_MotdPhrase, Arg, sizeof( Conf_MotdPhrase ));
  658. if (len >= sizeof( Conf_MotdPhrase ))
  659. Config_Error_TooLong( Line, Var );
  660. return;
  661. }
  662. if( strcasecmp( Var, "ChrootDir" ) == 0 ) {
  663. /* directory for chroot() */
  664. len = strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot ));
  665. if (len >= sizeof( Conf_Chroot ))
  666. Config_Error_TooLong( Line, Var );
  667. return;
  668. }
  669. if ( strcasecmp( Var, "PidFile" ) == 0 ) {
  670. /* name of pidfile */
  671. len = strlcpy( Conf_PidFile, Arg, sizeof( Conf_PidFile ));
  672. if (len >= sizeof( Conf_PidFile ))
  673. Config_Error_TooLong( Line, Var );
  674. return;
  675. }
  676. if( strcasecmp( Var, "ServerUID" ) == 0 ) {
  677. /* UID the daemon should switch to */
  678. pwd = getpwnam( Arg );
  679. if( pwd ) Conf_UID = pwd->pw_uid;
  680. else {
  681. #ifdef HAVE_ISDIGIT
  682. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  683. else
  684. #endif
  685. Conf_UID = (unsigned int)atoi( Arg );
  686. }
  687. return;
  688. }
  689. if( strcasecmp( Var, "ServerGID" ) == 0 ) {
  690. /* GID the daemon should use */
  691. grp = getgrnam( Arg );
  692. if( grp ) Conf_GID = grp->gr_gid;
  693. else {
  694. #ifdef HAVE_ISDIGIT
  695. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  696. else
  697. #endif
  698. Conf_GID = (unsigned int)atoi( Arg );
  699. }
  700. return;
  701. }
  702. if( strcasecmp( Var, "PingTimeout" ) == 0 ) {
  703. /* PING timeout */
  704. Conf_PingTimeout = atoi( Arg );
  705. if( Conf_PingTimeout < 5 ) {
  706. Config_Error( LOG_WARNING, "%s, line %d: Value of \"PingTimeout\" too low!",
  707. NGIRCd_ConfFile, Line );
  708. Conf_PingTimeout = 5;
  709. }
  710. return;
  711. }
  712. if( strcasecmp( Var, "PongTimeout" ) == 0 ) {
  713. /* PONG timeout */
  714. Conf_PongTimeout = atoi( Arg );
  715. if( Conf_PongTimeout < 5 ) {
  716. Config_Error( LOG_WARNING, "%s, line %d: Value of \"PongTimeout\" too low!",
  717. NGIRCd_ConfFile, Line );
  718. Conf_PongTimeout = 5;
  719. }
  720. return;
  721. }
  722. if( strcasecmp( Var, "ConnectRetry" ) == 0 ) {
  723. /* Seconds between connection attempts to other servers */
  724. Conf_ConnectRetry = atoi( Arg );
  725. if( Conf_ConnectRetry < 5 ) {
  726. Config_Error( LOG_WARNING, "%s, line %d: Value of \"ConnectRetry\" too low!",
  727. NGIRCd_ConfFile, Line );
  728. Conf_ConnectRetry = 5;
  729. }
  730. return;
  731. }
  732. if( strcasecmp( Var, "PredefChannelsOnly" ) == 0 ) {
  733. /* Should we only allow pre-defined-channels? (i.e. users cannot create their own channels) */
  734. Conf_PredefChannelsOnly = Check_ArgIsTrue( Arg );
  735. return;
  736. }
  737. if( strcasecmp( Var, "NoDNS" ) == 0 ) {
  738. /* don't do reverse dns lookups when clients connect? */
  739. Conf_NoDNS = Check_ArgIsTrue( Arg );
  740. return;
  741. }
  742. #ifdef WANT_IPV6
  743. /* the default setting for all the WANT_IPV6 special options is 'true' */
  744. if (strcasecmp(Var, "ListenIPv6") == 0) { /* DEPRECATED, option appeared in 0.12.0 */
  745. /*
  746. * listen on ipv6 sockets, if available?
  747. * Deprecated use "Listen = 0.0.0.0" (or, rather, do not list "::")
  748. */
  749. Conf_ListenIPv6 = Check_ArgIsTrue( Arg );
  750. Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '::' in \"Listen =\" option instead",
  751. NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv6), Conf_ListenIPv6 ? " ":"do not ");
  752. return;
  753. }
  754. if (strcasecmp(Var, "ListenIPv4") == 0) { /* DEPRECATED, option appeared in 0.12.0 */
  755. /*
  756. * listen on ipv4 sockets, if available?
  757. * this allows "ipv6-only" setups
  758. * Deprecated use "Listen = ::" (or, rather, do not list "0.0.0.0")
  759. */
  760. Conf_ListenIPv4 = Check_ArgIsTrue( Arg );
  761. Config_Error(LOG_WARNING, "%s, line %d: %s=%s is deprecated, %sinclude '0.0.0.0' in \"Listen =\" option instead",
  762. NGIRCd_ConfFile, Line, Var, yesno_to_str(Conf_ListenIPv4), Conf_ListenIPv4 ? " ":"do not ");
  763. return;
  764. }
  765. if( strcasecmp( Var, "ConnectIPv6" ) == 0 ) {
  766. /* connect to other hosts using ipv6, if they have an AAAA record? */
  767. Conf_ConnectIPv6 = Check_ArgIsTrue( Arg );
  768. return;
  769. }
  770. if( strcasecmp( Var, "ConnectIPv4" ) == 0 ) {
  771. /* connect to other hosts using ipv4.
  772. * again, this can be used for ipv6-only setups */
  773. Conf_ConnectIPv4 = Check_ArgIsTrue( Arg );
  774. return;
  775. }
  776. #endif
  777. if( strcasecmp( Var, "OperCanUseMode" ) == 0 ) {
  778. /* Are IRC operators allowed to use MODE in channels they aren't Op in? */
  779. Conf_OperCanMode = Check_ArgIsTrue( Arg );
  780. return;
  781. }
  782. if( strcasecmp( Var, "OperServerMode" ) == 0 ) {
  783. /* Mask IRC operator as if coming from the server? (ircd-irc2 compat hack) */
  784. Conf_OperServerMode = Check_ArgIsTrue( Arg );
  785. return;
  786. }
  787. if( strcasecmp( Var, "MaxConnections" ) == 0 ) {
  788. /* Maximum number of connections. 0 -> "no limit". */
  789. #ifdef HAVE_ISDIGIT
  790. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var);
  791. else
  792. #endif
  793. Conf_MaxConnections = atol( Arg );
  794. return;
  795. }
  796. if( strcasecmp( Var, "MaxConnectionsIP" ) == 0 ) {
  797. /* Maximum number of simultaneous connections from one IP. 0 -> "no limit" */
  798. #ifdef HAVE_ISDIGIT
  799. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  800. else
  801. #endif
  802. Conf_MaxConnectionsIP = atoi( Arg );
  803. return;
  804. }
  805. if( strcasecmp( Var, "MaxJoins" ) == 0 ) {
  806. /* Maximum number of channels a user can join. 0 -> "no limit". */
  807. #ifdef HAVE_ISDIGIT
  808. if( ! isdigit( (int)*Arg )) Config_Error_NaN( Line, Var );
  809. else
  810. #endif
  811. Conf_MaxJoins = atoi( Arg );
  812. return;
  813. }
  814. if( strcasecmp( Var, "MaxNickLength" ) == 0 ) {
  815. /* Maximum length of a nick name; must be same on all servers
  816. * within the IRC network! */
  817. Conf_MaxNickLength = Handle_MaxNickLength(Line, Arg);
  818. return;
  819. }
  820. if( strcasecmp( Var, "Listen" ) == 0 ) {
  821. /* IP-Address to bind sockets */
  822. if (Conf_ListenAddress) {
  823. Config_Error(LOG_ERR, "Multiple Listen= options, ignoring: %s", Arg);
  824. return;
  825. }
  826. Conf_ListenAddress = strdup_warn(Arg);
  827. /*
  828. * if allocation fails, we're in trouble:
  829. * we cannot ignore the error -- otherwise ngircd
  830. * would listen on all interfaces.
  831. */
  832. if (!Conf_ListenAddress) {
  833. Config_Error(LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME);
  834. exit(1);
  835. }
  836. return;
  837. }
  838. Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
  839. NGIRCd_ConfFile, Line, Var);
  840. } /* Handle_GLOBAL */
  841. static void
  842. Handle_OPERATOR( int Line, char *Var, char *Arg )
  843. {
  844. unsigned int opercount;
  845. size_t len;
  846. assert( Line > 0 );
  847. assert( Var != NULL );
  848. assert( Arg != NULL );
  849. assert( Conf_Oper_Count > 0 );
  850. if ( Conf_Oper_Count == 0 )
  851. return;
  852. opercount = Conf_Oper_Count - 1;
  853. if( strcasecmp( Var, "Name" ) == 0 ) {
  854. /* Name of IRC operator */
  855. len = strlcpy( Conf_Oper[opercount].name, Arg, sizeof( Conf_Oper[opercount].name ));
  856. if (len >= sizeof( Conf_Oper[opercount].name ))
  857. Config_Error_TooLong( Line, Var );
  858. return;
  859. }
  860. if( strcasecmp( Var, "Password" ) == 0 ) {
  861. /* Password of IRC operator */
  862. len = strlcpy( Conf_Oper[opercount].pwd, Arg, sizeof( Conf_Oper[opercount].pwd ));
  863. if (len >= sizeof( Conf_Oper[opercount].pwd ))
  864. Config_Error_TooLong( Line, Var );
  865. return;
  866. }
  867. if( strcasecmp( Var, "Mask" ) == 0 ) {
  868. if (Conf_Oper[opercount].mask) return; /* Hostname already configured */
  869. Conf_Oper[opercount].mask = strdup_warn( Arg );
  870. return;
  871. }
  872. Config_Error( LOG_ERR, "%s, line %d (section \"Operator\"): Unknown variable \"%s\"!",
  873. NGIRCd_ConfFile, Line, Var );
  874. } /* Handle_OPERATOR */
  875. static void
  876. Handle_SERVER( int Line, char *Var, char *Arg )
  877. {
  878. long port;
  879. size_t len;
  880. assert( Line > 0 );
  881. assert( Var != NULL );
  882. assert( Arg != NULL );
  883. /* Ignore server block if no space is left in server configuration structure */
  884. if( New_Server_Idx <= NONE ) return;
  885. if( strcasecmp( Var, "Host" ) == 0 ) {
  886. /* Hostname of the server */
  887. len = strlcpy( New_Server.host, Arg, sizeof( New_Server.host ));
  888. if (len >= sizeof( New_Server.host ))
  889. Config_Error_TooLong ( Line, Var );
  890. return;
  891. }
  892. if( strcasecmp( Var, "Name" ) == 0 ) {
  893. /* Name of the server ("Nick"/"ID") */
  894. len = strlcpy( New_Server.name, Arg, sizeof( New_Server.name ));
  895. if (len >= sizeof( New_Server.name ))
  896. Config_Error_TooLong( Line, Var );
  897. return;
  898. }
  899. if (strcasecmp(Var, "Bind") == 0) {
  900. if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
  901. return;
  902. Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
  903. NGIRCd_ConfFile, Line, Arg);
  904. return;
  905. }
  906. if( strcasecmp( Var, "MyPassword" ) == 0 ) {
  907. /* Password of this server which is sent to the peer */
  908. if (*Arg == ':') {
  909. Config_Error(LOG_ERR,
  910. "%s, line %d (section \"Server\"): MyPassword must not start with ':'!",
  911. NGIRCd_ConfFile, Line);
  912. }
  913. len = strlcpy( New_Server.pwd_in, Arg, sizeof( New_Server.pwd_in ));
  914. if (len >= sizeof( New_Server.pwd_in ))
  915. Config_Error_TooLong( Line, Var );
  916. return;
  917. }
  918. if( strcasecmp( Var, "PeerPassword" ) == 0 ) {
  919. /* Passwort of the peer which must be received */
  920. len = strlcpy( New_Server.pwd_out, Arg, sizeof( New_Server.pwd_out ));
  921. if (len >= sizeof( New_Server.pwd_out ))
  922. Config_Error_TooLong( Line, Var );
  923. return;
  924. }
  925. if( strcasecmp( Var, "Port" ) == 0 ) {
  926. /* Port to which this server should connect */
  927. port = atol( Arg );
  928. if( port > 0 && port < 0xFFFF )
  929. New_Server.port = (UINT16)port;
  930. else
  931. Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Illegal port number %ld!",
  932. NGIRCd_ConfFile, Line, port );
  933. return;
  934. }
  935. if( strcasecmp( Var, "Group" ) == 0 ) {
  936. /* Server group */
  937. #ifdef HAVE_ISDIGIT
  938. if( ! isdigit( (int)*Arg ))
  939. Config_Error_NaN( Line, Var );
  940. else
  941. #endif
  942. New_Server.group = atoi( Arg );
  943. return;
  944. }
  945. if( strcasecmp( Var, "Passive" ) == 0 ) {
  946. if (Check_ArgIsTrue(Arg))
  947. New_Server.flags |= CONF_SFLAG_DISABLED;
  948. return;
  949. }
  950. Config_Error( LOG_ERR, "%s, line %d (section \"Server\"): Unknown variable \"%s\"!",
  951. NGIRCd_ConfFile, Line, Var );
  952. } /* Handle_SERVER */
  953. static bool
  954. Handle_Channelname(size_t chancount, const char *name)
  955. {
  956. size_t size = sizeof( Conf_Channel[chancount].name );
  957. char *dest = Conf_Channel[chancount].name;
  958. if (*name && *name != '#') {
  959. *dest = '#';
  960. --size;
  961. ++dest;
  962. }
  963. return size > strlcpy(dest, name, size);
  964. }
  965. static void
  966. Handle_CHANNEL( int Line, char *Var, char *Arg )
  967. {
  968. size_t len;
  969. size_t chancount = 0;
  970. assert( Line > 0 );
  971. assert( Var != NULL );
  972. assert( Arg != NULL );
  973. if (Conf_Channel_Count > 0)
  974. chancount = Conf_Channel_Count - 1;
  975. if( strcasecmp( Var, "Name" ) == 0 ) {
  976. if (!Handle_Channelname(chancount, Arg))
  977. Config_Error_TooLong( Line, Var );
  978. return;
  979. }
  980. if( strcasecmp( Var, "Modes" ) == 0 ) {
  981. /* Initial modes */
  982. len = strlcpy( Conf_Channel[chancount].modes, Arg, sizeof( Conf_Channel[chancount].modes ));
  983. if (len >= sizeof( Conf_Channel[chancount].modes ))
  984. Config_Error_TooLong( Line, Var );
  985. return;
  986. }
  987. if( strcasecmp( Var, "Topic" ) == 0 ) {
  988. /* Initial topic */
  989. if (!array_copys( &Conf_Channel[chancount].topic, Arg))
  990. Config_Error_TooLong( Line, Var );
  991. return;
  992. }
  993. if( strcasecmp( Var, "Key" ) == 0 ) {
  994. /* Initial Channel Key (mode k) */
  995. len = strlcpy(Conf_Channel[chancount].key, Arg, sizeof(Conf_Channel[chancount].key));
  996. if (len >= sizeof( Conf_Channel[chancount].key ))
  997. Config_Error_TooLong(Line, Var);
  998. return;
  999. }
  1000. if( strcasecmp( Var, "MaxUsers" ) == 0 ) {
  1001. /* maximum user limit, mode l */
  1002. Conf_Channel[chancount].maxusers = (unsigned long) atol(Arg);
  1003. if (Conf_Channel[chancount].maxusers == 0)
  1004. Config_Error_NaN(Line, Var);
  1005. return;
  1006. }
  1007. Config_Error( LOG_ERR, "%s, line %d (section \"Channel\"): Unknown variable \"%s\"!",
  1008. NGIRCd_ConfFile, Line, Var );
  1009. } /* Handle_CHANNEL */
  1010. static bool
  1011. Validate_Config(bool Configtest, bool Rehash)
  1012. {
  1013. /* Validate configuration settings. */
  1014. #ifdef DEBUG
  1015. int i, servers, servers_once;
  1016. #endif
  1017. bool config_valid = true;
  1018. char *ptr;
  1019. /* Validate configured server name, see RFC 2812 section 2.3.1 */
  1020. ptr = Conf_ServerName;
  1021. do {
  1022. if (*ptr >= 'a' && *ptr <= 'z') continue;
  1023. if (*ptr >= 'A' && *ptr <= 'Z') continue;
  1024. if (*ptr >= '0' && *ptr <= '9') continue;
  1025. if (ptr > Conf_ServerName) {
  1026. if (*ptr == '.' || *ptr == '-')
  1027. continue;
  1028. }
  1029. Conf_ServerName[0] = '\0';
  1030. break;
  1031. } while (*(++ptr));
  1032. if (!Conf_ServerName[0]) {
  1033. /* No server name configured! */
  1034. config_valid = false;
  1035. Config_Error(LOG_ALERT,
  1036. "No (valid) server name configured in \"%s\" (section 'Global': 'Name')!",
  1037. NGIRCd_ConfFile);
  1038. if (!Configtest && !Rehash) {
  1039. Config_Error(LOG_ALERT,
  1040. "%s exiting due to fatal errors!",
  1041. PACKAGE_NAME);
  1042. exit(1);
  1043. }
  1044. }
  1045. if (Conf_ServerName[0] && !strchr(Conf_ServerName, '.')) {
  1046. /* No dot in server name! */
  1047. config_valid = false;
  1048. Config_Error(LOG_ALERT,
  1049. "Invalid server name configured in \"%s\" (section 'Global': 'Name'): Dot missing!",
  1050. NGIRCd_ConfFile);
  1051. if (!Configtest) {
  1052. Config_Error(LOG_ALERT,
  1053. "%s exiting due to fatal errors!",
  1054. PACKAGE_NAME);
  1055. exit(1);
  1056. }
  1057. }
  1058. #ifdef STRICT_RFC
  1059. if (!Conf_ServerAdminMail[0]) {
  1060. /* No administrative contact configured! */
  1061. config_valid = false;
  1062. Config_Error(LOG_ALERT,
  1063. "No administrator email address configured in \"%s\" ('AdminEMail')!",
  1064. NGIRCd_ConfFile);
  1065. if (!Configtest) {
  1066. Config_Error(LOG_ALERT,
  1067. "%s exiting due to fatal errors!",
  1068. PACKAGE_NAME);
  1069. exit(1);
  1070. }
  1071. }
  1072. #endif
  1073. if (!Conf_ServerAdmin1[0] && !Conf_ServerAdmin2[0]
  1074. && !Conf_ServerAdminMail[0]) {
  1075. /* No administrative information configured! */
  1076. Config_Error(LOG_WARNING,
  1077. "No administrative information configured but required by RFC!");
  1078. }
  1079. #ifdef DEBUG
  1080. servers = servers_once = 0;
  1081. for (i = 0; i < MAX_SERVERS; i++) {
  1082. if (Conf_Server[i].name[0]) {
  1083. servers++;
  1084. if (Conf_Server[i].flags & CONF_SFLAG_ONCE)
  1085. servers_once++;
  1086. }
  1087. }
  1088. Log(LOG_DEBUG,
  1089. "Configuration: Operators=%d, Servers=%d[%d], Channels=%d",
  1090. Conf_Oper_Count, servers, servers_once, Conf_Channel_Count);
  1091. #endif
  1092. return config_valid;
  1093. } /* Validate_Config */
  1094. static void
  1095. Config_Error_TooLong ( const int Line, const char *Item )
  1096. {
  1097. Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" too long!", NGIRCd_ConfFile, Line, Item );
  1098. }
  1099. static void
  1100. Config_Error_NaN( const int Line, const char *Item )
  1101. {
  1102. Config_Error( LOG_WARNING, "%s, line %d: Value of \"%s\" is not a number!",
  1103. NGIRCd_ConfFile, Line, Item );
  1104. }
  1105. #ifdef PROTOTYPES
  1106. static void Config_Error( const int Level, const char *Format, ... )
  1107. #else
  1108. static void Config_Error( Level, Format, va_alist )
  1109. const int Level;
  1110. const char *Format;
  1111. va_dcl
  1112. #endif
  1113. {
  1114. /* Error! Write to console and/or logfile. */
  1115. char msg[MAX_LOG_MSG_LEN];
  1116. va_list ap;
  1117. assert( Format != NULL );
  1118. #ifdef PROTOTYPES
  1119. va_start( ap, Format );
  1120. #else
  1121. va_start( ap );
  1122. #endif
  1123. vsnprintf( msg, MAX_LOG_MSG_LEN, Format, ap );
  1124. va_end( ap );
  1125. /* During "normal operations" the log functions of the daemon should
  1126. * be used, but during testing of the configuration file, all messages
  1127. * should go directly to the console: */
  1128. if (Use_Log) Log( Level, "%s", msg );
  1129. else puts( msg );
  1130. } /* Config_Error */
  1131. static void
  1132. Init_Server_Struct( CONF_SERVER *Server )
  1133. {
  1134. /* Initialize server configuration structur to default values */
  1135. assert( Server != NULL );
  1136. memset( Server, 0, sizeof (CONF_SERVER) );
  1137. Server->group = NONE;
  1138. Server->lasttry = time( NULL ) - Conf_ConnectRetry + STARTUP_DELAY;
  1139. if( NGIRCd_Passive ) Server->flags = CONF_SFLAG_DISABLED;
  1140. Resolve_Init(&Server->res_stat);
  1141. Server->conn_id = NONE;
  1142. memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
  1143. } /* Init_Server_Struct */
  1144. /* -eof- */