irc-mode.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2014 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. * IRC commands for mode changes (like MODE, AWAY, etc.)
  15. */
  16. #include <assert.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "conn.h"
  21. #include "channel.h"
  22. #include "irc-macros.h"
  23. #include "irc-write.h"
  24. #include "lists.h"
  25. #include "log.h"
  26. #include "parse.h"
  27. #include "messages.h"
  28. #include "conf.h"
  29. #include "irc-mode.h"
  30. static bool Client_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  31. CLIENT *Target));
  32. static bool Channel_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
  33. CHANNEL *Channel));
  34. static bool Add_To_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
  35. CHANNEL *Channel, const char *Pattern));
  36. static bool Del_From_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
  37. CHANNEL *Channel, const char *Pattern));
  38. static bool Send_ListChange PARAMS((const bool IsAdd, const char ModeChar,
  39. CLIENT *Prefix, CLIENT *Client,
  40. CHANNEL *Channel, const char *Mask));
  41. /**
  42. * Handler for the IRC "MODE" command.
  43. *
  44. * This function detects whether user or channel modes should be modified
  45. * and calls the appropriate sub-functions.
  46. *
  47. * @param Client The client from which this command has been received.
  48. * @param Req Request structure with prefix and all parameters.
  49. * @return CONNECTED or DISCONNECTED.
  50. */
  51. GLOBAL bool
  52. IRC_MODE( CLIENT *Client, REQUEST *Req )
  53. {
  54. CLIENT *cl, *origin;
  55. CHANNEL *chan;
  56. assert(Client != NULL);
  57. assert(Req != NULL);
  58. _IRC_GET_SENDER_OR_RETURN_(origin, Req, Client)
  59. /* Test for "fake" MODE commands injected by this local instance,
  60. * for example when handling the "DefaultUserModes" settings.
  61. * This doesn't harm real commands, because prefixes of regular
  62. * clients are checked in Validate_Prefix() and can't be faked. */
  63. if (Req->prefix && Client_Search(Req->prefix) == Client_ThisServer())
  64. Client = Client_Search(Req->prefix);
  65. /* Channel or user mode? */
  66. cl = NULL; chan = NULL;
  67. if (Client_IsValidNick(Req->argv[0]))
  68. cl = Client_Search(Req->argv[0]);
  69. if (Channel_IsValidName(Req->argv[0]))
  70. chan = Channel_Search(Req->argv[0]);
  71. if (cl)
  72. return Client_Mode(Client, Req, origin, cl);
  73. if (chan)
  74. return Channel_Mode(Client, Req, origin, chan);
  75. /* No target found! */
  76. return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
  77. Client_ID(Client), Req->argv[0]);
  78. } /* IRC_MODE */
  79. /**
  80. * Check if the "mode limit" for a client has been reached.
  81. *
  82. * This limit doesn't apply for servers or services!
  83. *
  84. * @param Client The client to check.
  85. * @param Count The number of modes already handled.
  86. * @return true if the limit has been reached.
  87. */
  88. static bool
  89. Mode_Limit_Reached(CLIENT *Client, int Count)
  90. {
  91. if (Client_Type(Client) == CLIENT_SERVER
  92. || Client_Type(Client) == CLIENT_SERVICE)
  93. return false;
  94. if (Count < MAX_HNDL_MODES_ARG)
  95. return false;
  96. return true;
  97. }
  98. /**
  99. * Handle client mode requests
  100. *
  101. * @param Client The client from which this command has been received.
  102. * @param Req Request structure with prefix and all parameters.
  103. * @param Origin The originator of the MODE command (prefix).
  104. * @param Target The target (client) of this MODE command.
  105. * @return CONNECTED or DISCONNECTED.
  106. */
  107. static bool
  108. Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
  109. {
  110. char the_modes[COMMAND_LEN], x[2], *mode_ptr;
  111. bool ok, set;
  112. bool send_RPL_HOSTHIDDEN_MSG = false;
  113. int mode_arg;
  114. size_t len;
  115. /* Is the client allowed to request or change the modes? */
  116. if (Client_Type(Client) == CLIENT_USER) {
  117. /* Users are only allowed to manipulate their own modes! */
  118. if (Target != Client)
  119. return IRC_WriteErrClient(Client,
  120. ERR_USERSDONTMATCH_MSG,
  121. Client_ID(Client));
  122. }
  123. /* Mode request: let's answer it :-) */
  124. if (Req->argc == 1)
  125. return IRC_WriteStrClient(Origin, RPL_UMODEIS_MSG,
  126. Client_ID(Target),
  127. Client_Modes(Target));
  128. mode_arg = 1;
  129. mode_ptr = Req->argv[mode_arg];
  130. /* Initial state: set or unset modes? */
  131. if (*mode_ptr == '+') {
  132. set = true;
  133. strcpy(the_modes, "+");
  134. } else if (*mode_ptr == '-') {
  135. set = false;
  136. strcpy(the_modes, "-");
  137. } else
  138. return IRC_WriteErrClient(Origin, ERR_UMODEUNKNOWNFLAG_MSG,
  139. Client_ID(Origin));
  140. x[1] = '\0';
  141. ok = CONNECTED;
  142. while (mode_ptr) {
  143. mode_ptr++;
  144. if (!*mode_ptr) {
  145. /* Try next argument if there's any */
  146. mode_arg++;
  147. if (mode_arg < Req->argc)
  148. mode_ptr = Req->argv[mode_arg];
  149. else
  150. break;
  151. }
  152. switch(*mode_ptr) {
  153. case '+':
  154. case '-':
  155. if ((*mode_ptr == '+' && !set)
  156. || (*mode_ptr == '-' && set)) {
  157. /* Action modifier ("+"/"-") must be changed */
  158. len = strlen(the_modes) - 1;
  159. if (the_modes[len] == '+'
  160. || the_modes[len] == '-') {
  161. /* Last character in the "result
  162. * string" was an "action", so just
  163. * overwrite it with the new action */
  164. the_modes[len] = *mode_ptr;
  165. } else {
  166. /* Append new modifier character to
  167. * the resulting mode string */
  168. x[0] = *mode_ptr;
  169. strlcat(the_modes, x,
  170. sizeof(the_modes));
  171. }
  172. if (*mode_ptr == '+')
  173. set = true;
  174. else
  175. set = false;
  176. }
  177. continue;
  178. }
  179. /* Validate modes */
  180. x[0] = '\0';
  181. switch (*mode_ptr) {
  182. case 'b': /* Block private msgs */
  183. case 'C': /* Only messages from clients sharing a channel */
  184. case 'i': /* Invisible */
  185. case 'I': /* Hide channel list from WHOIS */
  186. case 's': /* Server messages */
  187. case 'w': /* Wallops messages */
  188. x[0] = *mode_ptr;
  189. break;
  190. case 'a': /* Away */
  191. if (Client_Type(Client) == CLIENT_SERVER) {
  192. x[0] = 'a';
  193. Client_SetAway(Origin, DEFAULT_AWAY_MSG);
  194. } else
  195. ok = IRC_WriteErrClient(Origin,
  196. ERR_NOPRIVILEGES_MSG,
  197. Client_ID(Origin));
  198. break;
  199. case 'B': /* Bot */
  200. if (Client_HasMode(Client, 'r'))
  201. ok = IRC_WriteErrClient(Origin,
  202. ERR_RESTRICTED_MSG,
  203. Client_ID(Origin));
  204. else
  205. x[0] = 'B';
  206. break;
  207. case 'c': /* Receive connect notices */
  208. case 'q': /* KICK-protected user */
  209. case 'F': /* disable flood protection */
  210. /* (only settable by IRC operators!) */
  211. if (!set || Client_Type(Client) == CLIENT_SERVER
  212. || Client_HasMode(Origin, 'o'))
  213. x[0] = *mode_ptr;
  214. else
  215. ok = IRC_WriteErrClient(Origin,
  216. ERR_NOPRIVILEGES_MSG,
  217. Client_ID(Origin));
  218. break;
  219. case 'o': /* IRC operator (only unsettable!) */
  220. if (!set || Client_Type(Client) == CLIENT_SERVER) {
  221. x[0] = 'o';
  222. } else
  223. ok = IRC_WriteErrClient(Origin,
  224. ERR_NOPRIVILEGES_MSG,
  225. Client_ID(Origin));
  226. break;
  227. case 'r': /* Restricted (only settable) */
  228. if (set || Client_Type(Client) == CLIENT_SERVER)
  229. x[0] = 'r';
  230. else
  231. ok = IRC_WriteErrClient(Origin,
  232. ERR_RESTRICTED_MSG,
  233. Client_ID(Origin));
  234. break;
  235. case 'R': /* Registered (not [un]settable by clients) */
  236. if (Client_Type(Client) == CLIENT_SERVER)
  237. x[0] = 'R';
  238. else
  239. ok = IRC_WriteErrClient(Origin,
  240. ERR_NICKREGISTER_MSG,
  241. Client_ID(Origin));
  242. break;
  243. case 'x': /* Cloak hostname */
  244. if (Client_HasMode(Client, 'r'))
  245. ok = IRC_WriteErrClient(Origin,
  246. ERR_RESTRICTED_MSG,
  247. Client_ID(Origin));
  248. else if (!set || Conf_CloakHostModeX[0]
  249. || Client_Type(Client) == CLIENT_SERVER
  250. || Client_HasMode(Origin, 'o')) {
  251. x[0] = 'x';
  252. send_RPL_HOSTHIDDEN_MSG = true;
  253. } else
  254. ok = IRC_WriteErrClient(Origin,
  255. ERR_NOPRIVILEGES_MSG,
  256. Client_ID(Origin));
  257. break;
  258. default:
  259. if (Client_Type(Client) != CLIENT_SERVER) {
  260. Log(LOG_DEBUG,
  261. "Unknown mode \"%c%c\" from \"%s\"!?",
  262. set ? '+' : '-', *mode_ptr,
  263. Client_ID(Origin));
  264. ok = IRC_WriteErrClient(Origin,
  265. ERR_UMODEUNKNOWNFLAG2_MSG,
  266. Client_ID(Origin),
  267. set ? '+' : '-',
  268. *mode_ptr);
  269. x[0] = '\0';
  270. } else {
  271. Log(LOG_DEBUG,
  272. "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
  273. set ? '+' : '-', *mode_ptr,
  274. Client_ID(Origin), Client_ID(Target));
  275. x[0] = *mode_ptr;
  276. }
  277. }
  278. if (!ok)
  279. break;
  280. /* Is there a valid mode change? */
  281. if (!x[0])
  282. continue;
  283. if (set) {
  284. if (Client_ModeAdd(Target, x[0]))
  285. strlcat(the_modes, x, sizeof(the_modes));
  286. } else {
  287. if (Client_ModeDel(Target, x[0]))
  288. strlcat(the_modes, x, sizeof(the_modes));
  289. }
  290. }
  291. /* Are there changed modes? */
  292. if (the_modes[1]) {
  293. /* Remove needless action modifier characters */
  294. len = strlen(the_modes) - 1;
  295. if (the_modes[len] == '+' || the_modes[len] == '-')
  296. the_modes[len] = '\0';
  297. if (Client_Type(Client) == CLIENT_SERVER) {
  298. /* Forward modes to other servers */
  299. if (Client_Conn(Target) != NONE) {
  300. /* Remote server (service?) changed modes
  301. * for one of our clients. Inform it! */
  302. IRC_WriteStrClientPrefix(Target, Origin,
  303. "MODE %s :%s",
  304. Client_ID(Target),
  305. the_modes);
  306. }
  307. IRC_WriteStrServersPrefix(Client, Origin,
  308. "MODE %s :%s",
  309. Client_ID(Target),
  310. the_modes);
  311. } else {
  312. /* Send reply to client and inform other servers */
  313. ok = IRC_WriteStrClientPrefix(Client, Origin,
  314. "MODE %s :%s",
  315. Client_ID(Target),
  316. the_modes);
  317. IRC_WriteStrServersPrefix(Client, Origin,
  318. "MODE %s :%s",
  319. Client_ID(Target),
  320. the_modes);
  321. }
  322. if (send_RPL_HOSTHIDDEN_MSG && Client_Conn(Target) > NONE) {
  323. /* A new (cloaked) hostname must be announced */
  324. IRC_WriteStrClientPrefix(Target, Origin,
  325. RPL_HOSTHIDDEN_MSG,
  326. Client_ID(Target),
  327. Client_HostnameDisplayed(Target));
  328. }
  329. LogDebug("%s \"%s\": Mode change, now \"%s\".",
  330. Client_TypeText(Target), Client_Mask(Target),
  331. Client_Modes(Target));
  332. }
  333. return ok;
  334. } /* Client_Mode */
  335. /*
  336. * Reply to a channel mode request.
  337. *
  338. * @param Origin The originator of the MODE command (prefix).
  339. * @param Channel The channel of which the modes should be sent.
  340. * @return CONNECTED or DISCONNECTED.
  341. */
  342. static bool
  343. Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
  344. {
  345. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
  346. const char *mode_ptr;
  347. if (!Channel_IsMemberOf(Channel, Origin)) {
  348. /* Not a member: "simple" mode reply */
  349. if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  350. Client_ID(Origin), Channel_Name(Channel),
  351. Channel_Modes(Channel)))
  352. return DISCONNECTED;
  353. } else {
  354. /* The sender is a member: generate extended reply */
  355. strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
  356. mode_ptr = the_modes;
  357. the_args[0] = '\0';
  358. while(*mode_ptr) {
  359. switch(*mode_ptr) {
  360. case 'l':
  361. snprintf(argadd, sizeof(argadd), " %lu",
  362. Channel_MaxUsers(Channel));
  363. strlcat(the_args, argadd, sizeof(the_args));
  364. break;
  365. case 'k':
  366. strlcat(the_args, " ", sizeof(the_args));
  367. strlcat(the_args, Channel_Key(Channel),
  368. sizeof(the_args));
  369. break;
  370. }
  371. mode_ptr++;
  372. }
  373. if (the_args[0])
  374. strlcat(the_modes, the_args, sizeof(the_modes));
  375. if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
  376. Client_ID(Origin), Channel_Name(Channel),
  377. the_modes))
  378. return DISCONNECTED;
  379. }
  380. #ifndef STRICT_RFC
  381. /* Channel creation time */
  382. if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
  383. Client_ID(Origin), Channel_Name(Channel),
  384. Channel_CreationTime(Channel)))
  385. return DISCONNECTED;
  386. #endif
  387. return CONNECTED;
  388. }
  389. /**
  390. * Handle channel mode and channel-user mode changes
  391. *
  392. * @param Client The client from which this command has been received.
  393. * @param Req Request structure with prefix and all parameters.
  394. * @param Origin The originator of the MODE command (prefix).
  395. * @param Channel The target channel of this MODE command.
  396. * @return CONNECTED or DISCONNECTED.
  397. */
  398. static bool
  399. Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
  400. {
  401. char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
  402. argadd[CLIENT_PASS_LEN], *mode_ptr;
  403. bool connected, set, skiponce, retval, use_servermode,
  404. is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
  405. int mode_arg, arg_arg, mode_arg_count = 0;
  406. CLIENT *client;
  407. long l;
  408. size_t len;
  409. is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
  410. if (Channel_IsModeless(Channel))
  411. return IRC_WriteErrClient(Client, ERR_NOCHANMODES_MSG,
  412. Client_ID(Client), Channel_Name(Channel));
  413. /* Mode request: let's answer it :-) */
  414. if (Req->argc <= 1)
  415. return Channel_Mode_Answer_Request(Origin, Channel);
  416. /* Check if origin is oper and opers can use mode */
  417. use_servermode = Conf_OperServerMode;
  418. if(Client_HasMode(Client, 'o') && Conf_OperCanMode) {
  419. is_oper = true;
  420. }
  421. /* Check if client is a server/service */
  422. if(Client_Type(Client) == CLIENT_SERVER ||
  423. Client_Type(Client) == CLIENT_SERVICE) {
  424. is_machine = true;
  425. }
  426. /* Check if client is member of channel or an oper or an server/service */
  427. if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
  428. return IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG,
  429. Client_ID(Origin),
  430. Channel_Name(Channel));
  431. mode_arg = 1;
  432. mode_ptr = Req->argv[mode_arg];
  433. if (Req->argc > mode_arg + 1)
  434. arg_arg = mode_arg + 1;
  435. else
  436. arg_arg = -1;
  437. /* Initial state: set or unset modes? */
  438. skiponce = false;
  439. switch (*mode_ptr) {
  440. case '-':
  441. set = false;
  442. break;
  443. case '+':
  444. set = true;
  445. break;
  446. default:
  447. set = true;
  448. skiponce = true;
  449. }
  450. /* Prepare reply string */
  451. strcpy(the_modes, set ? "+" : "-");
  452. the_args[0] = '\0';
  453. x[1] = '\0';
  454. connected = CONNECTED;
  455. while (mode_ptr) {
  456. if (!skiponce)
  457. mode_ptr++;
  458. if (!*mode_ptr) {
  459. /* Try next argument if there's any */
  460. if (arg_arg < 0)
  461. break;
  462. if (arg_arg > mode_arg)
  463. mode_arg = arg_arg;
  464. else
  465. mode_arg++;
  466. if (mode_arg >= Req->argc)
  467. break;
  468. mode_ptr = Req->argv[mode_arg];
  469. if (Req->argc > mode_arg + 1)
  470. arg_arg = mode_arg + 1;
  471. else
  472. arg_arg = -1;
  473. }
  474. skiponce = false;
  475. switch (*mode_ptr) {
  476. case '+':
  477. case '-':
  478. if (((*mode_ptr == '+') && !set)
  479. || ((*mode_ptr == '-') && set)) {
  480. /* Action modifier ("+"/"-") must be changed ... */
  481. len = strlen(the_modes) - 1;
  482. if (the_modes[len] == '+' || the_modes[len] == '-') {
  483. /* Adjust last action modifier in result */
  484. the_modes[len] = *mode_ptr;
  485. } else {
  486. /* Append modifier character to result string */
  487. x[0] = *mode_ptr;
  488. strlcat(the_modes, x, sizeof(the_modes));
  489. }
  490. set = *mode_ptr == '+';
  491. }
  492. continue;
  493. }
  494. /* Are there arguments left? */
  495. if (arg_arg >= Req->argc)
  496. arg_arg = -1;
  497. if(!is_machine && !is_oper) {
  498. if (Channel_UserHasMode(Channel, Client, 'q'))
  499. is_owner = true;
  500. if (Channel_UserHasMode(Channel, Client, 'a'))
  501. is_admin = true;
  502. if (Channel_UserHasMode(Channel, Client, 'o'))
  503. is_op = true;
  504. if (Channel_UserHasMode(Channel, Client, 'h'))
  505. is_halfop = true;
  506. }
  507. /* Validate modes */
  508. x[0] = '\0';
  509. argadd[0] = '\0';
  510. client = NULL;
  511. switch (*mode_ptr) {
  512. /* --- Channel modes --- */
  513. case 'R': /* Registered users only */
  514. case 's': /* Secret channel */
  515. case 'z': /* Secure connections only */
  516. if(!is_oper && !is_machine && !is_owner &&
  517. !is_admin && !is_op) {
  518. connected = IRC_WriteErrClient(Origin,
  519. ERR_CHANOPRIVSNEEDED_MSG,
  520. Client_ID(Origin), Channel_Name(Channel));
  521. goto chan_exit;
  522. }
  523. case 'i': /* Invite only */
  524. case 'V': /* Invite disallow */
  525. case 'M': /* Only identified nicks can write */
  526. case 'm': /* Moderated */
  527. case 'n': /* Only members can write */
  528. case 'N': /* Can't change nick while on this channel */
  529. case 'Q': /* No kicks */
  530. case 't': /* Topic locked */
  531. if(is_oper || is_machine || is_owner ||
  532. is_admin || is_op || is_halfop)
  533. x[0] = *mode_ptr;
  534. else
  535. connected = IRC_WriteErrClient(Origin,
  536. ERR_CHANOPRIVSNEEDED_MSG,
  537. Client_ID(Origin), Channel_Name(Channel));
  538. break;
  539. case 'k': /* Channel key */
  540. if (Mode_Limit_Reached(Client, mode_arg_count++))
  541. goto chan_exit;
  542. if (!set) {
  543. if (is_oper || is_machine || is_owner ||
  544. is_admin || is_op || is_halfop) {
  545. x[0] = *mode_ptr;
  546. if (Channel_HasMode(Channel, 'k'))
  547. strlcpy(argadd, "*", sizeof(argadd));
  548. if (arg_arg > mode_arg)
  549. arg_arg++;
  550. } else
  551. connected = IRC_WriteErrClient(Origin,
  552. ERR_CHANOPRIVSNEEDED_MSG,
  553. Client_ID(Origin),
  554. Channel_Name(Channel));
  555. break;
  556. }
  557. if (arg_arg > mode_arg) {
  558. if (is_oper || is_machine || is_owner ||
  559. is_admin || is_op || is_halfop) {
  560. Channel_ModeDel(Channel, 'k');
  561. Channel_SetKey(Channel,
  562. Req->argv[arg_arg]);
  563. strlcpy(argadd, Channel_Key(Channel),
  564. sizeof(argadd));
  565. x[0] = *mode_ptr;
  566. } else {
  567. connected = IRC_WriteErrClient(Origin,
  568. ERR_CHANOPRIVSNEEDED_MSG,
  569. Client_ID(Origin),
  570. Channel_Name(Channel));
  571. }
  572. Req->argv[arg_arg][0] = '\0';
  573. arg_arg++;
  574. } else {
  575. #ifdef STRICT_RFC
  576. /* Only send error message in "strict" mode,
  577. * this is how ircd2.11 and others behave ... */
  578. connected = IRC_WriteErrClient(Origin,
  579. ERR_NEEDMOREPARAMS_MSG,
  580. Client_ID(Origin), Req->command);
  581. #endif
  582. goto chan_exit;
  583. }
  584. break;
  585. case 'l': /* Member limit */
  586. if (Mode_Limit_Reached(Client, mode_arg_count++))
  587. goto chan_exit;
  588. if (!set) {
  589. if (is_oper || is_machine || is_owner ||
  590. is_admin || is_op || is_halfop)
  591. x[0] = *mode_ptr;
  592. else
  593. connected = IRC_WriteErrClient(Origin,
  594. ERR_CHANOPRIVSNEEDED_MSG,
  595. Client_ID(Origin),
  596. Channel_Name(Channel));
  597. break;
  598. }
  599. if (arg_arg > mode_arg) {
  600. if (is_oper || is_machine || is_owner ||
  601. is_admin || is_op || is_halfop) {
  602. l = atol(Req->argv[arg_arg]);
  603. if (l > 0 && l < 0xFFFF) {
  604. Channel_ModeDel(Channel, 'l');
  605. Channel_SetMaxUsers(Channel, l);
  606. snprintf(argadd, sizeof(argadd),
  607. "%ld", l);
  608. x[0] = *mode_ptr;
  609. }
  610. } else {
  611. connected = IRC_WriteErrClient(Origin,
  612. ERR_CHANOPRIVSNEEDED_MSG,
  613. Client_ID(Origin),
  614. Channel_Name(Channel));
  615. }
  616. Req->argv[arg_arg][0] = '\0';
  617. arg_arg++;
  618. } else {
  619. #ifdef STRICT_RFC
  620. /* Only send error message in "strict" mode,
  621. * this is how ircd2.11 and others behave ... */
  622. connected = IRC_WriteErrClient(Origin,
  623. ERR_NEEDMOREPARAMS_MSG,
  624. Client_ID(Origin), Req->command);
  625. #endif
  626. goto chan_exit;
  627. }
  628. break;
  629. case 'O': /* IRC operators only */
  630. if (set) {
  631. /* Only IRC operators are allowed to
  632. * set the 'O' channel mode! */
  633. if(is_oper || is_machine)
  634. x[0] = 'O';
  635. else
  636. connected = IRC_WriteErrClient(Origin,
  637. ERR_NOPRIVILEGES_MSG,
  638. Client_ID(Origin));
  639. } else if(is_oper || is_machine || is_owner ||
  640. is_admin || is_op)
  641. x[0] = 'O';
  642. else
  643. connected = IRC_WriteErrClient(Origin,
  644. ERR_CHANOPRIVSNEEDED_MSG,
  645. Client_ID(Origin),
  646. Channel_Name(Channel));
  647. break;
  648. case 'P': /* Persistent channel */
  649. if (set) {
  650. /* Only IRC operators are allowed to
  651. * set the 'P' channel mode! */
  652. if(is_oper || is_machine)
  653. x[0] = 'P';
  654. else
  655. connected = IRC_WriteErrClient(Origin,
  656. ERR_NOPRIVILEGES_MSG,
  657. Client_ID(Origin));
  658. } else if(is_oper || is_machine || is_owner ||
  659. is_admin || is_op)
  660. x[0] = 'P';
  661. else
  662. connected = IRC_WriteErrClient(Origin,
  663. ERR_CHANOPRIVSNEEDED_MSG,
  664. Client_ID(Origin),
  665. Channel_Name(Channel));
  666. break;
  667. /* --- Channel user modes --- */
  668. case 'q': /* Owner */
  669. case 'a': /* Channel admin */
  670. if(!is_oper && !is_machine && !is_owner && !is_admin) {
  671. connected = IRC_WriteErrClient(Origin,
  672. ERR_CHANOPPRIVTOOLOW_MSG,
  673. Client_ID(Origin),
  674. Channel_Name(Channel));
  675. goto chan_exit;
  676. }
  677. case 'o': /* Channel operator */
  678. if(!is_oper && !is_machine && !is_owner &&
  679. !is_admin && !is_op) {
  680. connected = IRC_WriteErrClient(Origin,
  681. ERR_CHANOPRIVSNEEDED_MSG,
  682. Client_ID(Origin),
  683. Channel_Name(Channel));
  684. goto chan_exit;
  685. }
  686. case 'h': /* Half Op */
  687. if(!is_oper && !is_machine && !is_owner &&
  688. !is_admin && !is_op) {
  689. connected = IRC_WriteErrClient(Origin,
  690. ERR_CHANOPRIVSNEEDED_MSG,
  691. Client_ID(Origin),
  692. Channel_Name(Channel));
  693. goto chan_exit;
  694. }
  695. case 'v': /* Voice */
  696. if (arg_arg > mode_arg) {
  697. if (is_oper || is_machine || is_owner ||
  698. is_admin || is_op || is_halfop) {
  699. client = Client_Search(Req->argv[arg_arg]);
  700. if (client)
  701. x[0] = *mode_ptr;
  702. else
  703. connected = IRC_WriteErrClient(Origin,
  704. ERR_NOSUCHNICK_MSG,
  705. Client_ID(Origin),
  706. Req->argv[arg_arg]);
  707. } else {
  708. connected = IRC_WriteErrClient(Origin,
  709. ERR_CHANOPRIVSNEEDED_MSG,
  710. Client_ID(Origin),
  711. Channel_Name(Channel));
  712. }
  713. Req->argv[arg_arg][0] = '\0';
  714. arg_arg++;
  715. } else {
  716. #ifdef STRICT_RFC
  717. /* Report an error to the client, when a user
  718. * mode should be changed but no nickname is
  719. * given. But don't do it when not in "strict"
  720. * mode, because most other servers don't do
  721. * it as well and some clients send "wired"
  722. * MODE commands like "MODE #chan -ooo nick". */
  723. connected = IRC_WriteErrClient(Origin,
  724. ERR_NEEDMOREPARAMS_MSG,
  725. Client_ID(Origin), Req->command);
  726. #endif
  727. goto chan_exit;
  728. }
  729. break;
  730. /* --- Channel lists --- */
  731. case 'I': /* Invite lists */
  732. case 'b': /* Ban lists */
  733. case 'e': /* Channel exception lists */
  734. if (Mode_Limit_Reached(Client, mode_arg_count++))
  735. goto chan_exit;
  736. if (arg_arg > mode_arg) {
  737. /* modify list */
  738. if (is_oper || is_machine || is_owner ||
  739. is_admin || is_op || is_halfop) {
  740. connected = set
  741. ? Add_To_List(*mode_ptr, Origin,
  742. Client, Channel,
  743. Req->argv[arg_arg])
  744. : Del_From_List(*mode_ptr, Origin,
  745. Client, Channel,
  746. Req->argv[arg_arg]);
  747. } else {
  748. connected = IRC_WriteErrClient(Origin,
  749. ERR_CHANOPRIVSNEEDED_MSG,
  750. Client_ID(Origin),
  751. Channel_Name(Channel));
  752. }
  753. Req->argv[arg_arg][0] = '\0';
  754. arg_arg++;
  755. } else {
  756. switch (*mode_ptr) {
  757. case 'I':
  758. Channel_ShowInvites(Origin, Channel);
  759. break;
  760. case 'b':
  761. Channel_ShowBans(Origin, Channel);
  762. break;
  763. case 'e':
  764. Channel_ShowExcepts(Origin, Channel);
  765. break;
  766. }
  767. }
  768. break;
  769. default:
  770. if (Client_Type(Client) != CLIENT_SERVER) {
  771. Log(LOG_DEBUG,
  772. "Unknown mode \"%c%c\" from \"%s\" on %s!?",
  773. set ? '+' : '-', *mode_ptr,
  774. Client_ID(Origin), Channel_Name(Channel));
  775. connected = IRC_WriteErrClient(Origin,
  776. ERR_UNKNOWNMODE_MSG,
  777. Client_ID(Origin), *mode_ptr,
  778. Channel_Name(Channel));
  779. x[0] = '\0';
  780. } else {
  781. Log(LOG_DEBUG,
  782. "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
  783. set ? '+' : '-', *mode_ptr,
  784. Client_ID(Origin), Channel_Name(Channel));
  785. x[0] = *mode_ptr;
  786. }
  787. }
  788. if (!connected)
  789. break;
  790. /* Is there a valid mode change? */
  791. if (!x[0])
  792. continue;
  793. /* Validate target client */
  794. if (client && (!Channel_IsMemberOf(Channel, client))) {
  795. if (!IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
  796. Client_ID(Origin),
  797. Client_ID(client),
  798. Channel_Name(Channel)))
  799. break;
  800. continue;
  801. }
  802. if (client) {
  803. /* Channel-User-Mode */
  804. retval = set
  805. ? Channel_UserModeAdd(Channel, client, x[0])
  806. : Channel_UserModeDel(Channel, client, x[0]);
  807. if (retval) {
  808. strlcat(the_args, " ", sizeof(the_args));
  809. strlcat(the_args, Client_ID(client),
  810. sizeof(the_args));
  811. strlcat(the_modes, x, sizeof(the_modes));
  812. LogDebug
  813. ("User \"%s\": Mode change on %s, now \"%s\"",
  814. Client_Mask(client), Channel_Name(Channel),
  815. Channel_UserModes(Channel, client));
  816. }
  817. } else {
  818. /* Channel-Mode */
  819. retval = set
  820. ? Channel_ModeAdd(Channel, x[0])
  821. : Channel_ModeDel(Channel, x[0]);
  822. if (retval) {
  823. strlcat(the_modes, x, sizeof(the_modes));
  824. LogDebug("Channel %s: Mode change, now \"%s\".",
  825. Channel_Name(Channel),
  826. Channel_Modes(Channel));
  827. }
  828. }
  829. /* Are there additional arguments to add? */
  830. if (argadd[0]) {
  831. strlcat(the_args, " ", sizeof(the_args));
  832. strlcat(the_args, argadd, sizeof(the_args));
  833. }
  834. }
  835. chan_exit:
  836. /* Are there changed modes? */
  837. if (the_modes[1]) {
  838. /* Clean up mode string */
  839. len = strlen(the_modes) - 1;
  840. if ((the_modes[len] == '+') || (the_modes[len] == '-'))
  841. the_modes[len] = '\0';
  842. if (Client_Type(Client) == CLIENT_SERVER) {
  843. /* MODE requests for local channels from other servers
  844. * are definitely invalid! */
  845. if (Channel_IsLocal(Channel)) {
  846. Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
  847. return CONNECTED;
  848. }
  849. /* Forward mode changes to channel users and all the
  850. * other remote servers: */
  851. IRC_WriteStrServersPrefix(Client, Origin,
  852. "MODE %s %s%s", Channel_Name(Channel),
  853. the_modes, the_args);
  854. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  855. false, "MODE %s %s%s", Channel_Name(Channel),
  856. the_modes, the_args);
  857. } else {
  858. if (use_servermode)
  859. Origin = Client_ThisServer();
  860. /* Send reply to client and inform other servers and channel users */
  861. connected = IRC_WriteStrClientPrefix(Client, Origin,
  862. "MODE %s %s%s", Channel_Name(Channel),
  863. the_modes, the_args);
  864. /* Only forward requests for non-local channels */
  865. if (!Channel_IsLocal(Channel))
  866. IRC_WriteStrServersPrefix(Client, Origin,
  867. "MODE %s %s%s", Channel_Name(Channel),
  868. the_modes, the_args);
  869. IRC_WriteStrChannelPrefix(Client, Channel, Origin,
  870. false, "MODE %s %s%s", Channel_Name(Channel),
  871. the_modes, the_args);
  872. }
  873. }
  874. return connected;
  875. } /* Channel_Mode */
  876. /**
  877. * Handler for the IRC "AWAY" command.
  878. *
  879. * @param Client The client from which this command has been received.
  880. * @param Req Request structure with prefix and all parameters.
  881. * @return CONNECTED or DISCONNECTED.
  882. */
  883. GLOBAL bool
  884. IRC_AWAY( CLIENT *Client, REQUEST *Req )
  885. {
  886. assert (Client != NULL);
  887. assert (Req != NULL);
  888. if (Req->argc == 1 && Req->argv[0][0]) {
  889. Client_SetAway(Client, Req->argv[0]);
  890. Client_ModeAdd(Client, 'a');
  891. IRC_WriteStrServersPrefix(Client, Client, "MODE %s :+a",
  892. Client_ID( Client));
  893. return IRC_WriteStrClient(Client, RPL_NOWAWAY_MSG,
  894. Client_ID( Client));
  895. } else {
  896. Client_ModeDel(Client, 'a');
  897. IRC_WriteStrServersPrefix(Client, Client, "MODE %s :-a",
  898. Client_ID( Client));
  899. return IRC_WriteStrClient(Client, RPL_UNAWAY_MSG,
  900. Client_ID( Client));
  901. }
  902. } /* IRC_AWAY */
  903. /**
  904. * Add entries to channel invite, ban and exception lists.
  905. *
  906. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  907. * @param Prefix The originator of the command.
  908. * @param Client The sender of the command.
  909. * @param Channel The channel of which the list should be modified.
  910. * @param Pattern The pattern to add to the list.
  911. * @return CONNECTED or DISCONNECTED.
  912. */
  913. static bool
  914. Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  915. const char *Pattern)
  916. {
  917. char mask[MASK_LEN];
  918. struct list_head *list = NULL;
  919. long int current_count;
  920. assert(Client != NULL);
  921. assert(Channel != NULL);
  922. assert(Pattern != NULL);
  923. assert(what == 'I' || what == 'b' || what == 'e');
  924. Lists_MakeMask(Pattern, mask, sizeof(mask));
  925. current_count = Lists_Count(Channel_GetListInvites(Channel))
  926. + Lists_Count(Channel_GetListExcepts(Channel))
  927. + Lists_Count(Channel_GetListBans(Channel));
  928. switch(what) {
  929. case 'I':
  930. list = Channel_GetListInvites(Channel);
  931. break;
  932. case 'b':
  933. list = Channel_GetListBans(Channel);
  934. break;
  935. case 'e':
  936. list = Channel_GetListExcepts(Channel);
  937. break;
  938. }
  939. if (Lists_CheckDupeMask(list, mask))
  940. return CONNECTED;
  941. if (Client_Type(Client) == CLIENT_USER &&
  942. current_count >= MAX_HNDL_CHANNEL_LISTS)
  943. return IRC_WriteErrClient(Client, ERR_LISTFULL_MSG,
  944. Client_ID(Client),
  945. Channel_Name(Channel), mask,
  946. MAX_HNDL_CHANNEL_LISTS);
  947. switch (what) {
  948. case 'I':
  949. if (!Channel_AddInvite(Channel, mask, false, Client_ID(Client)))
  950. return CONNECTED;
  951. break;
  952. case 'b':
  953. if (!Channel_AddBan(Channel, mask, Client_ID(Client)))
  954. return CONNECTED;
  955. break;
  956. case 'e':
  957. if (!Channel_AddExcept(Channel, mask, Client_ID(Client)))
  958. return CONNECTED;
  959. break;
  960. }
  961. return Send_ListChange(true, what, Prefix, Client, Channel, mask);
  962. }
  963. /**
  964. * Delete entries from channel invite, ban and exception lists.
  965. *
  966. * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
  967. * @param Prefix The originator of the command.
  968. * @param Client The sender of the command.
  969. * @param Channel The channel of which the list should be modified.
  970. * @param Pattern The pattern to add to the list.
  971. * @return CONNECTED or DISCONNECTED.
  972. */
  973. static bool
  974. Del_From_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
  975. const char *Pattern)
  976. {
  977. char mask[MASK_LEN];
  978. struct list_head *list = NULL;
  979. assert(Client != NULL);
  980. assert(Channel != NULL);
  981. assert(Pattern != NULL);
  982. assert(what == 'I' || what == 'b' || what == 'e');
  983. Lists_MakeMask(Pattern, mask, sizeof(mask));
  984. switch (what) {
  985. case 'I':
  986. list = Channel_GetListInvites(Channel);
  987. break;
  988. case 'b':
  989. list = Channel_GetListBans(Channel);
  990. break;
  991. case 'e':
  992. list = Channel_GetListExcepts(Channel);
  993. break;
  994. }
  995. if (!Lists_CheckDupeMask(list, mask))
  996. return CONNECTED;
  997. Lists_Del(list, mask);
  998. return Send_ListChange(false, what, Prefix, Client, Channel, mask);
  999. }
  1000. /**
  1001. * Send information about changed channel invite/ban/exception lists to clients.
  1002. *
  1003. * @param IsAdd true if the list item has been added, false otherwise.
  1004. * @param ModeChar The mode to use (e. g. 'b' or 'I')
  1005. * @param Prefix The originator of the mode list change.
  1006. * @param Client The sender of the command.
  1007. * @param Channel The channel of which the list has been modified.
  1008. * @param Mask The mask which has been added or removed.
  1009. * @return CONNECTED or DISCONNECTED.
  1010. */
  1011. static bool
  1012. Send_ListChange(const bool IsAdd, const char ModeChar, CLIENT *Prefix,
  1013. CLIENT *Client, CHANNEL *Channel, const char *Mask)
  1014. {
  1015. bool ok = true;
  1016. /* Send confirmation to the client */
  1017. if (Client_Type(Client) == CLIENT_USER)
  1018. ok = IRC_WriteStrClientPrefix(Client, Prefix, "MODE %s %c%c %s",
  1019. Channel_Name(Channel),
  1020. IsAdd ? '+' : '-',
  1021. ModeChar, Mask);
  1022. /* to other servers */
  1023. IRC_WriteStrServersPrefix(Client, Prefix, "MODE %s %c%c %s",
  1024. Channel_Name(Channel), IsAdd ? '+' : '-',
  1025. ModeChar, Mask);
  1026. /* and local users in channel */
  1027. IRC_WriteStrChannelPrefix(Client, Channel, Prefix, false,
  1028. "MODE %s %c%c %s", Channel_Name(Channel),
  1029. IsAdd ? '+' : '-', ModeChar, Mask );
  1030. return ok;
  1031. } /* Send_ListChange */
  1032. /* -eof- */