Our server pr0vider carried out maintenance on 15 January 2020 but it corrupted some files in the process. If you notice anything out of the ordinary (partial files, pages not loading, that kind of shit) then let us know at:

m_timedbans.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #define TIMEDBANS_EXTCHAR 't' // Extended ban character (e.g. +b ~t: etc)
  9. #define BACKPORT (UNREAL_VERSION_GENERATION == 4 && UNREAL_VERSION_MAJOR == 0 && UNREAL_VERSION_MINOR <= 12)
  10. // Quality fowod declarations
  11. #if BACKPORT
  12. extern char *extban_conv_param_nuh(char *para); // Trivial bug where this function isn't marked extern in include/h.h (bug ID: 4975)
  13. #endif
  14. Ban *find_timedban(aChannel *chptr, char *mask);
  15. int timedbans_extban_isok(aClient *sptr, aChannel *chptr, char *param, int checkt, int what, int what2);
  16. int timedbans_isbanned(aClient *sptr, aChannel *chptr, char *ban, int chktype);
  17. EVENT(timedbans_event); // For expiring that shit fam
  18. void expirem(int count, char *modes[], aChannel *chptr);
  19. // Muh globals
  20. static ModuleInfo *timedbansMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  21. Extban *timedExtban;
  22. // Dat dere module header
  23. ModuleHeader MOD_HEADER(m_timedbans) = {
  24. "m_timedbans", // Module name
  25. "$Id: v1.02 2017/11/26 Gottem$", // Version
  26. "Adds extban ~t for auto-expiring bans", // Description
  27. "3.2-b8-1", // Modversion, not sure wat do
  28. NULL
  29. };
  30. // Initialisation routine (register hooks, commands and modes or create structs etc)
  31. MOD_INIT(m_timedbans) {
  32. timedbansMI = modinfo;
  33. // Request that extban y0
  34. ExtbanInfo req;
  35. memset(&req, 0, sizeof(ExtbanInfo));
  36. req.flag = TIMEDBANS_EXTCHAR; // Required ;]
  37. req.is_ok = timedbans_extban_isok; // Optional, but we need to check the expiration field more closely ;];]
  38. req.conv_param = extban_conv_param_nuh; // Required, simply use built-in function to turn ~t:60:ham into ~t:60:ham!*@* etc ;];];]
  39. req.is_banned = timedbans_isbanned; // Required, checks if user matches een bannerino ;];];];]
  40. if(!(timedExtban = ExtbanAdd(modinfo->handle, req))) { // Error while adding (flag exists?)
  41. config_error("[%s] Adding extban ~%c failed", MOD_HEADER(m_timedbans).name, TIMEDBANS_EXTCHAR);
  42. return MOD_FAILED;
  43. }
  44. return MOD_SUCCESS; // Let MOD_LOAD handle errors
  45. }
  46. // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
  47. MOD_LOAD(m_timedbans) {
  48. EventAddEx(timedbansMI->handle, "timedbans_event", 15, 0, timedbans_event, NULL); // Run event every 15 seconds, indefinitely and without any additional data (void *NULL etc)
  49. // Did the module throw an error during initialisation?
  50. if(ModuleGetError(timedbansMI->handle) != MODERR_NOERROR) {
  51. // Display error string kek
  52. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_timedbans).name, ModuleGetErrorStr(timedbansMI->handle));
  53. return MOD_FAILED; // No good
  54. }
  55. return MOD_SUCCESS; // We good
  56. }
  57. // Called on unload/rehash obv
  58. MOD_UNLOAD(m_timedbans) {
  59. return MOD_SUCCESS; // We good
  60. }
  61. Ban *find_timedban(aChannel *chptr, char *mask) {
  62. Ban *ban; // Pointer to ban entry lol
  63. char *bmask; //
  64. for(ban = chptr->banlist; ban; ban=ban->next) {
  65. if((ban->banstr[0] == '~') && (ban->banstr[1] == TIMEDBANS_EXTCHAR) && (ban->banstr[2] == ':')) { // Must start with ~t: etc ;];]
  66. if(strlen(ban->banstr) < 5) // Sanity check ("~t:" plus ":" and at least one char in expiration (so minimum of 5 lol)
  67. continue;
  68. bmask = strchr(ban->banstr + 3, ':') + 1;
  69. if(bmask && !stricmp(bmask, mask)) // Compare stored mask to new one (w/o taking into account the expiration) ;]
  70. return ban;
  71. }
  72. }
  73. return NULL;
  74. }
  75. // Validate param =]
  76. int timedbans_extban_isok(aClient *sptr, aChannel *chptr, char *param, int checkt, int what, int what2) {
  77. char *mask, *ep; // Pointers to store the mask bit and expiration field
  78. long expiry = 0; // Expiration as a long for checkin' em durations =]
  79. Ban *ban; // Ban entry y0
  80. if((what == MODE_ADD) && (what2 != EXBTYPE_BAN) && MyClient(sptr)) // Only works w/ +b ;];]
  81. return EX_DENY;
  82. if((what == MODE_ADD) && (checkt == EXBCHK_PARAM) && MyClient(sptr)) { // Check parameter sanity bruh
  83. if(match("~?:*:*!*@*", param) || strchr(param, ' ') != NULL) { // Cannot contain spaces imo tbh famlamla (should never happen but let's checkem anywaysz)
  84. sendto_one(sptr, ":%s NOTICE %s :[timedbans] Ban format is ~%c:\037expiration\037:\002banmask\002 (example: \002~%c:5m:*!*@*.some.isp\002)", me.name, chptr->chname, TIMEDBANS_EXTCHAR, TIMEDBANS_EXTCHAR);
  85. return EX_DENY; // D E N I E D
  86. }
  87. char buf[BUFSIZE]; // Cuz strtok() fucks ur shit up fam
  88. snprintf(buf, sizeof(buf), "%s", param + 3); // Copy that shit, get rid of ~t: first
  89. // Second token is the expiration fielderino
  90. ep = strtok(buf, ":");
  91. if(ep) // Sanity checc
  92. expiry = config_checkval(ep, CFG_TIME); // Converts that shit to a long yo
  93. // The rest is the actual banmask =]
  94. mask = strtok(NULL, "");
  95. if(!ep || !mask) // Should be handled by the match() at the top of muh parent if, but just in case yo
  96. return EX_DENY; // N O P E
  97. if(!expiry || expiry % 60 != 0) { // So the EVENT doesn't have to check every fucking second
  98. sendto_one(sptr, ":%s NOTICE %s :[timedbans] The resolution for the expiration time is 1 minute, valid examples are: \037120\037 (2 minutes written in seconds), \0375m\037 and \0372h30m\037", me.name, chptr->chname);
  99. return EX_DENY; // R E K T
  100. }
  101. if((ban = find_timedban(chptr, mask))) { // Gottem alredy?
  102. sendto_one(sptr, ":%s NOTICE %s :[timedbans] A similar timed ban was already found: %s", me.name, chptr->chname, ban->banstr);
  103. return EX_DENY; // R I P
  104. }
  105. }
  106. return EX_ALLOW; // Ayy we good FAM
  107. }
  108. // Check if a user should be banned
  109. int timedbans_isbanned(aClient *sptr, aChannel *chptr, char *ban, int chktype) {
  110. char *nuhost, *nurhost, *nuip;
  111. char *mask; // Only need the mask bit here imo tbh
  112. int ret; // St0re return value cuz we need to free some shit =]
  113. if(strlen(ban) < 5) // Sanity check ("~t:" plus ":" and at least one char in expiration (so minimum of 5 lol)
  114. return 0;
  115. mask = strchr(ban + 3, ':') + 1;
  116. if(!mask) // r u insaiyan?
  117. return 0; // y-yes
  118. nuhost = strdup(make_nick_user_host(sptr->name, sptr->user->username, GetHost(sptr)));
  119. nurhost = strdup(make_nick_user_host(sptr->name, sptr->user->username, sptr->user->realhost));
  120. nuip = strdup(make_nick_user_host(sptr->name, sptr->user->username, GetIP(sptr)));
  121. ret = 0; // 0 means we g00d
  122. if(!match(mask, nuhost) || !match(mask, nurhost) || !match(mask, nuip)) // Checkem
  123. ret = 1; // b& and v&
  124. free(nuhost);
  125. free(nurhost);
  126. free(nuip);
  127. return ret;
  128. }
  129. EVENT(timedbans_event) {
  130. // Gotta check all channels for ~t: extbans fam
  131. int bcount = 0; // We might do -bbbb instead of one -b for every fucking mask ;]
  132. size_t blen = 0;
  133. char *multi[8] = { 0 }; // Buffer 4 dat ^
  134. char *ep; // To grab expiration from the banstr
  135. long expiry = 0; // Need it as a long tho ;]
  136. TS tiem = TStime(); // Get current time
  137. aChannel *chptr; // Channel iter8or m8
  138. Ban *ban, *nban; // Ban iter8ors m8
  139. for(chptr = channel; chptr; chptr = chptr->nextch) { // Loop over all channels...
  140. for(ban = chptr->banlist; ban; ban = nban) { // ...and their banlists
  141. nban = ban->next; // So our loop doesn't go ripperoni
  142. if((ban->banstr[0] == '~') && (ban->banstr[1] == TIMEDBANS_EXTCHAR) && (ban->banstr[2] == ':')) { // Must start with ~t: etc ;];]
  143. size_t elen = strlen(ban->banstr + 3) - strlen(strchr(ban->banstr + 3, ':')); // Only interested in the expiration field hur ;]
  144. if(!elen) // Sanity cheqq lol
  145. continue; // Gtfo
  146. ep = malloc(elen + 1); // + nullbyet ofc
  147. memcpy(ep, &ban->banstr[3], elen); // Copy that shit =]
  148. ep[elen] = '\0'; // Ayy
  149. if(strlen(ep)) // Sanity checc
  150. expiry = config_checkval(ep, CFG_TIME); // Converts that shit to a long yo
  151. free(ep);
  152. if(tiem >= ban->when + expiry) { // Should expire =]]
  153. bcount++;
  154. blen += strlen(ban->banstr);
  155. multi[bcount - 1] = ban->banstr;
  156. }
  157. if(bcount >= 8 || blen >= 200) { // Some masks may be lengthy yo, so let's keep it to 8 per line or 200 chars max =]
  158. expirem(bcount, multi, chptr); // Actually expire them
  159. blen = bcount = 0; // Reset counters imo
  160. }
  161. }
  162. }
  163. if(bcount && multi[0]) { // The loop may not have hit the per-line limit, so "flush" that shit here lol
  164. expirem(bcount, multi, chptr);
  165. blen = bcount = 0;
  166. }
  167. }
  168. }
  169. void expirem(int count, char *modes[], aChannel *chptr) {
  170. char flags[MAXMODEPARAMS + 1]; // Includes nullbyet lel
  171. int i; // Iter8or lol
  172. int parc = 3 + count; // 3 "base" params plus the dynamic counter = total params =]
  173. char *parv[MAXPARA + 1]; // Also dat array fam (need to end w/ NULL etc, so + 1)
  174. flags[0] = '-'; // Flags shud begin with '-' obv
  175. for(i = 1; i <= count; i++) { // Now use the counter to loop that shit
  176. flags[i] = 'b';
  177. if(modes[i - 1])
  178. parv[2 + i] = modes[i - 1]; // e.g. i = 1, so parv[3] = modes[0]
  179. }
  180. flags[i] = '\0'; // May be wise to termin8 em yo
  181. parv[0] = NULL; // First "base" param is always NULL
  182. parv[1] = chptr->chname; // Followed by chanul
  183. parv[2] = flags; // And flags
  184. parv[parc] = NULL; // Also finish w/ NULL
  185. do_mode(chptr, &me, &me, parc - 2, parv + 2, TStime(), 0); // Call internal command so it clears that shit from memory too (also refresh timestamp here) ;];]
  186. for(i = 0; i < count; i++) // Clearasil fam
  187. modes[i] = NULL;
  188. }