unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

server_ban.c (8422B)

      1 /* server_ban.* 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/server_ban",
     11 	"1.0.3",
     12 	"server_ban.* RPC calls",
     13 	"UnrealIRCd Team",
     14 	"unrealircd-6",
     15 };
     16 
     17 /* Forward declarations */
     18 RPC_CALL_FUNC(rpc_server_ban_list);
     19 RPC_CALL_FUNC(rpc_server_ban_get);
     20 RPC_CALL_FUNC(rpc_server_ban_del);
     21 RPC_CALL_FUNC(rpc_server_ban_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 = "server_ban.list";
     31 	r.loglevel = ULOG_DEBUG;
     32 	r.call = rpc_server_ban_list;
     33 	if (!RPCHandlerAdd(modinfo->handle, &r))
     34 	{
     35 		config_error("[rpc/server_ban] Could not register RPC handler");
     36 		return MOD_FAILED;
     37 	}
     38 	r.method = "server_ban.get";
     39 	r.loglevel = ULOG_DEBUG;
     40 	r.call = rpc_server_ban_get;
     41 	if (!RPCHandlerAdd(modinfo->handle, &r))
     42 	{
     43 		config_error("[rpc/server_ban] Could not register RPC handler");
     44 		return MOD_FAILED;
     45 	}
     46 	r.method = "server_ban.del";
     47 	r.call = rpc_server_ban_del;
     48 	if (!RPCHandlerAdd(modinfo->handle, &r))
     49 	{
     50 		config_error("[rpc/server_ban] Could not register RPC handler");
     51 		return MOD_FAILED;
     52 	}
     53 	r.method = "server_ban.add";
     54 	r.call = rpc_server_ban_add;
     55 	if (!RPCHandlerAdd(modinfo->handle, &r))
     56 	{
     57 		config_error("[rpc/server_ban] 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_server_ban_list)
     75 {
     76 	json_t *result, *list, *item;
     77 	int index, index2;
     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 < TKLIPHASHLEN1; index++)
     85 	{
     86 		for (index2 = 0; index2 < TKLIPHASHLEN2; index2++)
     87 		{
     88 			for (tkl = tklines_ip_hash[index][index2]; tkl; tkl = tkl->next)
     89 			{
     90 				if (TKLIsServerBan(tkl))
     91 				{
     92 					item = json_object();
     93 					json_expand_tkl(item, NULL, tkl, 1);
     94 					json_array_append_new(list, item);
     95 				}
     96 			}
     97 		}
     98 	}
     99 	for (index = 0; index < TKLISTLEN; index++)
    100 	{
    101 		for (tkl = tklines[index]; tkl; tkl = tkl->next)
    102 		{
    103 			if (TKLIsServerBan(tkl))
    104 			{
    105 				item = json_object();
    106 				json_expand_tkl(item, NULL, tkl, 1);
    107 				json_array_append_new(list, item);
    108 			}
    109 		}
    110 	}
    111 
    112 	rpc_response(client, request, result);
    113 	json_decref(result);
    114 }
    115 
    116 /** Shared code for selecting a server ban, for .add/.del/.get */
    117 int server_ban_select_criteria(Client *client, json_t *request, json_t *params,
    118                                const char **name,
    119                                const char **type_name,
    120                                char *tkl_type_char,
    121                                int *tkl_type_int,
    122                                char **usermask,
    123                                char **hostmask,
    124                                int *soft)
    125 {
    126 	const char *error;
    127 
    128 	*name = json_object_get_string(params, "name");
    129 	if (!*name)
    130 	{
    131 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'name'");
    132 		return 0;
    133 	}
    134 
    135 	*type_name = json_object_get_string(params, "type");
    136 	if (!*type_name)
    137 	{
    138 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Missing parameter: 'type'");
    139 		return 0;
    140 	}
    141 
    142 	*tkl_type_char = tkl_configtypetochar(*type_name);
    143 	if (!*tkl_type_char)
    144 	{
    145 		rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid type: '%s'", *type_name);
    146 		return 0;
    147 	}
    148 	*tkl_type_int = tkl_chartotype(*tkl_type_char);
    149 	if (!TKLIsServerBanType(*tkl_type_int))
    150 	{
    151 		rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Invalid type: '%s' (type exists but is not valid for in server_ban.*)", *type_name);
    152 		return 0;
    153 	}
    154 
    155 	if (!server_ban_parse_mask(client, 0, *tkl_type_char, *name, usermask, hostmask, soft, &error))
    156 	{
    157 		rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Error: %s", error);
    158 		return 0;
    159 	}
    160 
    161 	/* Hm, shouldn't this be done by server_ban_parse_mask() ? */
    162 	if (*soft && (*usermask[0] == '%'))
    163 		*usermask = *usermask + 1;
    164 
    165 	return 1;
    166 }
    167 
    168 RPC_CALL_FUNC(rpc_server_ban_get)
    169 {
    170 	json_t *result, *list, *item;
    171 	const char *name, *type_name;
    172 	char *usermask, *hostmask;
    173 	int soft;
    174 	TKL *tkl;
    175 	char tkl_type_char;
    176 	int tkl_type_int;
    177 
    178 	if (!server_ban_select_criteria(client, request, params,
    179 	                                &name, &type_name,
    180 	                                &tkl_type_char, &tkl_type_int,
    181 	                                &usermask, &hostmask, &soft))
    182 	{
    183 		return;
    184 	}
    185 
    186 	if (!(tkl = find_tkl_serverban(tkl_type_int, usermask, hostmask, soft)))
    187 	{
    188 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Ban not found");
    189 		return;
    190 	}
    191 
    192 	result = json_object();
    193 	json_expand_tkl(result, "tkl", tkl, 1);
    194 	rpc_response(client, request, result);
    195 	json_decref(result);
    196 }
    197 
    198 RPC_CALL_FUNC(rpc_server_ban_del)
    199 {
    200 	json_t *result, *list, *item;
    201 	const char *name, *type_name;
    202 	const char *set_by;
    203 	char *usermask, *hostmask;
    204 	char usermask_mess[256];
    205 	int soft;
    206 	TKL *tkl;
    207 	char tkl_type_char;
    208 	int tkl_type_int;
    209 	const char *tkllayer[10];
    210 	char tkl_type_str[2];
    211 
    212 	if (!server_ban_select_criteria(client, request, params,
    213 	                                &name, &type_name,
    214 	                                &tkl_type_char, &tkl_type_int,
    215 	                                &usermask, &hostmask, &soft))
    216 	{
    217 		return;
    218 	}
    219 
    220 	tkl_type_str[0] = tkl_type_char;
    221 	tkl_type_str[1] = '\0';
    222 
    223 	if (!(tkl = find_tkl_serverban(tkl_type_int, usermask, hostmask, soft)))
    224 	{
    225 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Ban not found");
    226 		return;
    227 	}
    228 
    229 	OPTIONAL_PARAM_STRING("set_by", set_by);
    230 	if (!set_by)
    231 		set_by = client->name;
    232 
    233 	result = json_object();
    234 	json_expand_tkl(result, "tkl", tkl, 1);
    235 
    236 	tkllayer[1] = "-";
    237 	tkllayer[2] = tkl_type_str;
    238 	if (soft)
    239 	{
    240 		/* I don't like this fiddling.
    241 		 * It will be gone when we move from cmd_tkl() to a real function though.
    242 		 */
    243 		snprintf(usermask_mess, sizeof(usermask_mess), "%%%s", usermask);
    244 		tkllayer[3] = usermask_mess;
    245 	} else {
    246 		tkllayer[3] = usermask;
    247 	}
    248 	tkllayer[4] = hostmask;
    249 	tkllayer[5] = set_by;
    250 	tkllayer[6] = NULL;
    251 	cmd_tkl(&me, NULL, 6, tkllayer);
    252 
    253 	if (!find_tkl_serverban(tkl_type_int, usermask, hostmask, soft))
    254 	{
    255 		rpc_response(client, request, result);
    256 	} else {
    257 		/* Actually this may not be an internal error, it could be an
    258 		 * incorrect request, such as asking to remove a config-based ban.
    259 		 */
    260 		rpc_error(client, request, JSON_RPC_ERROR_INTERNAL_ERROR, "Unable to remove item");
    261 	}
    262 	json_decref(result);
    263 }
    264 
    265 RPC_CALL_FUNC(rpc_server_ban_add)
    266 {
    267 	json_t *result, *list, *item;
    268 	const char *name, *type_name;
    269 	const char *set_by;
    270 	char *usermask, *hostmask;
    271 	int soft;
    272 	TKL *tkl;
    273 	char tkl_type_char;
    274 	int tkl_type_int;
    275 	char tkl_type_str[2];
    276 	const char *reason;
    277 	const char *str;
    278 	time_t tkl_expire_at;
    279 	time_t tkl_set_at = TStime();
    280 
    281 	if (!server_ban_select_criteria(client, request, params,
    282 	                                &name, &type_name,
    283 	                                &tkl_type_char, &tkl_type_int,
    284 	                                &usermask, &hostmask, &soft))
    285 	{
    286 		return;
    287 	}
    288 
    289 	tkl_type_str[0] = tkl_type_char;
    290 	tkl_type_str[1] = '\0';
    291 
    292 	REQUIRE_PARAM_STRING("reason", reason);
    293 
    294 	/* Duration / expiry time */
    295 	if ((str = json_object_get_string(params, "duration_string")))
    296 	{
    297 		tkl_expire_at = config_checkval(str, CFG_TIME);
    298 		if (tkl_expire_at > 0)
    299 			tkl_expire_at = TStime() + tkl_expire_at;
    300 	} else
    301 	if ((str = json_object_get_string(params, "expire_at")))
    302 	{
    303 		tkl_expire_at = server_time_to_unix_time(str);
    304 	} else
    305 	{
    306 		/* Never expire */
    307 		tkl_expire_at = 0;
    308 	}
    309 
    310 	OPTIONAL_PARAM_STRING("set_by", set_by);
    311 	if (!set_by)
    312 		set_by = client->name;
    313 
    314 	if ((tkl_expire_at != 0) && (tkl_expire_at < TStime()))
    315 	{
    316 		rpc_error_fmt(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Error: the specified expiry time is before current time (before now)");
    317 		return;
    318 	}
    319 
    320 	if (find_tkl_serverban(tkl_type_int, usermask, hostmask, soft))
    321 	{
    322 		rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "A ban with that mask already exists");
    323 		return;
    324 	}
    325 
    326 	tkl = tkl_add_serverban(tkl_type_int, usermask, hostmask, reason,
    327 	                        set_by, tkl_expire_at, tkl_set_at,
    328 	                        soft, 0);
    329 
    330 	if (!tkl)
    331 	{
    332 		rpc_error(client, request, JSON_RPC_ERROR_INTERNAL_ERROR, "Unable to add item");
    333 		return;
    334 	}
    335 
    336 	tkl_added(client, tkl);
    337 
    338 	result = json_object();
    339 	json_expand_tkl(result, "tkl", tkl, 1);
    340 	rpc_response(client, request, result);
    341 	json_decref(result);
    342 }