SHARE
TWEET

Untitled

a guest Jan 24th, 2016 185 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top