unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
user.c (16988B)
1 /* user.* 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/user", 11 "1.0.7", 12 "user.* RPC calls", 13 "UnrealIRCd Team", 14 "unrealircd-6", 15 }; 16 17 /* Forward declarations */ 18 RPC_CALL_FUNC(rpc_user_list); 19 RPC_CALL_FUNC(rpc_user_get); 20 RPC_CALL_FUNC(rpc_user_set_nick); 21 RPC_CALL_FUNC(rpc_user_set_username); 22 RPC_CALL_FUNC(rpc_user_set_realname); 23 RPC_CALL_FUNC(rpc_user_set_vhost); 24 RPC_CALL_FUNC(rpc_user_set_mode); 25 RPC_CALL_FUNC(rpc_user_set_snomask); 26 RPC_CALL_FUNC(rpc_user_set_oper); 27 RPC_CALL_FUNC(rpc_user_kill); 28 RPC_CALL_FUNC(rpc_user_quit); 29 RPC_CALL_FUNC(rpc_user_join); 30 RPC_CALL_FUNC(rpc_user_part); 31 32 MOD_INIT() 33 { 34 RPCHandlerInfo r; 35 36 MARK_AS_OFFICIAL_MODULE(modinfo); 37 38 memset(&r, 0, sizeof(r)); 39 r.method = "user.list"; 40 r.loglevel = ULOG_DEBUG; 41 r.call = rpc_user_list; 42 if (!RPCHandlerAdd(modinfo->handle, &r)) 43 { 44 config_error("[rpc/user] Could not register RPC handler"); 45 return MOD_FAILED; 46 } 47 memset(&r, 0, sizeof(r)); 48 r.method = "user.get"; 49 r.loglevel = ULOG_DEBUG; 50 r.call = rpc_user_get; 51 if (!RPCHandlerAdd(modinfo->handle, &r)) 52 { 53 config_error("[rpc/user] Could not register RPC handler"); 54 return MOD_FAILED; 55 } 56 memset(&r, 0, sizeof(r)); 57 r.method = "user.set_nick"; 58 r.call = rpc_user_set_nick; 59 if (!RPCHandlerAdd(modinfo->handle, &r)) 60 { 61 config_error("[rpc/user] Could not register RPC handler"); 62 return MOD_FAILED; 63 } 64 memset(&r, 0, sizeof(r)); 65 r.method = "user.set_username"; 66 r.call = rpc_user_set_username; 67 if (!RPCHandlerAdd(modinfo->handle, &r)) 68 { 69 config_error("[rpc/user] Could not register RPC handler"); 70 return MOD_FAILED; 71 } 72 memset(&r, 0, sizeof(r)); 73 r.method = "user.set_realname"; 74 r.call = rpc_user_set_realname; 75 if (!RPCHandlerAdd(modinfo->handle, &r)) 76 { 77 config_error("[rpc/user] Could not register RPC handler"); 78 return MOD_FAILED; 79 } 80 memset(&r, 0, sizeof(r)); 81 r.method = "user.set_vhost"; 82 r.call = rpc_user_set_vhost; 83 if (!RPCHandlerAdd(modinfo->handle, &r)) 84 { 85 config_error("[rpc/user] Could not register RPC handler"); 86 return MOD_FAILED; 87 } 88 memset(&r, 0, sizeof(r)); 89 r.method = "user.set_mode"; 90 r.call = rpc_user_set_mode; 91 if (!RPCHandlerAdd(modinfo->handle, &r)) 92 { 93 config_error("[rpc/user] Could not register RPC handler"); 94 return MOD_FAILED; 95 } 96 memset(&r, 0, sizeof(r)); 97 r.method = "user.set_snomask"; 98 r.call = rpc_user_set_snomask; 99 if (!RPCHandlerAdd(modinfo->handle, &r)) 100 { 101 config_error("[rpc/user] Could not register RPC handler"); 102 return MOD_FAILED; 103 } 104 memset(&r, 0, sizeof(r)); 105 r.method = "user.set_oper"; 106 r.call = rpc_user_set_oper; 107 if (!RPCHandlerAdd(modinfo->handle, &r)) 108 { 109 config_error("[rpc/user] Could not register RPC handler"); 110 return MOD_FAILED; 111 } 112 memset(&r, 0, sizeof(r)); 113 r.method = "user.kill"; 114 r.call = rpc_user_kill; 115 if (!RPCHandlerAdd(modinfo->handle, &r)) 116 { 117 config_error("[rpc/user] Could not register RPC handler"); 118 return MOD_FAILED; 119 } 120 memset(&r, 0, sizeof(r)); 121 r.method = "user.quit"; 122 r.call = rpc_user_quit; 123 if (!RPCHandlerAdd(modinfo->handle, &r)) 124 { 125 config_error("[rpc/user] Could not register RPC handler"); 126 return MOD_FAILED; 127 } 128 memset(&r, 0, sizeof(r)); 129 r.method = "user.join"; 130 r.call = rpc_user_join; 131 if (!RPCHandlerAdd(modinfo->handle, &r)) 132 { 133 config_error("[rpc/user] Could not register RPC handler"); 134 return MOD_FAILED; 135 } 136 memset(&r, 0, sizeof(r)); 137 r.method = "user.part"; 138 r.call = rpc_user_part; 139 if (!RPCHandlerAdd(modinfo->handle, &r)) 140 { 141 config_error("[rpc/user] Could not register RPC handler"); 142 return MOD_FAILED; 143 } 144 145 return MOD_SUCCESS; 146 } 147 148 MOD_LOAD() 149 { 150 return MOD_SUCCESS; 151 } 152 153 MOD_UNLOAD() 154 { 155 return MOD_SUCCESS; 156 } 157 158 RPC_CALL_FUNC(rpc_user_list) 159 { 160 json_t *result, *list, *item; 161 Client *acptr; 162 int details; 163 164 OPTIONAL_PARAM_INTEGER("object_detail_level", details, 2); 165 if (details == 3) 166 { 167 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4."); 168 return; 169 } 170 171 result = json_object(); 172 list = json_array(); 173 json_object_set_new(result, "list", list); 174 175 list_for_each_entry(acptr, &client_list, client_node) 176 { 177 if (!IsUser(acptr)) 178 continue; 179 180 item = json_object(); 181 json_expand_client(item, NULL, acptr, details); 182 json_array_append_new(list, item); 183 } 184 185 rpc_response(client, request, result); 186 json_decref(result); 187 } 188 189 RPC_CALL_FUNC(rpc_user_get) 190 { 191 json_t *result, *list, *item; 192 const char *nick; 193 Client *acptr; 194 int details; 195 196 REQUIRE_PARAM_STRING("nick", nick); 197 198 OPTIONAL_PARAM_INTEGER("object_detail_level", details, 4); 199 if (details == 3) 200 { 201 rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4."); 202 return; 203 } 204 205 if (!(acptr = find_user(nick, NULL))) 206 { 207 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 208 return; 209 } 210 211 result = json_object(); 212 json_expand_client(result, "client", acptr, details); 213 rpc_response(client, request, result); 214 json_decref(result); 215 } 216 217 RPC_CALL_FUNC(rpc_user_set_nick) 218 { 219 json_t *result, *list, *item; 220 MessageTag *mtags = NULL; 221 const char *args[5]; 222 const char *nick, *newnick_requested, *str; 223 int force = 0; 224 char newnick[NICKLEN+1]; 225 char tsbuf[32]; 226 Client *acptr; 227 228 REQUIRE_PARAM_STRING("nick", nick); 229 REQUIRE_PARAM_STRING("newnick", newnick_requested); 230 strlcpy(newnick, newnick_requested, iConf.nick_length + 1); 231 OPTIONAL_PARAM_BOOLEAN("force", force, 0); 232 233 if (!(acptr = find_user(nick, NULL))) 234 { 235 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 236 return; 237 } 238 239 if (!do_nick_name(newnick) || strcmp(newnick, newnick_requested) || 240 !strcasecmp(newnick, "IRC") || !strcasecmp(newnick, "IRCd")) 241 { 242 rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New nickname contains forbidden character(s) or is too long"); 243 return; 244 } 245 246 if (!strcmp(nick, newnick)) 247 { 248 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old nickname and new nickname are identical"); 249 return; 250 } 251 252 if (!force) 253 { 254 /* Check other restrictions */ 255 Client *check = find_user(newnick, NULL); 256 int ishold = 0; 257 258 /* Check if in use by someone else (do allow case-changing) */ 259 if (check && (acptr != check)) 260 { 261 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "New nickname is already taken by another user"); 262 return; 263 } 264 265 // Can't really check for spamfilter here, since it assumes user is local 266 267 // But we can check q-lines... 268 if (find_qline(acptr, newnick, &ishold)) 269 { 270 rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New nickname is forbidden by q-line"); 271 return; 272 } 273 } 274 275 args[0] = NULL; 276 args[1] = acptr->name; 277 args[2] = newnick; 278 snprintf(tsbuf, sizeof(tsbuf), "%lld", (long long)TStime()); 279 args[3] = tsbuf; 280 args[4] = NULL; 281 mtag_add_issued_by(&mtags, client, NULL); 282 do_cmd(&me, mtags, "SVSNICK", 4, args); 283 safe_free_message_tags(mtags); 284 285 /* Simply return success */ 286 result = json_boolean(1); 287 rpc_response(client, request, result); 288 json_decref(result); 289 } 290 291 RPC_CALL_FUNC(rpc_user_set_username) 292 { 293 json_t *result, *list, *item; 294 const char *args[4]; 295 const char *nick, *username, *str; 296 MessageTag *mtags = NULL; 297 Client *acptr; 298 299 REQUIRE_PARAM_STRING("nick", nick); 300 REQUIRE_PARAM_STRING("username", username); 301 302 if (!(acptr = find_user(nick, NULL))) 303 { 304 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 305 return; 306 } 307 308 if (!valid_username(username)) 309 { 310 rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New username contains forbidden character(s) or is too long"); 311 return; 312 } 313 314 if (!strcmp(acptr->user->username, username)) 315 { 316 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new user name are identical"); 317 return; 318 } 319 320 args[0] = NULL; 321 args[1] = acptr->name; 322 args[2] = username; 323 args[3] = NULL; 324 mtag_add_issued_by(&mtags, client, NULL); 325 do_cmd(&me, mtags, "CHGIDENT", 3, args); 326 safe_free_message_tags(mtags); 327 328 /* Return result */ 329 if (!strcmp(acptr->user->username, username)) 330 result = json_boolean(1); 331 else 332 result = json_boolean(0); 333 rpc_response(client, request, result); 334 json_decref(result); 335 } 336 337 RPC_CALL_FUNC(rpc_user_set_realname) 338 { 339 json_t *result, *list, *item; 340 const char *args[4]; 341 const char *nick, *realname, *str; 342 MessageTag *mtags = NULL; 343 Client *acptr; 344 345 REQUIRE_PARAM_STRING("nick", nick); 346 REQUIRE_PARAM_STRING("realname", realname); 347 348 if (!(acptr = find_user(nick, NULL))) 349 { 350 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 351 return; 352 } 353 354 if (strlen(realname) > REALLEN) 355 { 356 rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New real name is too long"); 357 return; 358 } 359 360 if (!strcmp(acptr->info, realname)) 361 { 362 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new real name are identical"); 363 return; 364 } 365 366 args[0] = NULL; 367 args[1] = acptr->name; 368 args[2] = realname; 369 args[3] = NULL; 370 mtag_add_issued_by(&mtags, client, NULL); 371 do_cmd(&me, mtags, "CHGNAME", 3, args); 372 safe_free_message_tags(mtags); 373 374 /* Return result */ 375 if (!strcmp(acptr->info, realname)) 376 result = json_boolean(1); 377 else 378 result = json_boolean(0); 379 rpc_response(client, request, result); 380 json_decref(result); 381 } 382 383 RPC_CALL_FUNC(rpc_user_set_vhost) 384 { 385 json_t *result, *list, *item; 386 const char *args[4]; 387 const char *nick, *vhost, *str; 388 MessageTag *mtags = NULL; 389 Client *acptr; 390 391 REQUIRE_PARAM_STRING("nick", nick); 392 REQUIRE_PARAM_STRING("vhost", vhost); 393 394 if (!(acptr = find_user(nick, NULL))) 395 { 396 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 397 return; 398 } 399 400 if ((strlen(vhost) > HOSTLEN) || !valid_host(vhost, 0)) 401 { 402 rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New vhost contains forbidden character(s) or is too long"); 403 return; 404 } 405 406 if (!strcmp(GetHost(acptr), vhost)) 407 { 408 rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new vhost are identical"); 409 return; 410 } 411 412 args[0] = NULL; 413 args[1] = acptr->name; 414 args[2] = vhost; 415 args[3] = NULL; 416 mtag_add_issued_by(&mtags, client, NULL); 417 do_cmd(&me, mtags, "CHGHOST", 3, args); 418 safe_free_message_tags(mtags); 419 420 /* Return result */ 421 if (!strcmp(GetHost(acptr), vhost)) 422 result = json_boolean(1); 423 else 424 result = json_boolean(0); 425 rpc_response(client, request, result); 426 json_decref(result); 427 } 428 429 RPC_CALL_FUNC(rpc_user_set_mode) 430 { 431 json_t *result, *list, *item; 432 const char *args[4]; 433 const char *nick, *modes, *str; 434 int hidden; 435 MessageTag *mtags = NULL; 436 Client *acptr; 437 438 REQUIRE_PARAM_STRING("nick", nick); 439 REQUIRE_PARAM_STRING("modes", modes); 440 OPTIONAL_PARAM_BOOLEAN("hidden", hidden, 0); 441 442 if (!(acptr = find_user(nick, NULL))) 443 { 444 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 445 return; 446 } 447 448 args[0] = NULL; 449 args[1] = acptr->name; 450 args[2] = modes; 451 args[3] = NULL; 452 mtag_add_issued_by(&mtags, client, NULL); 453 do_cmd(&me, mtags, hidden ? "SVSMODE" : "SVS2MODE", 3, args); 454 safe_free_message_tags(mtags); 455 456 /* Return result (always true) */ 457 result = json_boolean(1); 458 rpc_response(client, request, result); 459 json_decref(result); 460 } 461 462 RPC_CALL_FUNC(rpc_user_set_snomask) 463 { 464 json_t *result, *list, *item; 465 const char *args[4]; 466 const char *nick, *snomask, *str; 467 int hidden; 468 MessageTag *mtags = NULL; 469 Client *acptr; 470 471 REQUIRE_PARAM_STRING("nick", nick); 472 REQUIRE_PARAM_STRING("snomask", snomask); 473 OPTIONAL_PARAM_BOOLEAN("hidden", hidden, 0); 474 475 if (!(acptr = find_user(nick, NULL))) 476 { 477 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 478 return; 479 } 480 481 args[0] = NULL; 482 args[1] = acptr->name; 483 args[2] = snomask; 484 args[3] = NULL; 485 mtag_add_issued_by(&mtags, client, NULL); 486 do_cmd(&me, mtags, hidden ? "SVSSNO" : "SVS2SNO", 3, args); 487 safe_free_message_tags(mtags); 488 489 /* Return result (always true) */ 490 result = json_boolean(1); 491 rpc_response(client, request, result); 492 json_decref(result); 493 } 494 495 RPC_CALL_FUNC(rpc_user_set_oper) 496 { 497 json_t *result, *list, *item; 498 const char *args[9]; 499 const char *nick, *oper_account, *oper_class; 500 const char *class=NULL, *modes=NULL, *snomask=NULL, *vhost=NULL; 501 MessageTag *mtags = NULL; 502 Client *acptr; 503 char default_modes[64]; 504 505 REQUIRE_PARAM_STRING("nick", nick); 506 REQUIRE_PARAM_STRING("oper_account", oper_account); 507 REQUIRE_PARAM_STRING("oper_class", oper_class); 508 OPTIONAL_PARAM_STRING("class", class); 509 OPTIONAL_PARAM_STRING("modes", modes); 510 OPTIONAL_PARAM_STRING("snomask", snomask); 511 OPTIONAL_PARAM_STRING("vhost", vhost); 512 513 if (!(acptr = find_user(nick, NULL))) 514 { 515 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 516 return; 517 } 518 519 if (modes == NULL) 520 { 521 strlcpy(default_modes, get_usermode_string_raw(OPER_MODES), sizeof(default_modes)); 522 modes = default_modes; 523 } 524 525 args[0] = NULL; 526 args[1] = acptr->name; 527 args[2] = oper_account; 528 args[3] = oper_class; 529 args[4] = class ? class : "opers"; 530 args[5] = modes; 531 args[6] = snomask ? snomask : iConf.oper_snomask; 532 args[7] = vhost ? vhost : "-"; 533 args[8] = NULL; 534 mtag_add_issued_by(&mtags, client, NULL); 535 do_cmd(&me, mtags, "SVSO", 8, args); 536 safe_free_message_tags(mtags); 537 538 /* Return result (always true) */ 539 result = json_boolean(1); 540 rpc_response(client, request, result); 541 json_decref(result); 542 } 543 544 RPC_CALL_FUNC(rpc_user_kill) 545 { 546 json_t *result, *list, *item; 547 const char *args[4]; 548 const char *nick, *reason; 549 MessageTag *mtags = NULL; 550 Client *acptr; 551 552 REQUIRE_PARAM_STRING("nick", nick); 553 REQUIRE_PARAM_STRING("reason", reason); 554 555 if (!(acptr = find_user(nick, NULL))) 556 { 557 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 558 return; 559 } 560 561 args[0] = NULL; 562 args[1] = acptr->name; 563 args[2] = reason; 564 args[3] = NULL; 565 mtag_add_issued_by(&mtags, client, NULL); 566 do_cmd(&me, mtags, "KILL", 3, args); 567 safe_free_message_tags(mtags); 568 569 /* Return result */ 570 if ((acptr = find_user(nick, NULL)) && !IsDead(acptr)) 571 result = json_boolean(0); 572 else 573 result = json_boolean(1); 574 rpc_response(client, request, result); 575 json_decref(result); 576 } 577 578 RPC_CALL_FUNC(rpc_user_quit) 579 { 580 json_t *result, *list, *item; 581 const char *args[4]; 582 const char *nick, *reason; 583 MessageTag *mtags = NULL; 584 Client *acptr; 585 586 REQUIRE_PARAM_STRING("nick", nick); 587 REQUIRE_PARAM_STRING("reason", reason); 588 589 if (!(acptr = find_user(nick, NULL))) 590 { 591 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 592 return; 593 } 594 595 args[0] = NULL; 596 args[1] = acptr->name; 597 args[2] = reason; 598 args[3] = NULL; 599 mtag_add_issued_by(&mtags, client, NULL); 600 do_cmd(&me, mtags, "SVSKILL", 3, args); 601 safe_free_message_tags(mtags); 602 603 /* Return result */ 604 if ((acptr = find_user(nick, NULL)) && !IsDead(acptr)) 605 result = json_boolean(0); 606 else 607 result = json_boolean(1); 608 rpc_response(client, request, result); 609 json_decref(result); 610 } 611 612 RPC_CALL_FUNC(rpc_user_join) 613 { 614 json_t *result, *list, *item; 615 const char *args[5]; 616 const char *nick, *channel, *key=NULL; 617 Client *acptr; 618 MessageTag *mtags = NULL; 619 int force = 0; 620 621 REQUIRE_PARAM_STRING("nick", nick); 622 REQUIRE_PARAM_STRING("channel", channel); 623 OPTIONAL_PARAM_STRING("key", key); 624 OPTIONAL_PARAM_BOOLEAN("force", force, 0); 625 626 if (!(acptr = find_user(nick, NULL))) 627 { 628 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 629 return; 630 } 631 632 mtag_add_issued_by(&mtags, client, NULL); 633 634 args[0] = NULL; 635 args[1] = acptr->name; 636 args[2] = channel; 637 638 if (force == 0) 639 { 640 args[3] = key; 641 args[4] = NULL; 642 do_cmd(&me, mtags, "SVSJOIN", key ? 4 : 3, args); 643 } else { 644 args[3] = NULL; 645 do_cmd(&me, mtags, "SAJOIN", 3, args); 646 } 647 648 safe_free_message_tags(mtags); 649 650 /* Return result -- yeah this is always true, not so good.. :D 651 * It is that way because we (this server) may not actually 652 * do the SVSJOIN at all, we may be just relaying it to some 653 * other server. 654 */ 655 result = json_boolean(1); 656 rpc_response(client, request, result); 657 json_decref(result); 658 } 659 660 RPC_CALL_FUNC(rpc_user_part) 661 { 662 json_t *result, *list, *item; 663 const char *args[5]; 664 const char *nick, *channel, *reason=NULL; 665 Client *acptr; 666 MessageTag *mtags = NULL; 667 int force = 0; 668 669 REQUIRE_PARAM_STRING("nick", nick); 670 REQUIRE_PARAM_STRING("channel", channel); 671 OPTIONAL_PARAM_STRING("reason", reason); 672 OPTIONAL_PARAM_BOOLEAN("force", force, 0); 673 674 if (!(acptr = find_user(nick, NULL))) 675 { 676 rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found"); 677 return; 678 } 679 680 args[0] = NULL; 681 args[1] = acptr->name; 682 args[2] = channel; 683 args[3] = reason; 684 args[4] = NULL; 685 mtag_add_issued_by(&mtags, client, NULL); 686 do_cmd(&me, NULL, force ? "SAPART" : "SVSPART", reason ? 4 : 3, args); 687 safe_free_message_tags(mtags); 688 689 /* Return result. Always 'true' at the moment. 690 * Technically we could check if the user is in all of these channels. 691 * But then again, do we really want to return failure if one specified 692 * channel does not exist out of X channels to be parted? Not worth it. 693 */ 694 result = json_boolean(1); 695 rpc_response(client, request, result); 696 json_decref(result); 697 }