m_bancheck_access.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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 to override
  9. #define OVR_MODE "MODE"
  10. #define MYCONF "bancheck_access_notif"
  11. // Quality fowod declarations
  12. int bancheck_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
  13. int bancheck_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
  14. int bancheck_rehash(void);
  15. static int bancheck_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
  16. // Muh globals
  17. static ModuleInfo *bancheckMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  18. Cmdoverride *bancheckOVR; // Pointer to the override we're gonna add
  19. int showNotif = 0; // Display message in case of disallowed masks
  20. // Dat dere module header
  21. ModuleHeader MOD_HEADER(m_bancheck_access) = {
  22. "m_bancheck_access", // Module name
  23. "$Id: v1.12 2019/01/24 Gottem$", // Version
  24. "Prevents people who have +o or higher from getting banned, unless done by people with +a/+q or opers", // Description
  25. "3.2-b8-1", // Modversion, not sure wat do
  26. NULL
  27. };
  28. // Configuration testing-related hewks go in testing phase obv
  29. MOD_TEST(m_bancheck_access) {
  30. // We have our own config block so we need to checkem config obv m9
  31. // Priorities don't really matter here
  32. HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, bancheck_configtest);
  33. return MOD_SUCCESS;
  34. }
  35. // Initialisation routine (register hooks, commands and modes or create structs etc)
  36. MOD_INIT(m_bancheck_access) {
  37. bancheckMI = modinfo; // Store module info yo
  38. HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, bancheck_configrun);
  39. HookAdd(modinfo->handle, HOOKTYPE_REHASH, 0, bancheck_rehash);
  40. return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
  41. }
  42. // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
  43. MOD_LOAD(m_bancheck_access) {
  44. bancheckOVR = CmdoverrideAdd(bancheckMI->handle, OVR_MODE, bancheck_override); // Attempt to add command override
  45. // Did the module throw an error when adding override(s), or is bancheckOVR null even?
  46. if(ModuleGetError(bancheckMI->handle) != MODERR_NOERROR || !bancheckOVR) {
  47. // Display error string kek
  48. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_bancheck_access).name, ModuleGetErrorStr(bancheckMI->handle));
  49. return MOD_FAILED; // No good
  50. }
  51. return MOD_SUCCESS; // We good
  52. }
  53. // Called on unload/rehash obv
  54. MOD_UNLOAD(m_bancheck_access) {
  55. showNotif = 0;
  56. return MOD_SUCCESS; // We good
  57. }
  58. int bancheck_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
  59. int errors = 0; // Error count
  60. // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  61. if(type != CONFIG_MAIN)
  62. return 0; // Returning 0 means idgaf bout dis
  63. // Check for valid config entries first
  64. if(!ce || !ce->ce_varname)
  65. return 0;
  66. // If it isn't our directive, idc
  67. if(strcmp(ce->ce_varname, MYCONF))
  68. return 0;
  69. if(!ce->ce_vardata || (strcmp(ce->ce_vardata, "0") && strcmp(ce->ce_vardata, "1"))) {
  70. config_error("%s:%i: %s must be either 0 or 1 fam", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, MYCONF);
  71. errors++; // Increment err0r count fam
  72. }
  73. *errs = errors;
  74. // Returning 1 means "all good", -1 means we shat our panties
  75. return errors ? -1 : 1;
  76. }
  77. // "Run" the config (everything should be valid at this point)
  78. int bancheck_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
  79. // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  80. if(type != CONFIG_MAIN)
  81. return 0; // Returning 0 means idgaf bout dis
  82. // Check for valid config entries first
  83. if(!ce || !ce->ce_varname)
  84. return 0;
  85. // If it isn't our directive, idc
  86. if(strcmp(ce->ce_varname, MYCONF))
  87. return 0;
  88. showNotif = atoi(ce->ce_vardata);
  89. return 1; // We good
  90. }
  91. int bancheck_rehash(void) {
  92. showNotif = 0;
  93. return HOOK_CONTINUE;
  94. }
  95. // Now for the actual override
  96. static int bancheck_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
  97. /* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
  98. **
  99. ** ovr: Pointer to the override we're attached to
  100. ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
  101. ** sptr: Pointer to user executing command
  102. ** parc: Amount of arguments (also includes the command in the count)
  103. ** parv: Contains the actual args, first one starts at parv[1]
  104. **
  105. ** So "MODE test" would result in parc = 2 and parv[1] = "test"
  106. ** Also, parv[0] seems to always be NULL, so better not rely on it fam
  107. */
  108. aChannel *chptr; // Channel pointer
  109. aClient *acptr; // Ban target
  110. int fc, mc; // Flag count and mask count respectively
  111. int i, j; // Just s0em iterators fam
  112. int stripped; // Count 'em
  113. int skip[MAXPARA + 1]; // Skippem
  114. int newparc; // Keep track of proper param count
  115. int breakem, cont; // So we can break the outer for loop
  116. char newflags[MODEBUFLEN + 3]; // Store cleaned up flags
  117. char *newparv[MAXPARA + 1]; // Ditto for masks etc
  118. char curdir; // Current direction (add/del etc)
  119. char *tmp; // Store a "raw" mask
  120. char *tmpmask; // After cleaning it
  121. char *banmask; // Have to store it agen so it doesn't get fukt lol (sheeeeeit)
  122. char *umask, *realumask; // Full nick!ident@host masks for users yo
  123. long flags; // User flags in regards to channel list m0des lol
  124. if(!MyConnect(sptr) || IsOper(sptr) || IsServer(sptr) || IsMe(sptr) || BadPtr(parv[1]) || BadPtr(parv[2]) || BadPtr(parv[3]) ||
  125. !(chptr = find_channel(parv[1], NULL)) || !is_skochanop(sptr, chptr) || is_chanowner(sptr, chptr) || is_chanprot(sptr, chptr))
  126. return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
  127. newparc = parc; // Initialise new param count
  128. fc = mc = 0; // Ditto for flag/mask counters
  129. curdir = 0; // Set "direction" (+ or - to NULL imo)
  130. stripped = 0;
  131. newparv[0] = parv[0];
  132. newparv[1] = parv[1];
  133. memset(newflags, '\0', sizeof(newflags)); // Set 'em
  134. for(i = 0; i < parc; i++)
  135. skip[i] = 0; // Set default so the loop doesn't fuck it up as it goes along
  136. // Loop over every mode flag
  137. for(i = 0; i < strlen(parv[2]); i++) {
  138. char c = parv[2][i]; // Current flag lol, can be '+', '-' or any lettur
  139. tmp = tmpmask = banmask = umask = NULL; // Aye elemao
  140. flags = 0L;
  141. breakem = cont = 0;
  142. // Check if we need to verify somethang
  143. switch(c) {
  144. // Do shit for bans only
  145. case 'b': // Ban
  146. j = 3 + mc++; // In parv[] the first mask is found at index 3
  147. // Finito?
  148. if(parc <= j || BadPtr(parv[j])) {
  149. breakem = 1;
  150. break;
  151. }
  152. // Jus' checkin' if it's good fam
  153. if(curdir == '+') {
  154. tmp = strdup(parv[j]); // Dup 'em, seems to be necessary cuz parv[j] gets fucked otherwise
  155. tmpmask = clean_ban_mask(tmp, MODE_ADD, cptr); // Turns "+b *" into "+b *!*@*" so we can easily check bel0w =]
  156. free(tmp);
  157. // On error getting above, just let CallCmdoverride handle it
  158. if(!tmpmask)
  159. break;
  160. banmask = strdup(tmpmask);
  161. // Iter8 em
  162. Member *memb = NULL; // Channel members thingy =]
  163. for(memb = chptr->members; memb; memb = memb->next) {
  164. acptr = memb->cptr; // Ban target
  165. if(acptr) { // Sanity check lol
  166. flags = get_access(acptr, chptr); // Get axx flags yo
  167. umask = strdup(make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr))); // Get full nick!ident@host mask imo tbh
  168. realumask = strdup(make_nick_user_host(acptr->name, acptr->user->username, acptr->user->cloakedhost)); // Get it with the "real" host imo
  169. if(umask && flags & (CHFL_CHANOP | CHFL_CHANPROT | CHFL_CHANOWNER) && (!match(banmask, umask) || !match(banmask, realumask))) { // Check if banmask matches it for +o and highur
  170. skip[j] = 1; // Skip it lol
  171. newparc--; // Decrement parc so Unreal doesn't shit itself =]
  172. cont = 1;
  173. stripped++;
  174. }
  175. free(umask);
  176. free(realumask);
  177. }
  178. if(cont)
  179. break;
  180. }
  181. free(banmask);
  182. }
  183. break;
  184. // Some other modes may have an argument t00
  185. case 'e': // Ban exempts
  186. case 'I': // Invite exempts
  187. case 'v': // Access mode, voice
  188. case 'h': // Hops
  189. case 'o': // Ops
  190. case 'a': // Chanadmin
  191. case 'q': // Chanowner
  192. case 'f': // Floodprot
  193. case 'F': // m_forward, which despite being 3rd partay we'll take into account
  194. case 'k': // Channel key
  195. case 'L': // Channel link
  196. case 'l': // Limit
  197. mc++; // Simply increment the mask counter so we pass over it
  198. newparc++;
  199. break;
  200. // Directionals yo
  201. case '+':
  202. case '-':
  203. curdir = c;
  204. break;
  205. // Fuck errythang else lol
  206. default:
  207. break;
  208. }
  209. if(breakem)
  210. break;
  211. if(cont)
  212. continue;
  213. newflags[fc++] = c; // Seems to be a sane mode, append it
  214. }
  215. // Now checkem masks, we have to do this separately so we can reliably get the (proper) corresponding mask
  216. for(i = 3, j = 3; i < parc && !BadPtr(parv[i]); i++) {
  217. if(skip[i] || !strlen(parv[i]))
  218. continue;
  219. // Now store this mask =]
  220. newparv[j++] = parv[i];
  221. }
  222. if(stripped && showNotif)
  223. sendto_one(sptr, ":%s NOTICE %s :[BA] Stripped %d mask(s) (disallowed)", me.name, chptr->chname, stripped);
  224. // If we now have no masks but we had them before, return silently =]
  225. if(newparc <= 3 && newparc < parc)
  226. return 0;
  227. // Heck 'em
  228. newparv[2] = newflags;
  229. newparv[newparc] = NULL;
  230. return CallCmdoverride(ovr, cptr, sptr, newparc, newparv); // Run original function yo
  231. }