unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
server.c (9966B)
1 /* server.* 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", 11 "1.0.0", 12 "server.* RPC calls", 13 "UnrealIRCd Team", 14 "unrealircd-6", 15 }; 16 17 /* Forward declarations */ 18 RPC_CALL_FUNC(rpc_server_list); 19 RPC_CALL_FUNC(rpc_server_get); 20 RPC_CALL_FUNC(rpc_server_rehash); 21 RPC_CALL_FUNC(rpc_server_connect); 22 RPC_CALL_FUNC(rpc_server_disconnect); 23 RPC_CALL_FUNC(rpc_server_module_list); 24 25 int rpc_server_rehash_log(int failure, json_t *rehash_log); 26 27 MOD_INIT() 28 { 29 RPCHandlerInfo r; 30 31 MARK_AS_OFFICIAL_MODULE(modinfo); 32 33 memset(&r, 0, sizeof(r)); 34 r.method = "server.list"; 35 r.loglevel = ULOG_DEBUG; 36 r.call = rpc_server_list; 37 if (!RPCHandlerAdd(modinfo->handle, &r)) 38 { 39 config_error("[rpc/server] Could not register RPC handler"); 40 return MOD_FAILED; 41 } 42 memset(&r, 0, sizeof(r)); 43 r.method = "server.get"; 44 r.loglevel = ULOG_DEBUG; 45 r.call = rpc_server_get; 46 if (!RPCHandlerAdd(modinfo->handle, &r)) 47 { 48 config_error("[rpc/server] Could not register RPC handler"); 49 return MOD_FAILED; 50 } 51 memset(&r, 0, sizeof(r)); 52 r.method = "server.rehash"; 53 r.call = rpc_server_rehash; 54 if (!RPCHandlerAdd(modinfo->handle, &r)) 55 { 56 config_error("[rpc/server] Could not register RPC handler"); 57 return MOD_FAILED; 58 } 59 memset(&r, 0, sizeof(r)); 60 r.method = "server.connect"; 61 r.call = rpc_server_connect; 62 if (!RPCHandlerAdd(modinfo->handle, &r)) 63 { 64 config_error("[rpc/server] Could not register RPC handler"); 65 return MOD_FAILED; 66 } 67 memset(&r, 0, sizeof(r)); 68 r.method = "server.disconnect"; 69 r.call = rpc_server_disconnect; 70 if (!RPCHandlerAdd(modinfo->handle, &r)) 71 { 72 config_error("[rpc/server] Could not register RPC handler"); 73 return MOD_FAILED; 74 } 75 memset(&r, 0, sizeof(r)); 76 r.method = "server.module_list"; 77 r.loglevel = ULOG_DEBUG; 78 r.call = rpc_server_module_list; 79 if (!RPCHandlerAdd(modinfo->handle, &r)) 80 { 81 config_error("[rpc/server] Could not register RPC handler"); 82 return MOD_FAILED; 83 } 84 85 HookAdd(modinfo->handle, HOOKTYPE_REHASH_LOG, 0, rpc_server_rehash_log); 86 87 return MOD_SUCCESS; 88 } 89 90 MOD_LOAD() 91 { 92 return MOD_SUCCESS; 93 } 94 95 MOD_UNLOAD() 96 { 97 return MOD_SUCCESS; 98 } 99 100 RPC_CALL_FUNC(rpc_server_list) 101 { 102 json_t *result, *list, *item; 103 Client *acptr; 104 105 result = json_object(); 106 list = json_array(); 107 json_object_set_new(result, "list", list); 108 109 list_for_each_entry(acptr, &global_server_list, client_node) 110 { 111 if (!IsServer(acptr) && !IsMe(acptr)) 112 continue; 113 114 item = json_object(); 115 json_expand_client(item, NULL, acptr, 99); 116 json_array_append_new(list, item); 117 } 118 119 rpc_response(client, request, result); 120 json_decref(result); 121 } 122 123 RPC_CALL_FUNC(rpc_server_get) 124 { 125 json_t *result, *list, *item; 126 const char *server; 127 Client *acptr; 128 129 OPTIONAL_PARAM_STRING("server", server); 130 if (server) 131 { 132 if (!(acptr = find_server(server, NULL))) 133 { 134 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found"); 135 return; 136 } 137 } else { 138 acptr = &me; 139 } 140 141 result = json_object(); 142 json_expand_client(result, "server", acptr, 99); 143 rpc_response(client, request, result); 144 json_decref(result); 145 } 146 147 RPC_CALL_FUNC(rpc_server_rehash) 148 { 149 json_t *result, *list, *item; 150 const char *server; 151 Client *acptr; 152 153 OPTIONAL_PARAM_STRING("server", server); 154 if (server) 155 { 156 if (!(acptr = find_server(server, NULL))) 157 { 158 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found"); 159 return; 160 } 161 } else { 162 acptr = &me; 163 } 164 165 if (acptr != &me) 166 { 167 /* Forward to remote */ 168 if (rrpc_supported_simple(acptr, NULL)) 169 { 170 /* Server supports RRPC and will handle the response */ 171 rpc_send_request_to_remote(client, acptr, request); 172 } else { 173 /* Server does not support RRPC, so we can only do best effort: */ 174 sendto_one(acptr, NULL, ":%s REHASH %s", me.id, acptr->name); 175 result = json_boolean(1); 176 rpc_response(client, request, result); 177 json_decref(result); 178 } 179 return; 180 } 181 182 if (client->rpc->rehash_request) 183 { 184 rpc_error(client, request, JSON_RPC_ERROR_INVALID_REQUEST, "A rehash initiated by you is already in progress"); 185 return; 186 } 187 188 /* It's for me... */ 189 190 SetMonitorRehash(client); 191 SetAsyncRPC(client); 192 client->rpc->rehash_request = json_copy(request); // or json_deep_copy ?? 193 194 if (!loop.rehashing) 195 { 196 unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD", client, "Rehashing server configuration file [by: $client.details]"); 197 request_rehash(client); 198 } /* else.. we simply joined the rehash request so we are notified as well ;) */ 199 200 /* Do NOT send the JSON Response here, it is done by rpc_server_rehash_log() 201 * after the REHASH completed (which may take several seconds). 202 */ 203 } 204 205 int rpc_server_rehash_log(int failure, json_t *rehash_log) 206 { 207 Client *client, *next; 208 209 list_for_each_entry(client, &unknown_list, lclient_node) 210 { 211 if (IsRPC(client) && IsMonitorRehash(client) && client->rpc && client->rpc->rehash_request) 212 { 213 rpc_response(client, client->rpc->rehash_request, rehash_log); 214 json_decref(client->rpc->rehash_request); 215 client->rpc->rehash_request = NULL; 216 } 217 } 218 list_for_each_entry_safe(client, next, &rpc_remote_list, client_node) 219 { 220 if (IsMonitorRehash(client) && client->rpc && client->rpc->rehash_request) 221 { 222 rpc_response(client, client->rpc->rehash_request, rehash_log); 223 json_decref(client->rpc->rehash_request); 224 client->rpc->rehash_request = NULL; 225 free_client(client); 226 } 227 } 228 return 0; 229 } 230 231 RPC_CALL_FUNC(rpc_server_connect) 232 { 233 json_t *result, *list, *item; 234 const char *server, *link_name; 235 Client *acptr; 236 ConfigItem_link *link; 237 const char *err; 238 239 OPTIONAL_PARAM_STRING("server", server); 240 if (server) 241 { 242 if (!(acptr = find_server(server, NULL))) 243 { 244 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found"); 245 return; 246 } 247 } else { 248 acptr = &me; 249 } 250 REQUIRE_PARAM_STRING("link", link_name); 251 252 if (acptr != &me) 253 { 254 /* Not supported atm */ 255 result = json_boolean(0); 256 rpc_response(client, request, result); 257 json_decref(result); 258 return; 259 } 260 261 if (find_server_quick(link_name)) 262 { 263 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Server is already linked"); 264 return; 265 } 266 267 link = find_link(link_name); 268 if (!link) 269 { 270 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server with that name does not exist in any link block"); 271 return; 272 } 273 if (!link->outgoing.hostname && !link->outgoing.file) 274 { 275 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server with that name exists but is not configured as an OUTGOING server."); 276 return; 277 } 278 279 if ((err = check_deny_link(link, 0))) 280 { 281 rpc_error_fmt(client, request, JSON_RPC_ERROR_DENIED, "Server linking is denied via a deny link { } block: %s", err); 282 return; 283 } 284 285 unreal_log(ULOG_INFO, "link", "LINK_REQUEST", client, 286 "CONNECT: Link to $link_block requested by $client", 287 log_data_link_block(link)); 288 289 connect_server(link, client, NULL); 290 result = json_boolean(1); 291 rpc_response(client, request, result); 292 json_decref(result); 293 } 294 295 RPC_CALL_FUNC(rpc_server_disconnect) 296 { 297 json_t *result, *list, *item; 298 const char *server, *link_name, *reason; 299 Client *acptr, *target; 300 MessageTag *mtags = NULL; 301 302 OPTIONAL_PARAM_STRING("server", server); 303 if (server) 304 { 305 if (!(acptr = find_server(server, NULL))) 306 { 307 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found"); 308 return; 309 } 310 } else { 311 acptr = &me; 312 } 313 REQUIRE_PARAM_STRING("link", link_name); 314 REQUIRE_PARAM_STRING("reason", reason); 315 316 if (acptr != &me) 317 { 318 /* Not supported atm */ 319 result = json_boolean(0); 320 rpc_response(client, request, result); 321 json_decref(result); 322 return; 323 } 324 325 target = find_server_quick(link_name); 326 if (!target) 327 { 328 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server link not found"); 329 return; 330 } 331 332 if (target == &me) 333 { 334 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "We cannot disconnect ourselves"); 335 return; 336 } 337 338 unreal_log(ULOG_INFO, "link", "SQUIT", client, 339 "SQUIT: Forced server disconnect of $target by $client ($reason)", 340 log_data_client("target", target), 341 log_data_string("reason", reason)); 342 343 /* The actual SQUIT: */ 344 new_message(client, NULL, &mtags); 345 exit_client_ex(target, NULL, mtags, reason); 346 free_message_tags(mtags); 347 348 /* Return true */ 349 result = json_boolean(1); 350 rpc_response(client, request, result); 351 json_decref(result); 352 } 353 354 void json_expand_module(json_t *j, const char *key, Module *m, int detail) 355 { 356 char buf[BUFSIZE+1]; 357 json_t *child; 358 359 if (key) 360 { 361 child = json_object(); 362 json_object_set_new(j, key, child); 363 } else { 364 child = j; 365 } 366 367 json_object_set_new(child, "name", json_string_unreal(m->header->name)); 368 json_object_set_new(child, "version", json_string_unreal(m->header->version)); 369 json_object_set_new(child, "author", json_string_unreal(m->header->author)); 370 json_object_set_new(child, "description", json_string_unreal(m->header->description)); 371 json_object_set_new(child, "third_party", json_boolean(m->options & MOD_OPT_OFFICIAL ? 0 : 1)); 372 json_object_set_new(child, "permanent", json_boolean(m->options & MOD_OPT_PERM ? 1 : 0)); 373 json_object_set_new(child, "permanent_but_reloadable", json_boolean(m->options & MOD_OPT_PERM_RELOADABLE ? 1 : 0)); 374 } 375 376 RPC_CALL_FUNC(rpc_server_module_list) 377 { 378 json_t *result, *list, *item; 379 const char *server; 380 Client *acptr; 381 Module *m; 382 383 OPTIONAL_PARAM_STRING("server", server); 384 if (server) 385 { 386 if (!(acptr = find_server(server, NULL))) 387 { 388 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found"); 389 return; 390 } 391 } else { 392 acptr = &me; 393 } 394 395 if (acptr != &me) 396 { 397 /* Forward to remote */ 398 rpc_send_request_to_remote(client, acptr, request); 399 return; 400 } 401 402 /* Return true */ 403 result = json_object(); 404 list = json_array(); 405 json_object_set_new(result, "list", list); 406 407 for (m = Modules; m; m = m->next) 408 { 409 item = json_object(); 410 json_expand_module(item, NULL, m, 1); 411 json_array_append_new(list, item); 412 } 413 414 rpc_response(client, request, result); 415 json_decref(result); 416 }