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_allowctcp_opers.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. // Hooktype to use
  9. #define MYHEWK HOOKTYPE_PRE_USERMSG
  10. // Muh macros
  11. #define IsMDErr(x, y, z) \
  12. do { \
  13. if(!(x)) { \
  14. config_error("A critical error occurred when registering ModData for %s: %s", MOD_HEADER(y).name, ModuleGetErrorStr((z)->handle)); \
  15. return MOD_FAILED; \
  16. } \
  17. } while(0)
  18. #define BACKPORT_CONNECTTIMEOUT (UNREAL_VERSION_GENERATION == 4 && UNREAL_VERSION_MAJOR == 0 && UNREAL_VERSION_MINOR <= 15)
  19. #define BACKPORT (UNREAL_VERSION_GENERATION == 4 && UNREAL_VERSION_MAJOR == 0 && UNREAL_VERSION_MINOR < 12)
  20. // Big hecks go here
  21. typedef struct t_ctcpOverride cOverride;
  22. struct t_ctcpOverride {
  23. cOverride *next, *prev;
  24. char *uid;
  25. time_t when;
  26. };
  27. // Quality fowod declarations
  28. char *allowctcp_opers_preusermsg(aClient *sptr, aClient *to, char *text, int notice);
  29. void override_md_free(ModData *md);
  30. void check_stale_overrides(aClient *sptr);
  31. cOverride *match_override(aClient *sptr, char *uid);
  32. void add_override(aClient *sptr, aClient *to);
  33. void delete_override(aClient *sptr, cOverride *covr);
  34. void free_override(cOverride *covr);
  35. static int IsACTCP(char *s);
  36. #if BACKPORT
  37. long find_user_mode(char flag);
  38. int has_user_mode(aClient *acptr, char mode);
  39. #endif
  40. // Muh globals
  41. ModDataInfo *COvrMDI; // To store some shit with the user's aClient pointur ;]
  42. static ModuleInfo *allowctcp_opersMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  43. Hook *preUMsgHook = NULL;
  44. // Dat dere module header
  45. ModuleHeader MOD_HEADER(m_allowctcp_opers) = {
  46. "m_allowctcp_opers", // Module name
  47. "$Id: v1.11 2017/11/11 Gottem$", // Version
  48. "Allows opers to override someone's umode +T (noctcp)", // Description
  49. "3.2-b8-1", // Modversion, not sure wat do
  50. NULL
  51. };
  52. // Initialisation routine (register hooks, commands and modes or create structs etc)
  53. MOD_INIT(m_allowctcp_opers) {
  54. preUMsgHook = HookAddPChar(modinfo->handle, MYHEWK, -1, allowctcp_opers_preusermsg); // Add a hook with higher priority than noctcp_preusermsg()
  55. // Request moddata for storing the actual overrides
  56. ModDataInfo mreq;
  57. memset(&mreq, 0, sizeof(mreq));
  58. mreq.type = MODDATATYPE_CLIENT; // Apply to users only (CLIENT actually includes servers but we'll disregard that here =])
  59. mreq.name = "allowctcp_opers"; // Name it
  60. mreq.free = override_md_free; // Function to free 'em
  61. COvrMDI = ModDataAdd(modinfo->handle, mreq);
  62. IsMDErr(COvrMDI, m_allowctcp_opers, modinfo);
  63. allowctcp_opersMI = modinfo; // Store module info yo
  64. return MOD_SUCCESS; // Let MOD_LOAD handle errors and shyte
  65. }
  66. // Actually load the module here
  67. MOD_LOAD(m_allowctcp_opers) {
  68. // Check if module handle is available, also check for hooks that weren't added for some raisin
  69. if(ModuleGetError(allowctcp_opersMI->handle) != MODERR_NOERROR || !preUMsgHook) {
  70. // Display error string kek
  71. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_allowctcp_opers).name, ModuleGetErrorStr(allowctcp_opersMI->handle));
  72. return MOD_FAILED; // No good
  73. }
  74. return MOD_SUCCESS; // We good
  75. }
  76. // Called on unload/rehash obv
  77. MOD_UNLOAD(m_allowctcp_opers) {
  78. return MOD_SUCCESS; // We good
  79. }
  80. // Actual hewk function m8
  81. char *allowctcp_opers_preusermsg(aClient *sptr, aClient *to, char *text, int notice) {
  82. /* Arguments depend on hook type used obv
  83. **
  84. ** sptr: Pointer to user executing command
  85. ** to: Same sort of pointer to the target client
  86. ** text: Actual text obv
  87. ** notice: Was it a notice?
  88. */
  89. cOverride *covr = NULL; // To store the matching entry for een bit
  90. if(MyClient(sptr) && IsACTCP(text) && IsOper(sptr)) { // If an oper is sending a CTCP
  91. if(has_user_mode(sptr, 'T') && !IsOper(to)) { // If oper has +T themselves and target is not an oper (override is not necessary in that case ;])
  92. check_stale_overrides(sptr); // Ayyy lmao
  93. add_override(sptr, to); // Add override for the reply yo
  94. }
  95. if(has_user_mode(to, 'T')) { // Target has +T, so bypass that shit
  96. sendto_one(to, ":%s %s %s :%s", sptr->name, (notice ? "NOTICE" : "PRIVMSG"), to->name, text); // Dirty hack goes here lol
  97. return NULL; // Don't process other hooks (i.e. usermodes/noctcp)
  98. }
  99. return text; // No further action required
  100. }
  101. if(has_user_mode(to, 'T') && IsACTCP(text) && IsOper(to)) { // If an oper is receiving a CTCP reply but has +T also
  102. if(MyClient(sptr) && !MyClient(to)) { // Target is on different server, so bypass that shit
  103. sendto_one(to, ":%s %s %s :%s", sptr->name, (notice ? "NOTICE" : "PRIVMSG"), to->name, text); // Dirty hack goes here lol
  104. return NULL; // Don't process other hooks (i.e. usermodes/noctcp)
  105. }
  106. if(MyClient(to)) { // If the target is on our server
  107. check_stale_overrides(to); // Flush stale overrides first
  108. if(IsOper(sptr) || (covr = match_override(to, sptr->id))) { // Checkem override
  109. delete_override(to, covr); // Clear entry first lol
  110. if(MyClient(sptr)) //{ // Only need to bypass here if it's local2local client
  111. sendto_one(to, ":%s %s %s :%s", sptr->name, (notice ? "NOTICE" : "PRIVMSG"), to->name, text); // Ayyy we good
  112. }
  113. else { // No override found, unsolicited CTCP
  114. if(!notice)
  115. sendto_one(sptr, err_str(ERR_NOCTCP), me.name, sptr->name, to->name);
  116. return NULL; // Drop 'em
  117. }
  118. }
  119. }
  120. return text; // Process normally
  121. }
  122. void override_md_free(ModData *md) {
  123. if(md->ptr) { // r u insaiyan?
  124. cOverride *covrList, *covr, *next; // Sum iter8ors lol
  125. covrList = md->ptr; // Get pointur to head of teh list
  126. for(covr = covrList; covr; covr = next) { // Let's do all entries yo
  127. next = covr->next; // Get next entry in advance lol
  128. free_override(covr); // Free 'em imo
  129. }
  130. md->ptr = NULL; // Shit rip's if we don't kek
  131. }
  132. }
  133. void check_stale_overrides(aClient *sptr) {
  134. int ping; // Expiration time is the same as ping timeouts ;]
  135. cOverride *covrList, *covr, *next; // Sum iter8ors lol
  136. if(!sptr || !sptr->local) // r u insaiyan?
  137. return;
  138. if((covrList = moddata_client(sptr, COvrMDI).ptr)) { // One of the for loops MIGHT have cleared the entire list ;]
  139. #if BACKPORT_CONNECTTIMEOUT
  140. ping = (sptr->local->class ? sptr->local->class->pingfreq : CONNECTTIMEOUT);
  141. #else
  142. ping = (sptr->local->class ? sptr->local->class->pingfreq : iConf.handshake_timeout);
  143. #endif
  144. for(covr = covrList; covr; covr = next) { // Iterate em lol
  145. next = covr->next; // Next one imo
  146. if(ping > (TStime() - sptr->local->lasttime)) // Still good
  147. continue;
  148. // Doubly linked lists ftw yo
  149. if(covr->prev) // Is anything but the FIRST entry
  150. covr->prev->next = covr->next; // Previous entry should skip over dis one
  151. else { // Is the first entry
  152. moddata_client(sptr, COvrMDI).ptr = covr->next; // So make the moddata thingy point to the second one
  153. covrList = covr->next; // Really just for the if below (outside the lewp) =]
  154. }
  155. if(covr->next) // If anything but the LAST entry
  156. covr->next->prev = covr->prev; // Next entry should skip over dis one
  157. next = covr->next; // Next one imo
  158. free_override(covr); // Free 'em lol
  159. }
  160. if(!covrList) // We empty nao?
  161. moddata_client(sptr, COvrMDI).ptr = NULL; // Cuz inb4ripperoni
  162. }
  163. }
  164. cOverride *match_override(aClient *sptr, char *uid) {
  165. cOverride *covrList, *covr; // Some iter80rs lol
  166. if(!sptr || !uid || !uid[0]) // Sanity checks
  167. return NULL; // Lolnope
  168. if((covrList = moddata_client(sptr, COvrMDI).ptr)) { // Something st0red?
  169. for(covr = covrList; covr; covr = covr->next) { // Iter8 em
  170. if(!strcmp(covr->uid, uid)) // Checkem UID
  171. return covr; // Gottem
  172. }
  173. }
  174. return NULL; // Loln0pe
  175. }
  176. void add_override(aClient *sptr, aClient *to) {
  177. cOverride *covrList, *last, *cur; // Sum iterators famalam
  178. cOverride *covr; // New entry etc
  179. if(!sptr || !to || !to->id) // Sanity checks
  180. return; // kbai
  181. covr = (cOverride *)MyMallocEx(sizeof(cOverride)); // Alloc8 new entry pls
  182. covr->uid = strdup(to->id); // Set 'em UID
  183. covr->next = NULL; // Inb4rip
  184. covr->prev = NULL; // ditt0
  185. covr->when = TStime(); // Set timestamp lol
  186. if(!(covrList = moddata_client(sptr, COvrMDI).ptr)) { // One of the for loops MIGHT have cleared the entire list ;]
  187. moddata_client(sptr, COvrMDI).ptr = covr; // Necessary to properly st0re that shit
  188. return; // We good
  189. }
  190. // Dirty shit to get the last entry lol
  191. for(cur = covrList; cur; cur = cur->next)
  192. last = cur; // cur will end up pointing to NULL, so let's use the entry just before ;];]
  193. covr->prev = last; // The new entry's prev should point to the actual last entry
  194. last->next = covr; // And the last entry's next should be the new one obv =]
  195. }
  196. void delete_override(aClient *sptr, cOverride *covr) {
  197. cOverride *covrList, *last; // Sum iter8ors lol
  198. if(!covr || !covr->uid) // r u insaiyan?
  199. return;
  200. if(sptr && (covrList = moddata_client(sptr, COvrMDI).ptr)) { // One of the for loops MIGHT have cleared the entire list ;]
  201. for(last = covrList; last; last = last->next) { // Iterate em lol
  202. if(last == covr) { // We gottem match?
  203. // Doubly linked lists ftw yo
  204. if(last->prev) // Is anything but the FIRST entry
  205. last->prev->next = last->next; // Previous entry should skip over dis one
  206. else { // Is the first entry
  207. moddata_client(sptr, COvrMDI).ptr = last->next; // So make the moddata thingy point to the second one
  208. covrList = last->next; // Really just for the if below =]
  209. }
  210. if(last->next) // If anything but the LAST entry
  211. last->next->prev = last->prev; // Next entry should skip over dis one
  212. free_override(last); // Free 'em lol
  213. break; // Gtfo imo tbh famlammlmflma
  214. }
  215. }
  216. if(!covrList) // We empty nao?
  217. moddata_client(sptr, COvrMDI).ptr = NULL; // Cuz inb4ripperoni
  218. }
  219. }
  220. void free_override(cOverride *covr) {
  221. if(!covr) // LOLNOPE
  222. return;
  223. if(covr->uid) // Sanity cheqq lol
  224. free(covr->uid); // Free
  225. free(covr); // 'em
  226. }
  227. // Ripped from src/modules/usermodes/noctcp.c =]
  228. static int IsACTCP(char *s) {
  229. if(!s)
  230. return 0;
  231. if((*s == '\001') && strncmp(&s[1], "ACTION ", 7) && strncmp(&s[1], "DCC ", 4))
  232. return 1;
  233. return 0;
  234. }
  235. #if BACKPORT
  236. // Both functions were ripped from src/umodes.c in U4.0.12 =]
  237. long find_user_mode(char flag) {
  238. int i;
  239. for (i = 0; i < UMODETABLESZ; i++) {
  240. if((Usermode_Table[i].flag == flag) && !(Usermode_Table[i].unloaded))
  241. return Usermode_Table[i].mode;
  242. }
  243. return 0;
  244. }
  245. int has_user_mode(aClient *acptr, char mode) {
  246. long m = find_user_mode(mode);
  247. if(acptr->umodes & m)
  248. return 1; // We gottem
  249. return 0;
  250. }
  251. #endif