m_rtkl.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* Copyright (C) All Rights Reserved
  2. ** Written by Gottem <support@gottem.nl>
  3. ** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
  4. ** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
  5. */
  6. // One include for all cross-platform compatibility thangs
  7. #include "unrealircd.h"
  8. // Command strings
  9. #define MSG_RKLINE "RKLINE"
  10. #define MSG_RZLINE "RZLINE"
  11. // Register command functions
  12. CMD_FUNC(m_rkline);
  13. CMD_FUNC(m_rzline);
  14. // Quality fowod declarations
  15. static int dumpit(aClient *sptr, char **p);
  16. int m_rtkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char *cmd, char *operperm);
  17. int hook_tkl_add(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]);
  18. int hook_tkl_del(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]);
  19. int hook_tkl_main(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[], char flag);
  20. // Muh globals
  21. static ModuleInfo *rtklMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  22. Command *rklineCmd, *rzlineCmd; // Pointers to the commands we're gonna add
  23. Hook *hookTklAdd, *hookTklDel; // Pointers for TKL ADD/DEL hewks ;]
  24. // Help string in case someone does just /RKLINE
  25. static char *rtklhelp[] = {
  26. /* Special characters:
  27. ** \002 = bold -- \x02
  28. ** \037 = underlined -- \x1F
  29. */
  30. "*** \002Help on /RKLINE and /RZLINE\002 ***",
  31. "Both of those commands allow you to remove \037local\037",
  32. "K:Lines and Z:Lines from remote servers. This might be useful",
  33. "if for example a spamfilter triggered a K:Line and you want to",
  34. "remove the ban without reconnecting.",
  35. " ",
  36. "Syntax:",
  37. " \002/RKLINE\002 \037server\037 \037[-]user@host\037 [duration] [reason]",
  38. " \002/RZLINE\002 \037server\037 \037[-]user@IP\037 [duration] [reason]",
  39. " Everything after the \037server\037 arg is the same stuff",
  40. "as for regular K/Z:Lines.",
  41. " ",
  42. "Examples:",
  43. " \002/RKLINE myleaf.dom.tld guest*@* 0 na d00d\002",
  44. " \002/RZLINE myleaf.dom.tld guest*@* 0 na d00d\002",
  45. " Place a ban on all guests",
  46. " \002/RKLINE myleaf.dom.tld -guest*@*\002",
  47. " Remove the same ban",
  48. " ",
  49. "There's no function for listing them in this module, as you can already use",
  50. "\002/stats K <server>\002 for that.",
  51. NULL
  52. };
  53. // Dat dere module header
  54. ModuleHeader MOD_HEADER(m_rtkl) = {
  55. "m_rtkl", // Module name
  56. "$Id: v1.01 2019/01/24 Gottem$", // Version
  57. "Allows privileged opers to remove remote servers' local K/Z:Lines", // Description
  58. "3.2-b8-1", // Modversion, not sure wat do
  59. NULL
  60. };
  61. // Initialisation routine (register hooks, commands and modes or create structs etc)
  62. MOD_INIT(m_rtkl) {
  63. // If command already exists for some reason, bail out
  64. if(CommandExists(MSG_RKLINE)) {
  65. config_error("Command %s already exists", MSG_RKLINE);
  66. return MOD_FAILED;
  67. }
  68. if(CommandExists(MSG_RZLINE)) {
  69. config_error("Command %s already exists", MSG_RZLINE);
  70. return MOD_FAILED;
  71. }
  72. hookTklAdd = HookAdd(modinfo->handle, HOOKTYPE_TKL_ADD, 0, hook_tkl_add);
  73. hookTklDel = HookAdd(modinfo->handle, HOOKTYPE_TKL_DEL, 0, hook_tkl_del);
  74. // Only users may use this module's commands =]
  75. rklineCmd = CommandAdd(modinfo->handle, MSG_RKLINE, m_rkline, MAXPARA, M_USER);
  76. rzlineCmd = CommandAdd(modinfo->handle, MSG_RZLINE, m_rzline, MAXPARA, M_USER);
  77. rtklMI = modinfo; // Store module info yo
  78. return MOD_SUCCESS; // Let MOD_LOAD handle errors
  79. }
  80. // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
  81. MOD_LOAD(m_rtkl) {
  82. // Did the module throw an error during initialisation, or is one of the commands/hewks null even?
  83. if(ModuleGetError(rtklMI->handle) != MODERR_NOERROR || !rklineCmd || !rzlineCmd || !hookTklAdd || !hookTklDel) {
  84. // Display error string kek
  85. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_rtkl).name, ModuleGetErrorStr(rtklMI->handle));
  86. return MOD_FAILED; // No good
  87. }
  88. return MOD_SUCCESS; // We good
  89. }
  90. // Called on unload/rehash obv
  91. MOD_UNLOAD(m_rtkl) {
  92. return MOD_SUCCESS; // We good
  93. }
  94. // Dump a NULL-terminated array of strings to user sptr using the numeric rplnum, and then return 0 (taken from DarkFire IRCd)
  95. static int dumpit(aClient *sptr, char **p) {
  96. if(IsServer(sptr)) // Bail out early and silently if it's a server =]
  97. return 0;
  98. for(; *p != NULL; p++)
  99. sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p);
  100. // Let user take 8 seconds to read it
  101. sptr->local->since += 8;
  102. return 0;
  103. }
  104. CMD_FUNC(m_rkline) {
  105. /* Gets args: aClient *cptr, aClient *sptr, int parc, char *parv[]
  106. **
  107. ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
  108. ** sptr: Pointer to user executing command
  109. ** parc: Amount of arguments (also includes the command in the count)
  110. ** parv: Contains the actual args, first one starts at parv[1]
  111. **
  112. ** So "RKLINE test" would result in parc = 2 and parv[1] = "test"
  113. ** Also, parv[0] seems to always be NULL, so better not rely on it fam
  114. */
  115. return m_rtkl_main(cptr, sptr, parc, parv, MSG_RKLINE, "tkl:kline");
  116. }
  117. CMD_FUNC(m_rzline) {
  118. return m_rtkl_main(cptr, sptr, parc, parv, MSG_RZLINE, "tkl:zline");
  119. }
  120. int m_rtkl_main(aClient *cptr, aClient *sptr, int parc, char *parv[], char *cmd, char *operperm) {
  121. int i; // Iterator to shift parv in a bit ;]
  122. aClient *srv; // Server pointer kek
  123. char buf[BUFSIZE];
  124. if(!MyClient(sptr) || !IsPerson(sptr) || IsULine(sptr)) // Only regular local users (well, opers) can use this =]
  125. return 0;
  126. if(!IsOper(sptr) || !ValidatePermissionsForPath(operperm, sptr, NULL, NULL, NULL)) {
  127. sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name); // Not gonna happen
  128. return -1; // "Critical" error
  129. }
  130. if(BadPtr(parv[1]) || !stricmp(parv[1], "help") || !stricmp(parv[1], "halp")) // If first argument is a bad pointer or "help", don't proceed
  131. return dumpit(sptr, rtklhelp); // Return help string instead
  132. // Need at least 2 args before we pass it on to the server
  133. if(BadPtr(parv[2])) {
  134. sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, MSG_RKLINE); // Show "needs more parameters" error string
  135. return -1; // "Critical" error
  136. }
  137. if(!(srv = find_server(parv[1], NULL))) {
  138. sendnotice(sptr, "[m_rtkl] Invalid server name: %s (server not found)", parv[1]);
  139. return -1; // "Critical" error
  140. }
  141. memset(buf, '\0', BUFSIZE);
  142. for(i = 2; i < parc && parv[i]; i++) {
  143. if(i == 2) {
  144. ircsnprintf(buf, BUFSIZE, "%s", parv[i]);
  145. if(*parv[i] == '-') // No need to process any more args for deletions =]
  146. break;
  147. }
  148. else
  149. ircsnprintf(buf, BUFSIZE, "%s %s", buf, parv[i]);
  150. }
  151. sendto_snomask_global(SNO_TKL, "*** [m_rtkl] %s (%s@%s) used %s for server %s [args = %s]", sptr->name, sptr->user->username, sptr->user->realhost, cmd, parv[1], buf);
  152. *cmd++; // Skip the R in RKLINE etc =]
  153. sendto_one(srv, ":%s %s %s", sptr->name, cmd, buf);
  154. return 0; // All good
  155. }
  156. int hook_tkl_add(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]) {
  157. return hook_tkl_main(cptr, sptr, tkl, parc, parv, '+');
  158. }
  159. int hook_tkl_del(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[]) {
  160. return hook_tkl_main(cptr, sptr, tkl, parc, parv, '-');
  161. }
  162. int hook_tkl_main(aClient *cptr, aClient *sptr, aTKline *tkl, int parc, char *parv[], char flag) {
  163. char *p, *nick; // To get just the nick bit from the full user!ident@host mask lol
  164. aClient *acptr; // Pointer to the client using that nick
  165. if(sptr || MyClient(sptr) || parc < 6 || BadPtr(parv[5]) || !strchr("zk", *parv[2])) // Only respond to non-local clients and _local_ K/Z:Lines ;];]
  166. return 0; // kbye
  167. nick = strdup(parv[5]);
  168. if(!(p = strrchr(nick, '!'))) // If for some reason the arg is malformed (expecting user!ident@host here), bail the fuck out
  169. return 0;
  170. *p = '\0';
  171. if(!(acptr = find_person(nick, NULL))) // Validate target nick
  172. return 0; // Lolnope
  173. char buf[BUFSIZE]; // Outbut buffer lol
  174. char *timeret; // Time buffer yo
  175. memset(buf, '\0', BUFSIZE); // Just in caes lol
  176. // Let's build that fucking message
  177. ircsnprintf(buf, BUFSIZE, "[m_rtkl] %s", (flag == '+' ? "Added" : "Removed")); // Let's start with the "direction"
  178. // Check if the X:Line is permanent
  179. if(tkl->expire_at == 0)
  180. ircsnprintf(buf, BUFSIZE, "%s permanent", buf); // Append that shit
  181. // Always mention the X:Line type and the user@host mask
  182. ircsnprintf(buf, BUFSIZE, "%s (local) %c:Line for %s@%s", buf, toupper(*parv[2]), tkl->usermask, tkl->hostmask);
  183. // If deleting only...
  184. if(flag == '-') {
  185. timeret = asctime(gmtime((TS *)&tkl->set_at)); // ...get original "set at" time as a char * ...
  186. ircsnprintf(buf, BUFSIZE, "%s set by %s at %s GMT", buf, tkl->setby, timeret); // ...as well as "setby", then append that shit
  187. }
  188. if(tkl->expire_at > 0) { // If the X:Line would've expired (deleting) or will expire at some point (adding) ...
  189. timeret = asctime(gmtime((TS *)&tkl->expire_at)); // ... get that shit too as a char * ...
  190. ircsnprintf(buf, BUFSIZE, "%s (to expire at %s GMT, reason: ", buf, timeret); // ...and append em w/o setby (is not necessary when adding)
  191. }
  192. else // Permanent X:Line, no need for expiration field
  193. ircsnprintf(buf, BUFSIZE, "%s (reason: ", buf); // Open parenthesis group thingy for da raisin
  194. ircsnprintf(buf, BUFSIZE, "%s %s)", buf, tkl->reason); // Actual reason gets appended here lol, w/ closing parenthesis
  195. sendnotice(acptr, buf); // Send that fucking abomination
  196. return 0; // Can't do shit anyways =]
  197. }