Advertisement
Guest User

Untitled

a guest
Jan 24th, 2016
418
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.68 KB | None | 0 0
  1. /*
  2. * =================================================================
  3. * Filename: cmdshun.c
  4. * Description: Command shun
  5. * Author: AngryWolf <angrywolf@flashmail.com>
  6. * Documentation: cmdshun.txt (comes with the package)
  7. * =================================================================
  8. */
  9.  
  10. #include "config.h"
  11. #include "struct.h"
  12. #include "common.h"
  13. #include "sys.h"
  14. #include "numeric.h"
  15. #include "msg.h"
  16. #include "channel.h"
  17. #include <time.h>
  18. #include <sys/stat.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #ifdef _WIN32
  23. #include <io.h>
  24. #endif
  25. #include <fcntl.h>
  26. #include "h.h"
  27. #ifdef STRIPBADWORDS
  28. #include "badwords.h"
  29. #endif
  30. #ifdef _WIN32
  31. #include "version.h"
  32. #endif
  33.  
  34. typedef struct _cmdentry CmdEntry;
  35. typedef struct _cmdshun CmdShun;
  36. typedef struct _ovrentry OvrEntry;
  37.  
  38. /*
  39. * CmdEntry:
  40. * list of commands disabled for a user@host
  41. *
  42. * cmd: info about the disabled command
  43. * opt: additional options for PRIVSMG & NOTICE
  44. */
  45. struct _cmdentry
  46. {
  47. CmdEntry *prev, *next;
  48. OvrEntry *cmd;
  49. char opt;
  50. };
  51.  
  52. /*
  53. * OvrEntry:
  54. * list of command overrides used by this module
  55. *
  56. * ovr: an override entry for the command
  57. * name: name of the command
  58. * used: how many times the command is used in CmdShuns
  59. * temporary: has a true value if the command belongs to temporarily
  60. * created command lists
  61. */
  62. struct _ovrentry
  63. {
  64. OvrEntry *prev, *next;
  65. Cmdoverride *ovr;
  66. char *name;
  67. unsigned short used;
  68. unsigned char temporary;
  69. };
  70.  
  71. /*
  72. * CmdShun:
  73. * data structure for a command shun
  74. * primary keys: usermask, hostmask, cmdlist
  75. *
  76. * commands: a copy of the command list given the second parameter of
  77. * /cmdshun
  78. * cmdlist: a parsed form of the command list
  79. * numofcmds: how many commands are in the command list
  80. * event: an event to remove an expired cmdshun
  81. */
  82. struct _cmdshun
  83. {
  84. CmdShun *prev, *next;
  85. char *usermask, *hostmask;
  86. char *setby, *reason, *commands;
  87. CmdEntry *cmdlist;
  88. struct irc_netmask *netmask;
  89. Event *event;
  90. u_short numofcmds;
  91. TS set_at;
  92. TS expire_at;
  93. };
  94.  
  95. extern void sendto_one(aClient *to, char *pattern, ...);
  96. extern void sendto_realops(char *pattern, ...);
  97. extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...);
  98.  
  99. #define ERR_DISABLED ":%s 517 %s %s :Command disabled (%s)" /* ircu */
  100. #define MSG_CMDSHUN "CMDSHUN"
  101. #define TOK_CMDSHUN NULL
  102. #define MSG_CMDSHUNFWD "CMDSHUNFWD"
  103. #define TOK_CMDSHUNFWD "SF"
  104. #define OPT_FLAG '#'
  105.  
  106. #define IsParam(x) (parc > (x) && !BadPtr(parv[(x)]))
  107. #define IsNotParam(x) (parc <= (x) || BadPtr(parv[(x)]))
  108. #define DelHook(x) if (x) HookDel(x); x = NULL
  109. #define DelCommand(x) if (x) CommandDel(x); x = NULL
  110. #define DelOverride(cmd, ovr) if (ovr && CommandExists(cmd)) CmdoverrideDel(ovr); ovr = NULL
  111.  
  112. static Command *AddCommand(Module *module, char *msg, char *token, iFP func, unsigned char parameters, int flags);
  113. static Cmdoverride *AddOverride(char *msg, iFP cb);
  114. static int m_cmdshun(aClient *, aClient *, int, char *[]);
  115. static int m_cmdshunfwd(aClient *, aClient *, int, char *[]);
  116. static int ovr_cmd(Cmdoverride *, aClient *, aClient *, int, char *[]);
  117. static int cb_rehash();
  118. static int cb_rehash_complete();
  119. static int cb_server_connect(aClient *);
  120. static void del_cmdshun(CmdShun *s);
  121.  
  122. static ModuleInfo *ModCmdshun;
  123. static Hook *HookRehashDone, *HookRehash, *HookServConn;
  124. static Command *CmdCmdshun, *CmdCmdshunfwd;
  125. static CmdShun *CmdShunList;
  126. static OvrEntry *OverridesList;
  127. static CmdEntry *tmp_cmdlist;
  128. static aClient *SetBy;
  129. static u_char module_loaded = 0;
  130. static char buf[BUFSIZE];
  131. static u_short tmp_numofcmds;
  132.  
  133. #ifndef STATIC_LINKING
  134. static ModuleInfo *MyModInfo = NULL;
  135. #define MyMod MyModInfo->handle
  136. #define SAVE_MODINFO MyModInfo = modinfo;
  137. #else
  138. #define MyMod NULL
  139. #define SAVE_MODINFO
  140. #endif
  141.  
  142. ModuleHeader MOD_HEADER(cmdshun)
  143. = {
  144. "cmdshun",
  145. "$Id: cmdshun.c,v 1.1 2004/08/16 13:31:25 angrywolf Exp $",
  146. "Command Shun",
  147. "3.2-b8-1",
  148. NULL
  149. };
  150.  
  151. DLLFUNC int MOD_TEST(cmdshun)(ModuleInfo *modinfo)
  152. {
  153. return MOD_SUCCESS;
  154. }
  155.  
  156. DLLFUNC int MOD_INIT(cmdshun)(ModuleInfo *modinfo)
  157. {
  158. SAVE_MODINFO
  159.  
  160. #ifndef STATIC_LINKING
  161. ModuleSetOptions(modinfo->handle, MOD_OPT_PERM);
  162. #endif
  163.  
  164. ModCmdshun = modinfo;
  165. CmdShunList = NULL;
  166. OverridesList = NULL;
  167. SetBy = NULL;
  168. tmp_cmdlist = NULL;
  169. tmp_numofcmds = 0;
  170.  
  171. HookRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH,
  172. cb_rehash);
  173. HookRehashDone = HookAddEx(modinfo->handle, HOOKTYPE_REHASH_COMPLETE,
  174. cb_rehash_complete);
  175. HookServConn = HookAddEx(modinfo->handle, HOOKTYPE_SERVER_CONNECT,
  176. cb_server_connect);
  177.  
  178. CmdCmdshun = AddCommand(modinfo->handle, MSG_CMDSHUN, TOK_CMDSHUN,
  179. m_cmdshun, 4, 0);
  180. CmdCmdshunfwd = AddCommand(modinfo->handle, MSG_CMDSHUNFWD, TOK_CMDSHUNFWD,
  181. m_cmdshunfwd, MAXPARA, M_SERVER);
  182.  
  183. if (!CmdCmdshun || !CmdCmdshunfwd)
  184. return MOD_FAILED;
  185.  
  186. return MOD_SUCCESS;
  187. }
  188.  
  189. DLLFUNC int MOD_LOAD(cmdshun)(int module_load)
  190. {
  191. cb_rehash_complete();
  192. return MOD_SUCCESS;
  193. }
  194.  
  195. DLLFUNC int MOD_UNLOAD(cmdshun)(int module_unload)
  196. {
  197. CmdShun *s;
  198. ListStruct *next;
  199.  
  200. DelHook(HookServConn);
  201. DelHook(HookRehashDone);
  202. DelHook(HookRehash);
  203. DelCommand(CmdCmdshunfwd);
  204. DelCommand(CmdCmdshun);
  205. cb_rehash();
  206.  
  207. for (s = CmdShunList; s; s = (CmdShun *) next)
  208. {
  209. next = (ListStruct *) s->next;
  210. del_cmdshun(s);
  211. }
  212.  
  213. return MOD_SUCCESS;
  214. }
  215.  
  216. static int cb_rehash()
  217. {
  218. OvrEntry *o;
  219.  
  220. module_loaded = 0;
  221.  
  222. /*
  223. * What I do here is just deleting command overrides.
  224. * (Only command shun removals may delete OvrEntry structures.)
  225. */
  226.  
  227. for (o = OverridesList; o; o = o->next)
  228. if (o->ovr)
  229. {
  230. DelOverride(o->name, o->ovr);
  231. }
  232.  
  233. return 0;
  234. }
  235.  
  236. static int cb_rehash_complete()
  237. {
  238. OvrEntry *o;
  239.  
  240. if (!module_loaded)
  241. {
  242. for (o = OverridesList; o; o = o->next)
  243. if (!o->ovr)
  244. o->ovr = AddOverride(o->name, ovr_cmd);
  245.  
  246. module_loaded = 1;
  247. }
  248.  
  249. return 0;
  250. }
  251.  
  252. static Command *AddCommand(Module *module, char *msg, char *token, iFP func,
  253. unsigned char parameters, int flags)
  254. {
  255. Command *cmd;
  256.  
  257. if (CommandExists(msg))
  258. {
  259. config_error("Command %s already exists", msg);
  260. return NULL;
  261. }
  262. if (token && CommandExists(token))
  263. {
  264. config_error("Token %s already exists", token);
  265. return NULL;
  266. }
  267.  
  268. cmd = CommandAdd(module, msg, token, func, parameters, flags);
  269.  
  270. #ifndef STATIC_LINKING
  271. if (ModuleGetError(module) != MODERR_NOERROR || !cmd)
  272. #else
  273. if (!cmd)
  274. #endif
  275. {
  276. #ifndef STATIC_LINKING
  277. config_error("Error adding command %s: %s", msg,
  278. ModuleGetErrorStr(module));
  279. #else
  280. config_error("Error adding command %s", msg);
  281. #endif
  282. return NULL;
  283. }
  284.  
  285. return cmd;
  286. }
  287.  
  288. static Cmdoverride *AddOverride(char *msg, iFP cb)
  289. {
  290. Cmdoverride *ovr = CmdoverrideAdd(MyMod, msg, cb);
  291.  
  292. #ifndef STATIC_LINKING
  293. if (ModuleGetError(MyMod) != MODERR_NOERROR || !ovr)
  294. #else
  295. if (!ovr)
  296. #endif
  297. {
  298. #ifndef STATIC_LINKING
  299. config_error("Error replacing command %s when loading module %s: %s",
  300. msg, MOD_HEADER(cmdshun).name, ModuleGetErrorStr(MyMod));
  301. #else
  302. config_error("Error replacing command %s when loading module %s",
  303. msg, MOD_HEADER(cmdshun).name);
  304. #endif
  305. return NULL;
  306. }
  307.  
  308. return ovr;
  309. }
  310.  
  311. /*
  312. * cb_server_connect:
  313. * Distribute our CmdShuns to other servers on the network
  314. * when they are connecting to us or we to them.
  315. */
  316.  
  317. static int cb_server_connect(aClient *cptr)
  318. {
  319. CmdShun *s;
  320.  
  321. for (s = CmdShunList; s; s = s->next)
  322. {
  323. sendto_one(cptr, ":%s %s ! %s %s %s %s %ld %ld :%s",
  324. me.name, IsToken(cptr) ? TOK_CMDSHUNFWD : MSG_CMDSHUNFWD,
  325. s->usermask, s->hostmask, s->commands, s->setby,
  326. (long) s->set_at, (long) s->expire_at,
  327. s->reason ? s->reason : "");
  328. }
  329.  
  330. return 0;
  331. }
  332.  
  333. /*
  334. * find_Cmd_quick:
  335. * This is a quick way to search for commands names.
  336. */
  337.  
  338. static inline aCommand *find_Cmd_quick(char *cmd)
  339. {
  340. aCommand *p;
  341.  
  342. for (p = CommandHash[toupper(*cmd)]; p; p = p->next)
  343. if (!stricmp(p->cmd, cmd))
  344. break;
  345.  
  346. return p;
  347. }
  348.  
  349. /*
  350. * find_cmdentry:
  351. * Look through a list of commands, and search for a command with
  352. * the given options (c->opt).
  353. */
  354.  
  355. static CmdEntry *find_cmdentry(char *name, CmdEntry *list, char *param)
  356. {
  357. CmdEntry *c;
  358.  
  359. for (c = list; c; c = c->next)
  360. if (!stricmp(c->cmd->name, name))
  361. {
  362. if (c->opt)
  363. {
  364. if (!param)
  365. continue;
  366. if (!stricmp(name, "privmsg") ||
  367. !stricmp(name, "notice"))
  368. {
  369. if (c->opt == 'p' && param[0] == '#')
  370. continue;
  371. if (c->opt == 'c' && param[0] != '#')
  372. continue;
  373. }
  374. }
  375. break;
  376. }
  377.  
  378. return c;
  379. }
  380.  
  381. static OvrEntry *find_ovrentry(char *name)
  382. {
  383. OvrEntry *o;
  384.  
  385. for (o = OverridesList; o; o = o->next)
  386. if (!stricmp(o->name, name))
  387. break;
  388.  
  389. return o;
  390. }
  391.  
  392. /*
  393. * del_cmdlist:
  394. * Delete a list of command entries with their overrides.
  395. */
  396.  
  397. static void del_cmdlist(CmdEntry **list)
  398. {
  399. CmdEntry *c;
  400. OvrEntry *o;
  401. ListStruct *next;
  402.  
  403. for (c = *list; c; c = (CmdEntry *) next)
  404. {
  405. next = (ListStruct *) c->next;
  406. o = c->cmd;
  407.  
  408. DelListItem(c, *list);
  409. if (!--o->used)
  410. {
  411. DelListItem(o, OverridesList);
  412. DelOverride(o->name, o->ovr);
  413. if (!o->temporary)
  414. {
  415. MyFree(o->name);
  416. MyFree(o);
  417. }
  418. }
  419. MyFree(c);
  420. }
  421. }
  422.  
  423. /*
  424. * del_cmdlist_noovr:
  425. * Delete a list of command entries, but keep the overrides (this is
  426. * used with make_cmdlist, see below).
  427. */
  428.  
  429. static void del_cmdlist_noovr(CmdEntry **list)
  430. {
  431. CmdEntry *c;
  432. OvrEntry *o;
  433. ListStruct *next;
  434.  
  435. for (c = *list; c; c = (CmdEntry *) next)
  436. {
  437. next = (ListStruct *) c->next;
  438. o = c->cmd;
  439.  
  440. DelListItem(c, *list);
  441. if (!o->used)
  442. {
  443. MyFree(o->name);
  444. MyFree(o);
  445. }
  446. else
  447. o->temporary = 0;
  448. MyFree(c);
  449. }
  450. }
  451.  
  452. /*
  453. * make_cmdlist:
  454. * Create an initial list of command entries without overrides.
  455. * ('commands' may not be NULL.) Also return the number of
  456. * commands in the list through 'num'.
  457. */
  458.  
  459. static CmdEntry *make_cmdlist(char *commands, u_short *num)
  460. {
  461. CmdEntry *entry, *cmdlist = NULL;
  462. OvrEntry *o;
  463. char *tmp = strdup(commands);
  464. char *c, *p = NULL;
  465. char *opt;
  466. u_short count = 0;
  467.  
  468. for (c = strtoken(&p, tmp, ","); c; c = strtoken(&p, NULL, ","))
  469. {
  470. entry = (CmdEntry *) MyMallocEx(sizeof(CmdEntry));
  471. if ((opt = strchr(c, OPT_FLAG)))
  472. {
  473. opt[0] = 0;
  474. /*
  475. * Syntax is: <command>#<flag>. Set entry->opt to
  476. * OPT_FLAG when <flag> is missing or long than
  477. * one character.
  478. */
  479. entry->opt = (!opt[1] || opt[2])
  480. ? OPT_FLAG : opt[1];
  481. }
  482. if (!(o = find_ovrentry(c)))
  483. {
  484. o = (OvrEntry *) MyMallocEx(sizeof(OvrEntry));
  485. o->name = strdup(c);
  486. }
  487. if (opt)
  488. opt[0] = OPT_FLAG;
  489. o->temporary = 1;
  490. entry->cmd = o;
  491. AddListItem(entry, cmdlist);
  492. count++;
  493. }
  494.  
  495. MyFree(tmp);
  496. *num = count;
  497.  
  498. return cmdlist;
  499. }
  500.  
  501. static void del_cmdshun(CmdShun *s)
  502. {
  503. DelListItem(s, CmdShunList);
  504. MyFree(s->usermask);
  505. MyFree(s->hostmask);
  506. MyFree(s->commands);
  507. MyFree(s->setby);
  508. MyFree(s->reason);
  509. del_cmdlist(&s->cmdlist);
  510. if (s->netmask)
  511. MyFree(s->netmask);
  512. if (s->event)
  513. EventDel(s->event);
  514. MyFree(s);
  515. }
  516.  
  517. static void del_tmp_data()
  518. {
  519. del_cmdlist_noovr(&tmp_cmdlist);
  520. tmp_numofcmds = 0;
  521. }
  522.  
  523. static void event_cmdshunexpire(CmdShun *s)
  524. {
  525. char gmt[64], *settime, *p;
  526. TS now = TStime();
  527.  
  528. if (s->expire_at > now)
  529. {
  530. /*
  531. * I don't know how feasible this can be, but at least
  532. * inform opers if such a thing happens...
  533. */
  534. if (s->expire_at)
  535. {
  536. char gmt2[64];
  537.  
  538. strlcpy(gmt2, asctime(gmtime(&s->expire_at)), sizeof gmt);
  539. iCstrip(gmt2);
  540.  
  541. sendto_realops("event_cmdshunexpire(): expire for "
  542. "non-yet-expired CmdShun %s@%s with "
  543. "command%s %s (should expire on %s GMT)",
  544. s->usermask, s->hostmask,
  545. s->cmdlist->next ? "s" : "", s->commands,
  546. gmt);
  547. }
  548. else
  549. {
  550. sendto_realops("event_cmdshunexpire(): expire for "
  551. "permanent CmdShun %s@%s with command%s %s",
  552. s->usermask, s->hostmask,
  553. s->cmdlist->next ? "s" : "", s->commands,
  554. gmt);
  555. }
  556.  
  557. return;
  558. }
  559.  
  560. /* notification */
  561. strlcpy(gmt, asctime(gmtime(&s->set_at)), sizeof gmt);
  562. iCstrip(gmt);
  563.  
  564. settime = pretty_time_val(TStime() - s->set_at);
  565. if (*(p = settime + strlen(settime) - 1) == ' ')
  566. *p = 0;
  567.  
  568. snprintf(buf, sizeof buf, "Expiring CmdShun (%s@%s with command%s "
  569. "%s) made by %s (Reason: %s) set %s ago)",
  570. s->usermask, s->hostmask, s->cmdlist->next ? "s" : "",
  571. s->commands, s->setby, s->reason ? s->reason : "no reason",
  572. settime);
  573.  
  574. sendto_snomask(SNO_TKL, "*** %s", buf);
  575. ircd_log(LOG_TKL, "%s", buf);
  576.  
  577. del_cmdshun(s);
  578. }
  579.  
  580. static int ovr_cmd(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
  581. {
  582. if (MyConnect(sptr) && !IsULine(sptr) && IsPerson(sptr) && !IsAnOper(sptr))
  583. {
  584. CmdShun *s;
  585. char *param = IsParam(1) ? parv[1] : NULL;
  586. char *ip = GetIP(sptr);
  587. char *user = sptr->user->username;
  588. char *host = sptr->sockhost;
  589. char *cmd = ovr->command->cmd;
  590.  
  591. for (s = CmdShunList; s; s = s->next)
  592. {
  593. if (!find_cmdentry(cmd, s->cmdlist, param))
  594. continue;
  595. if (match(s->usermask, user))
  596. continue;
  597. if (s->netmask)
  598. {
  599. if (match_ip(sptr->ip, NULL, NULL, s->netmask))
  600. break;
  601. continue;
  602. }
  603. if (!match(s->hostmask, host))
  604. break;
  605. if (!match(s->hostmask, ip))
  606. break;
  607. }
  608.  
  609. if (s)
  610. {
  611. sendto_one(sptr, ERR_DISABLED, me.name, sptr->name,
  612. cmd, s->reason ? s->reason : "no reason");
  613. return 0;
  614. }
  615. }
  616.  
  617. return CallCmdoverride(ovr, cptr, sptr, parc, parv);
  618. }
  619.  
  620. /*
  621. ** m_cmdshun
  622. ** ---------
  623. **
  624. ** Used by IRCOps to add/remove CmdShuns.
  625. **
  626. ** parv[1]: u@h mask or nick
  627. ** parv[2]: commands
  628. ** parv[3]: expire time (optional)
  629. ** parv[4]: reason (optional)
  630. **
  631. */
  632.  
  633. #define PFrom 0
  634. #define PWhat 1
  635. #define PUserMask 2
  636. #define PHostMask 3
  637. #define PCommands 4
  638. #define PSetBy 5
  639. #define PSetAt 6
  640. #define PExpireAt 7
  641. #define PReason 8
  642.  
  643. static int m_cmdshun(aClient *cptr, aClient *sptr, int parc, char *parv[])
  644. {
  645. char *params[9];
  646. char *p, *mask, *usermask, *hostmask;
  647. char set_at[BUFSIZE], expire_at[BUFSIZE];
  648. u_char add;
  649.  
  650. if (!MyConnect(sptr) || !IsPerson(sptr))
  651. return 0;
  652.  
  653. if (!IsAnOper(sptr) && !IsULine(sptr))
  654. {
  655. sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
  656. return 0;
  657. }
  658.  
  659. if (IsNotParam(1))
  660. {
  661. CmdShun *s;
  662. char gmt[64], *expiretime = NULL, *p;
  663.  
  664. for (s = CmdShunList; s; s = s->next)
  665. {
  666. strlcpy(gmt, asctime(gmtime(&s->set_at)), sizeof gmt);
  667. iCstrip(gmt);
  668.  
  669. if (s->expire_at)
  670. {
  671. expiretime = pretty_time_val(s->expire_at - TStime());
  672. if (*(p = expiretime + strlen(expiretime) - 1) == ' ')
  673. *p = 0;
  674. }
  675.  
  676. sendto_one(sptr, ":%s %i %s :CmdShun %s@%s %s (set at: %s, "
  677. "%s%s, reason: %s)",
  678. me.name, RPL_TEXT, sptr->name,
  679. s->usermask, s->hostmask, s->commands, gmt,
  680. s->expire_at ? "expires in: " : "never expires",
  681. s->expire_at ? expiretime : "",
  682. s->reason ? s->reason : "no reason");
  683. }
  684.  
  685. sendnotice(sptr, "End of /CMDSHUN list");
  686. return 0;
  687. }
  688.  
  689. if (!IsULine(sptr) && !OPCanTKL(sptr))
  690. {
  691. sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
  692. return 0;
  693. }
  694.  
  695. /* add or remove? */
  696. mask = parv[1];
  697. add = 1;
  698.  
  699. switch(*mask)
  700. {
  701. case '-':
  702. add = 0;
  703. case '+':
  704. mask++;
  705. }
  706.  
  707. /* no mask & command(s)? */
  708. if (!*mask || IsNotParam(2))
  709. {
  710. sendnotice(sptr, "*** \2Usage:\2 /cmdshun [+]<user@host>|<nick> <command-list> [<expiretime>] :<reason>]");
  711. sendnotice(sptr, "*** /cmdshun -<user@host>|<nick> <command-list>");
  712. sendnotice(sptr, "*** <command-list>: a comma-separated list of one or more command names");
  713. sendnotice(sptr, "*** <expiretime>: a time value in the usual format");
  714. sendnotice(sptr, "*** \2Examples:\2 /cmdshun *user@*.host1 whois,whowas 2h5s This is your punishment");
  715. sendnotice(sptr, "*** /cmdshun -*user@*.host1 whois,whowas");
  716. return 0;
  717. }
  718.  
  719. /* check if it's a hostmask and legal */
  720. if ((p = strchr(mask, '@')))
  721. {
  722. if (add && strchr(mask, '!'))
  723. {
  724. sendnotice(sptr, "[error] Cannot have ! in masks.");
  725. return 0;
  726. }
  727.  
  728. /*
  729. * I know buggy OS'es shouldn't be supported, but since I'm developing
  730. * modules on a Linux with glibc-2.3.2, I don't want to see that
  731. * strtok() bug again with /cmdshun +@ ... (see m_tkl_line if you don't
  732. * know what I'm talking about). Also: I don't think my solution is
  733. * slower.
  734. *
  735. * http://www.mail-archive.com/bug-glibc@gnu.org/msg01210.html
  736. * http://lists.gnu.org/archive/html/bug-glibc/2001-02/msg00117.html
  737. */
  738.  
  739. *p = 0;
  740. usermask = mask;
  741. hostmask = p + 1;
  742.  
  743. if (!*hostmask)
  744. {
  745. if (!*usermask)
  746. {
  747. sendnotice(sptr, "[error] Syntax error in mask.");
  748. return 0;
  749. }
  750.  
  751. /* convert "user@" to "*@user" */
  752. hostmask = usermask;
  753. usermask = "*";
  754. }
  755. else if (!*usermask)
  756. /* convert "@host" to "*@host" */
  757. usermask = "*";
  758. }
  759. else
  760. {
  761. aClient *acptr;
  762.  
  763. /* It's seemingly a nick .. let's see if we can find the user */
  764. if (!(acptr = find_person(mask, NULL)))
  765. {
  766. sendto_one(sptr, rpl_str(ERR_NOSUCHNICK), me.name,
  767. sptr->name, mask);
  768. return 0;
  769. }
  770.  
  771. usermask = "*";
  772. hostmask = acptr->user->realhost;
  773. }
  774.  
  775. /* do other checkings & build up params list */
  776. if (add)
  777. {
  778. struct tm *t;
  779. OvrEntry *o;
  780. CmdEntry *c, *c2;
  781. TS secs, now;
  782. int i = 0;
  783.  
  784. for (p = hostmask; *p; p++)
  785. if (*p != '*' && *p != '.' && *p != '?')
  786. i++;
  787. if (i < 4)
  788. {
  789. sendnotice(sptr, "*** [error] Too broad mask");
  790. return 0;
  791. }
  792.  
  793. /* Prepare temporary cmdlist for m_cmdshunfwd */
  794. tmp_cmdlist = make_cmdlist(parv[2], &tmp_numofcmds);
  795.  
  796. /* Check if valid command names & options are given */
  797. for (c = tmp_cmdlist; c; c = c->next)
  798. {
  799. o = c->cmd;
  800.  
  801. if (!find_Cmd_quick(o->name))
  802. {
  803. /*
  804. * It may happen that a command exists on
  805. * a server while it doesn't on other servers
  806. * of the network. I think the best is to
  807. * accept non-existing commands only remotely.
  808. * The goal is to not have desynchs between
  809. * servers.
  810. */
  811.  
  812. sendnotice(sptr, "[error] No such command: "
  813. "%s", o->name);
  814. del_tmp_data();
  815. return 0;
  816. }
  817. if (!stricmp(o->name, "privmsg") ||
  818. !stricmp(o->name, "notice"))
  819. {
  820. if (!c->opt)
  821. continue;
  822. if (c->opt == OPT_FLAG)
  823. {
  824. sendnotice(sptr, "[error] Syntax "
  825. "error after command '%s'",
  826. o->name);
  827. del_tmp_data();
  828. return 0;
  829. }
  830. if (c->opt != 'p' && c->opt != 'c')
  831. {
  832. sendnotice(sptr, "[error] Option '%c' "
  833. "is invalid for command '%s'",
  834. c->opt, o->name);
  835. del_tmp_data();
  836. return 0;
  837. }
  838. }
  839. else if (c->opt)
  840. {
  841. sendnotice(sptr, "[error] No options "
  842. "available for command %s",
  843. o->name);
  844. del_tmp_data();
  845. return 0;
  846. }
  847. }
  848.  
  849. /* Check for duplicated commands */
  850. for (c = tmp_cmdlist; c; c = c->next)
  851. for (c2 = c->next; c2; c2 = c2->next)
  852. if (!stricmp(c->cmd->name, c2->cmd->name))
  853. {
  854. sendnotice(sptr, "[error] Command '%s' "
  855. "is already on the given list",
  856. c->cmd->name);
  857. del_tmp_data();
  858. return 0;
  859. }
  860.  
  861. secs = 0;
  862. if (IsParam(3))
  863. {
  864. secs = atime(parv[3]);
  865. if (secs < 0)
  866. {
  867. sendnotice(sptr, "*** [error] The time you "
  868. "specified is out of range!");
  869. return 0;
  870. }
  871. }
  872. else if (DEFAULT_BANTIME)
  873. secs = DEFAULT_BANTIME;
  874.  
  875. now = TStime();
  876. if (secs)
  877. secs += now;
  878.  
  879. ircsprintf(set_at, "%ld", now);
  880. ircsprintf(expire_at, "%ld", secs);
  881.  
  882. i = atol(expire_at);
  883. t = gmtime((TS *)&i);
  884. if (!t)
  885. {
  886. sendnotice(sptr, "*** [error] The time you specified "
  887. "is out of range");
  888. return 0;
  889. }
  890.  
  891. params[PWhat] = "+";
  892. params[PSetAt] = set_at;
  893. params[PExpireAt] = expire_at;
  894. params[PReason] = IsParam(4) ? parv[4] : "";
  895. }
  896. else
  897. {
  898. params[PWhat] = "-";
  899. }
  900.  
  901. params[PFrom] = me.name;
  902. params[PUserMask] = usermask;
  903. params[PHostMask] = hostmask;
  904. params[PCommands] = parv[2];
  905. params[PSetBy] = make_nick_user_host(sptr->name,
  906. sptr->user->username, GetHost(sptr));
  907.  
  908. SetBy = sptr;
  909. m_cmdshunfwd(&me, &me, 9, params);
  910. SetBy = NULL;
  911.  
  912. return 0;
  913. }
  914.  
  915. /*
  916. ** m_cmdshunfwd
  917. ** ------------
  918. **
  919. ** Used by servers to distribute CmdShuns.
  920. **
  921. ** parv[0]: server name
  922. ** parv[1]: + (add) / - (remove) / ! (sync)
  923. ** parv[2]: usermask
  924. ** parv[3]: hostmask
  925. ** parv[4]: commands
  926. ** parv[5]: setby (or removed by)
  927. ** parv[6]: set_at
  928. ** parv[7]: expire_at
  929. ** parv[8]: reason (optional)
  930. **
  931. ** Note: NO PARAM CHECKING! You shouldn't really know anything
  932. ** about the existence of this command. Otherwise
  933. ** don't complain about server crashes!
  934. */
  935.  
  936. static int m_cmdshunfwd(aClient *cptr, aClient *sptr, int parc, char *parv[])
  937. {
  938. char *usermask = parv[PUserMask], *hostmask = parv[PHostMask];
  939. char *commands = parv[PCommands];
  940. char gmt[64], gmt2[64], what = *parv[PWhat];
  941. CmdEntry *c, *c2;
  942. CmdShun *s;
  943.  
  944. if (!tmp_cmdlist)
  945. tmp_cmdlist = make_cmdlist(commands, &tmp_numofcmds);
  946.  
  947. switch(what)
  948. {
  949. case '!':
  950. case '+':
  951. {
  952. struct irc_netmask tmp;
  953. OvrEntry *o;
  954. TS setat = atol(parv[PSetAt]);
  955. TS expireat = atol(parv[PExpireAt]);
  956.  
  957. /* Preliminary checks on commands list */
  958. for (c = tmp_cmdlist; c; c = c->next)
  959. if (c->cmd->used >= 5000) /* just to be sure */
  960. {
  961. if (SetBy)
  962. sendnotice(SetBy, "[error] Too much "
  963. "cmdshuns for command %s",
  964. c->cmd->name);
  965. del_tmp_data();
  966. return 0;
  967. }
  968.  
  969. /* Check if the cmdshun is added */
  970. for (s = CmdShunList; s; s = s->next)
  971. {
  972. if (stricmp(s->usermask, usermask) ||
  973. stricmp(s->hostmask, hostmask))
  974. continue;
  975.  
  976. for (c = s->cmdlist; c; c = c->next)
  977. for (c2 = tmp_cmdlist; c2; c2 = c2->next)
  978. if (!stricmp(c->cmd->name,
  979. c2->cmd->name))
  980. goto loopend;
  981. }
  982.  
  983. loopend: if (s) /* found */
  984. {
  985. /*
  986. * I haven't got definite plans about allowing
  987. * updates of CmdShuns. Currently the sync fight
  988. * idea seems to work, and I'll leave it here
  989. * until I work out the new method to handle
  990. * duplicate entries.
  991. */
  992.  
  993. if (what != '!')
  994. {
  995. if (SetBy)
  996. sendnotice(SetBy, "[error] A cmdshun "
  997. "with mask %s@%s and one of "
  998. "the specified command(s) is "
  999. "already set",
  1000. usermask, hostmask);
  1001.  
  1002. del_tmp_data();
  1003. return 0;
  1004. }
  1005. else /* sync problem, begin fight */
  1006. {
  1007. enum Results { r_WeWon, r_TheyWon };
  1008. u_char result = r_WeWon;
  1009.  
  1010. if (s->numofcmds > tmp_numofcmds)
  1011. /* we won */;
  1012. else if (s->numofcmds < tmp_numofcmds)
  1013. result = r_TheyWon;
  1014. else if (s->set_at < setat)
  1015. /* we won */;
  1016. else if (s->set_at > setat)
  1017. result = r_TheyWon;
  1018. else if (s->expire_at > expireat)
  1019. /* we won */;
  1020. else if (s->expire_at < expireat)
  1021. result = r_TheyWon;
  1022. else if (stricmp(s->reason, parv[PReason]) < 0)
  1023. /* we won */;
  1024. else if (stricmp(s->reason, parv[PReason]) > 0)
  1025. result = r_TheyWon;
  1026. else if (stricmp(s->commands, commands) < 0)
  1027. /* we won */;
  1028. else if (stricmp(s->commands, commands) > 0)
  1029. result = r_TheyWon;
  1030. /* default:
  1031. same cmdshuns -> we won */
  1032.  
  1033. /* sendto_realops("cmdshun sync-time fight: result=[%s], ours=[%s@%s %s %ld %ld] theirs=[%s@%s %s %ld %ld]",
  1034. result == r_TheyWon ? "r_TheyWon" : "r_WeWon",
  1035. s->usermask, s->hostmask, s->commands, (long) s->set_at, (long) s->expire_at,
  1036. usermask, hostmask, commands, setat, expireat); */
  1037.  
  1038. if (result == r_TheyWon)
  1039. {
  1040. /* replace the cmdshun with the new one */
  1041. del_cmdshun(s);
  1042. }
  1043. else
  1044. {
  1045. /* don't accept the new cmdshun */
  1046. del_tmp_data();
  1047. return 0;
  1048. }
  1049. }
  1050. }
  1051.  
  1052. /* Create a cmdshun entry */
  1053. s = (CmdShun *) MyMallocEx(sizeof(CmdShun));
  1054. s->usermask = strdup(usermask);
  1055. s->hostmask = strdup(hostmask);
  1056. s->commands = strdup(commands);
  1057. s->setby = strdup(parv[PSetBy]);
  1058. s->reason = *parv[PReason] ? strdup(parv[PReason]) : NULL;
  1059. for (c = tmp_cmdlist; c; c = c->next)
  1060. {
  1061. o = c->cmd;
  1062. o->temporary = 0;
  1063. if (!o->used++)
  1064. {
  1065. o->ovr = AddOverride(o->name, ovr_cmd);
  1066. AddListItem(o, OverridesList);
  1067. }
  1068. }
  1069. s->cmdlist = tmp_cmdlist;
  1070. s->numofcmds = tmp_numofcmds;
  1071. s->set_at = setat;
  1072. s->expire_at = expireat;
  1073. if ((tmp.type = parse_netmask(hostmask, &tmp)) != HM_HOST)
  1074. {
  1075. s->netmask = MyMallocEx(sizeof(struct irc_netmask));
  1076. bcopy(&tmp, s->netmask, sizeof(struct irc_netmask));
  1077. }
  1078. AddListItem(s, CmdShunList);
  1079. tmp_cmdlist = NULL;
  1080.  
  1081. /* Notification */
  1082. if (what == '+')
  1083. {
  1084. strlcpy(gmt, asctime(gmtime(&s->set_at)), sizeof gmt);
  1085. iCstrip(gmt);
  1086.  
  1087. if(s->expire_at)
  1088. {
  1089. s->event = EventAddEx(MyMod, "cmdshunexpire",
  1090. s->expire_at - TStime(), 1,
  1091. event_cmdshunexpire, s);
  1092.  
  1093. strlcpy(gmt2, asctime(gmtime(&s->expire_at)),
  1094. sizeof gmt2);
  1095. iCstrip(gmt2);
  1096.  
  1097. snprintf(buf, sizeof buf, "Timed CmdShun added "
  1098. "for %s@%s with command%s %s on %s GMT "
  1099. "(from %s to expire at %s GMT: %s)",
  1100. usermask, hostmask,
  1101. s->cmdlist->next ? "s" : "",
  1102. commands, gmt, parv[PSetBy], gmt2,
  1103. s->reason ? s->reason : "no reason");
  1104. }
  1105. else
  1106. {
  1107. snprintf(buf, sizeof buf, "Permanent CmdShun "
  1108. "added for %s@%s with command%s %s on "
  1109. "%s GMT (from %s: %s)",
  1110. usermask, hostmask,
  1111. s->cmdlist->next ? "s" : "",
  1112. commands, gmt, parv[PSetBy],
  1113. s->reason ? s->reason : "no reason");
  1114. }
  1115.  
  1116. sendto_snomask(SNO_TKL, "*** %s", buf);
  1117. ircd_log(LOG_TKL, "%s", buf);
  1118.  
  1119. }
  1120.  
  1121. sendto_serv_butone_token(NULL, parv[PFrom], MSG_CMDSHUNFWD,
  1122. TOK_CMDSHUNFWD, "%c %s %s %s %s %s %s :%s",
  1123. what, usermask, hostmask, commands, parv[PSetBy],
  1124. parv[PSetAt], parv[PExpireAt], parv[PReason]);
  1125.  
  1126. break;
  1127. }
  1128.  
  1129. case '-':
  1130. {
  1131. u_char required, found;
  1132.  
  1133. /* Check if the cmdshun is added */
  1134. for (s = CmdShunList; s; s = s->next)
  1135. {
  1136. if (stricmp(s->usermask, usermask) ||
  1137. stricmp(s->hostmask, hostmask))
  1138. continue;
  1139.  
  1140. required = found = 0;
  1141. for (c = s->cmdlist; c; c = c->next)
  1142. {
  1143. required++;
  1144. for (c2 = tmp_cmdlist; c2; c2 = c2->next)
  1145. if (!stricmp(c->cmd->name,
  1146. c2->cmd->name))
  1147. found++;
  1148. }
  1149.  
  1150. if (required == found)
  1151. break;
  1152. }
  1153.  
  1154. if (!s)
  1155. {
  1156. if (SetBy)
  1157. sendnotice(SetBy, "[error] No cmdshun "
  1158. "is set with mask %s@%s and "
  1159. "command%s %s",
  1160. usermask, hostmask,
  1161. strchr(commands, ',') ? "s" : "",
  1162. commands);
  1163.  
  1164. del_tmp_data();
  1165. return 0;
  1166. }
  1167.  
  1168. /* Notification */
  1169. strlcpy(gmt, asctime(gmtime(&s->set_at)), sizeof gmt);
  1170. iCstrip(gmt);
  1171.  
  1172. snprintf(buf, sizeof buf, "%s removed CmdShun %s@%s set "
  1173. "with command%s %s (at %s - reason: %s)",
  1174. parv[PSetBy], usermask, hostmask,
  1175. s->cmdlist->next ? "s" : "", commands,
  1176. gmt, s->reason ? s->reason : "no reason");
  1177.  
  1178. sendto_snomask(SNO_TKL, "*** %s", buf);
  1179. ircd_log(LOG_TKL, "%s", buf);
  1180.  
  1181. /* Delete cmdshun entry & temporary stuff */
  1182. del_cmdshun(s);
  1183. del_tmp_data();
  1184.  
  1185. sendto_serv_butone_token(NULL, parv[PFrom],
  1186. MSG_CMDSHUNFWD, TOK_CMDSHUNFWD,
  1187. "- %s %s %s %s",
  1188. usermask, hostmask, commands, parv[PSetBy]);
  1189.  
  1190. break;
  1191. }
  1192. }
  1193.  
  1194. return 0;
  1195. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement