conf.c 53 KB

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