unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
spamfilter.c (8128B)
1 /* spamfilter.* RPC calls 2 * (C) Copyright 2022-.. Bram Matthys (Syzop) and the UnrealIRCd team 3 * License: GPLv2 or later 4 */ 5 6 #include "unrealircd.h" 7 8 ModuleHeader MOD_HEADER 9 = { 10 "rpc/spamfilter", 11 "1.0.3", 12 "spamfilter.* RPC calls", 13 "UnrealIRCd Team", 14 "unrealircd-6", 15 }; 16 17 /* Forward declarations */ 18 RPC_CALL_FUNC(rpc_spamfilter_list); 19 RPC_CALL_FUNC(rpc_spamfilter_get); 20 RPC_CALL_FUNC(rpc_spamfilter_del); 21 RPC_CALL_FUNC(rpc_spamfilter_add); 22 23 MOD_INIT() 24 { 25 RPCHandlerInfo r; 26 27 MARK_AS_OFFICIAL_MODULE(modinfo); 28 29 memset(&r, 0, sizeof(r)); 30 r.method = "spamfilter.list"; 31 r.loglevel = ULOG_DEBUG; 32 r.call = rpc_spamfilter_list; 33 if (!RPCHandlerAdd(modinfo->handle, &r)) 34 { 35 config_error("[rpc/spamfilter] Could not register RPC handler"); 36 return MOD_FAILED; 37 } 38 r.method = "spamfilter.get"; 39 r.loglevel = ULOG_DEBUG; 40 r.call = rpc_spamfilter_get; 41 if (!RPCHandlerAdd(modinfo->handle, &r)) 42 { 43 config_error("[rpc/spamfilter] Could not register RPC handler"); 44 return MOD_FAILED; 45 } 46 r.method = "spamfilter.del"; 47 r.call = rpc_spamfilter_del; 48 if (!RPCHandlerAdd(modinfo->handle, &r)) 49 { 50 config_error("[rpc/spamfilter] Could not register RPC handler"); 51 return MOD_FAILED; 52 } 53 r.method = "spamfilter.add"; 54 r.call = rpc_spamfilter_add; 55 if (!RPCHandlerAdd(modinfo->handle, &r)) 56 { 57 config_error("[rpc/spamfilter] Could not register RPC handler"); 58 return MOD_FAILED; 59 } 60 61 return MOD_SUCCESS; 62 } 63 64 MOD_LOAD() 65 { 66 return MOD_SUCCESS; 67 } 68 69 MOD_UNLOAD() 70 { 71 return MOD_SUCCESS; 72 } 73 74 RPC_CALL_FUNC(rpc_spamfilter_list) 75 { 76 json_t *result, *list, *item; 77 int index; 78 TKL *tkl; 79 80 result = json_object(); 81 list = json_array(); 82 json_object_set_new(result, "list", list); 83 84 for (index = 0; index < TKLISTLEN; index++) 85 { 86 for (tkl = tklines[index]; tkl; tkl = tkl->next) 87 { 88 if (TKLIsSpamfilter(tkl)) 89 { 90 item = json_object(); 91 json_expand_tkl(item, NULL, tkl, 1); 92 json_array_append_new(list, item); 93 } 94 } 95 } 96 97 rpc_response(client, request, result); 98 json_decref(result); 99 } 100 101 /* Shared code for selecting a spamfilter, for .add/.del/get */ 102 int spamfilter_select_criteria(Client *client, json_t *request, json_t *params, const char **name, int *match_type, 103 int *targets, char *targetbuf, size_t targetbuflen, BanAction *action, char *actionbuf) 104 { 105 const char *str; 106 107 *name = json_object_get_string(params, "name"); 108 if (!*name) 109 { 110 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'name'"); 111 return 0; 112 } 113 114 str = json_object_get_string(params, "match_type"); 115 if (!str) 116 { 117 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'match_type'"); 118 return 0; 119 } 120 *match_type = unreal_match_method_strtoval(str); 121 if (!*match_type) 122 { 123 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid value for parameter 'match_type'"); 124 return 0; 125 } 126 127 str = json_object_get_string(params, "spamfilter_targets"); 128 if (!str) 129 { 130 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'spamfilter_targets'"); 131 return 0; 132 } 133 *targets = spamfilter_gettargets(str, NULL); 134 if (!*targets) 135 { 136 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid value(s) for parameter 'spamfilter_targets'"); 137 return 0; 138 } 139 strlcpy(targetbuf, spamfilter_target_inttostring(*targets), targetbuflen); 140 141 str = json_object_get_string(params, "ban_action"); 142 if (!str) 143 { 144 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'ban_action'"); 145 return 0; 146 } 147 *action = banact_stringtoval(str); 148 if (!*action) 149 { 150 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid value for parameter 'ban_action'"); 151 return 0; 152 } 153 actionbuf[0] = banact_valtochar(*action); 154 actionbuf[1] = '\0'; 155 return 1; 156 } 157 158 RPC_CALL_FUNC(rpc_spamfilter_get) 159 { 160 json_t *result; 161 int type = TKL_SPAMF|TKL_GLOBAL; 162 const char *name; 163 TKL *tkl; 164 BanAction action; 165 int match_type = 0; 166 int targets = 0; 167 char targetbuf[64]; 168 char actionbuf[2]; 169 170 if (!spamfilter_select_criteria(client, request, params, &name, &match_type, &targets, targetbuf, sizeof(targetbuf), &action, actionbuf)) 171 return; /* Error already communicated to client */ 172 173 tkl = find_tkl_spamfilter(type, name, action, targets); 174 if (!tkl) 175 { 176 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Spamfilter not found"); 177 return; 178 } 179 180 result = json_object(); 181 json_expand_tkl(result, "tkl", tkl, 1); 182 rpc_response(client, request, result); 183 json_decref(result); 184 } 185 186 RPC_CALL_FUNC(rpc_spamfilter_add) 187 { 188 json_t *result; 189 int type = TKL_SPAMF|TKL_GLOBAL; 190 const char *str; 191 const char *name, *reason; 192 const char *set_by; 193 time_t ban_duration = 0; 194 TKL *tkl; 195 Match *m; 196 BanAction action; 197 int match_type = 0; 198 int targets = 0; 199 char targetbuf[64]; 200 char actionbuf[2]; 201 char reasonbuf[512]; 202 char *err = NULL; 203 204 if (!spamfilter_select_criteria(client, request, params, &name, &match_type, &targets, targetbuf, sizeof(targetbuf), &action, actionbuf)) 205 return; /* Error already communicated to client */ 206 207 /* Reason */ 208 reason = json_object_get_string(params, "reason"); 209 if (!reason) 210 { 211 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'reason'"); 212 return; 213 } 214 215 /* Ban duration */ 216 if ((str = json_object_get_string(params, "ban_duration"))) 217 { 218 ban_duration = config_checkval(str, CFG_TIME); 219 if (ban_duration < 0) 220 { 221 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid value for parameter 'ban_duration'"); 222 return; 223 } 224 } 225 226 OPTIONAL_PARAM_STRING("set_by", set_by); 227 if (!set_by) 228 set_by = client->name; 229 230 if (find_tkl_spamfilter(type, name, action, targets)) 231 { 232 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "A spamfilter with that regex+action+target already exists"); 233 return; 234 } 235 236 /* Convert reason to use internal storage and wire format */ 237 reason = unreal_encodespace(reason); 238 strlcpy(reasonbuf, reason, sizeof(reasonbuf)); 239 reason = reasonbuf; 240 241 /* now check the regex / match field (only when adding) */ 242 m = unreal_create_match(match_type, name, &err); 243 if (!m) 244 { 245 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid regex or match string specified"); 246 return; 247 } 248 249 tkl = tkl_add_spamfilter(type, targets, action, m, set_by, 0, TStime(), 250 ban_duration, reason, 0); 251 252 if (!tkl) 253 { 254 rpc_error(client, request, JSON_RPC_ERROR_INTERNAL_ERROR, "Unable to add item"); 255 return; 256 } 257 258 tkl_added(client, tkl); 259 260 result = json_object(); 261 json_expand_tkl(result, "tkl", tkl, 1); 262 rpc_response(client, request, result); 263 json_decref(result); 264 } 265 266 RPC_CALL_FUNC(rpc_spamfilter_del) 267 { 268 json_t *result; 269 int type = TKL_SPAMF|TKL_GLOBAL; 270 const char *name; 271 const char *set_by; 272 TKL *tkl; 273 BanAction action; 274 int match_type = 0; 275 int targets = 0; 276 char targetbuf[64]; 277 char actionbuf[2]; 278 const char *tkllayer[13]; 279 280 if (!spamfilter_select_criteria(client, request, params, &name, &match_type, &targets, targetbuf, sizeof(targetbuf), &action, actionbuf)) 281 return; /* Error already communicated to client */ 282 283 OPTIONAL_PARAM_STRING("set_by", set_by); 284 if (!set_by) 285 set_by = client->name; 286 287 tkl = find_tkl_spamfilter(type, name, action, targets); 288 if (!tkl) 289 { 290 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Spamfilter not found"); 291 return; 292 } 293 294 result = json_object(); 295 json_expand_tkl(result, "tkl", tkl, 1); 296 297 /* Wait.. this is a bit dull? */ 298 tkllayer[1] = "-"; 299 tkllayer[2] = "F"; 300 tkllayer[3] = targetbuf; 301 tkllayer[4] = actionbuf; 302 tkllayer[5] = set_by; 303 tkllayer[6] = "-"; 304 tkllayer[7] = "0"; 305 tkllayer[8] = "0"; 306 tkllayer[9] = "-"; 307 tkllayer[10] = unreal_match_method_valtostr(match_type); 308 tkllayer[11] = name; 309 tkllayer[12] = NULL; 310 311 cmd_tkl(&me, NULL, 12, tkllayer); 312 313 tkl = find_tkl_spamfilter(type, name, action, targets); 314 if (!tkl) 315 { 316 rpc_response(client, request, result); 317 } else { 318 /* Spamfilter still exists so failure to remove. 319 * Actually this may not be an internal error, it could be an 320 * incorrect request, such as asking to remove a config-based spamfilter. 321 */ 322 rpc_error(client, request, JSON_RPC_ERROR_INTERNAL_ERROR, "Unable to remove item"); 323 return; 324 } 325 json_decref(result); 326 }